BVB Source Codes

CRYENGINE Show OffMeshNavigationManager.cpp Source code

Return Download CRYENGINE: download OffMeshNavigationManager.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include "OffMeshNavigationManager.h"
  5.  
  6. #include "SmartObjects.h"
  7. #include "NavigationSystem.h"
  8.  
  9. OffMeshNavigationManager::OffMeshNavigationManager(const int offMeshMapSize)
  10.         : m_offMeshMap(offMeshMapSize)
  11.         , m_objectRegistrationEnabled(false)
  12.         , m_operations(128)
  13.         , m_listeners(32)
  14. {
  15. }
  16.  
  17. const MNM::OffMeshNavigation& OffMeshNavigationManager::GetOffMeshNavigationForMesh(const NavigationMeshID& meshID) const
  18. {
  19.         if (meshID && m_offMeshMap.validate(meshID))
  20.         {
  21.                 return m_offMeshMap[meshID];
  22.         }
  23.         else
  24.         {
  25.                 assert(0);
  26.                 AIWarning("No off-mesh navigation available, returning empty one! Navigation might not be able to use external links when path-finding");
  27.                 return m_emptyOffMeshNavigation;
  28.         }
  29. }
  30.  
  31. MNM::OffMeshNavigation& OffMeshNavigationManager::GetOffMeshNavigationForMesh(const NavigationMeshID& meshID)
  32. {
  33.         if (meshID && m_offMeshMap.validate(meshID))
  34.         {
  35.                 return m_offMeshMap[meshID];
  36.         }
  37.         else
  38.         {
  39.                 assert(0);
  40.                 AIWarning("No off-mesh navigation available, returning empty one! Navigation might not be able to use external links when path-finding");
  41.                 return m_emptyOffMeshNavigation;
  42.         }
  43. }
  44.  
  45. void OffMeshNavigationManager::QueueCustomLinkAddition(const MNM::LinkAdditionRequest& request)
  46. {
  47. #if DEBUG_MNM_LOG_OFFMESH_LINK_OPERATIONS
  48.         AILogCommentID("<MNM:OffMeshLink>", "OffMeshNavigationManager::QueueCustomLinkAddition for entity %x", request.requestOwner);
  49. #endif
  50.         m_operations.push_back(request);
  51. }
  52.  
  53. void OffMeshNavigationManager::QueueCustomLinkRemoval(const MNM::LinkRemovalRequest& request)
  54. {
  55. #if DEBUG_MNM_LOG_OFFMESH_LINK_OPERATIONS
  56.         AILogCommentID("<MNM:OffMeshLink>", "OffMeshNavigationManager::QueueCustomLinkRemoval linkId %u for entity %x", request.linkId, request.requestOwner);
  57. #endif
  58.         m_operations.push_back(request);
  59. }
  60.  
  61. bool OffMeshNavigationManager::IsLinkRemovalRequested(const MNM::OffMeshLinkID& linkID) const
  62. {
  63.         for (const MNM::OffMeshOperationRequestBase& requestBase : m_operations)
  64.         {
  65.                 if ((requestBase.operationType == MNM::eOffMeshOperationType_Remove) && (requestBase.linkId == linkID))
  66.                 {
  67.                         return true;
  68.                 }
  69.         }
  70.  
  71.         return false;
  72. }
  73.  
  74. bool OffMeshNavigationManager::AddCustomLink(const NavigationMeshID& meshID, MNM::OffMeshLinkPtr& pLinkData, MNM::OffMeshLinkID& linkID, const bool bCloneLinkData)
  75. {
  76.         // Grab the navigation mesh
  77.         NavigationMesh& mesh = gAIEnv.pNavigationSystem->GetMesh(meshID);
  78.  
  79.         CRY_ASSERT(pLinkData.get() != nullptr);
  80.  
  81.         MNM::OffMeshLink& linkData = *pLinkData;
  82.  
  83.         // Query the entry/exit positions
  84.         const Vec3 startPoint = linkData.GetStartPosition();
  85.         const Vec3 endPoint = linkData.GetEndPosition();
  86.  
  87.         MNM::vector3_t fixedStartPoint(startPoint);
  88.         MNM::vector3_t fixedEndPoint(endPoint);
  89.  
  90.         MNM::TriangleID startTriangleID, endTriangleID;
  91.  
  92.         const MNM::real_t range = MNM::real_t(1.0f);
  93.  
  94.         // Get entry triangle
  95.         startTriangleID = mesh.navMesh.GetTriangleAt(fixedStartPoint, range, range);
  96.  
  97.         if (!startTriangleID)
  98.         {
  99.                 //Bail out; Entry position not connected to a triangle
  100.                 return false;
  101.         }
  102.  
  103.         // Get entry triangle
  104.         endTriangleID = mesh.navMesh.GetTriangleAt(fixedEndPoint, range, range);
  105.  
  106.         if (!endTriangleID)
  107.         {
  108.                 //Bail out; Exit position not connected to a triangle
  109.                 return false;
  110.         }
  111.  
  112.         if (startTriangleID == endTriangleID)
  113.         {
  114.                 // points are on the same triangle so don't bother
  115.                 return false;
  116.         }
  117.  
  118.         // Select the corresponding off-mesh navigation object
  119.         assert(m_offMeshMap.validate(meshID));
  120.         MNM::OffMeshNavigation& offMeshNavigation = m_offMeshMap[meshID];
  121.  
  122.         // Important: if we already added this particular link before, we need to remove it prior to re-adding it, as the startTriangleID might be
  123.         //            a different one now and then the NavMesh would suddenly have 2 different triangle-links referring to the same offmesh-link.
  124.         //            This can happen if there are multiple add-link requests in m_operations dealing with the same linkID but with *different* start/end positions (!)
  125.         TLinkInfoMap::const_iterator it = m_links.find(linkID);
  126.         if (it != m_links.end())
  127.         {
  128.                 // we added this link before already, now see if the starting triangle changed
  129.                 if (it->second.startTriangleID != startTriangleID)
  130.                 {
  131.                         // gotcha! (notice that we end up here very rarely in practice)
  132.                         offMeshNavigation.RemoveLink(mesh, it->second.startTriangleID, linkID);
  133.                 }
  134.         }
  135.  
  136.         // Register the new link with the off-mesh navigation system
  137.         offMeshNavigation.AddLink(mesh, startTriangleID, endTriangleID, *&linkID);
  138.         assert(linkID > 0);
  139.  
  140.         MNM::OffMeshLinkPtr pOffMeshLink;
  141.         if (bCloneLinkData)
  142.         {
  143.                 pOffMeshLink.reset(linkData.Clone());
  144.         }
  145.         else
  146.         {
  147.                 pOffMeshLink = pLinkData;
  148.         }
  149.         pOffMeshLink->SetLinkID(linkID);
  150.  
  151.         m_links[linkID] = SLinkInfo(meshID, startTriangleID, endTriangleID, std::move(pOffMeshLink));
  152.  
  153.         gAIEnv.pNavigationSystem->AddOffMeshLinkIslandConnectionsBetweenTriangles(meshID, startTriangleID, endTriangleID, linkID);
  154.  
  155.         return true;
  156. }
  157.  
  158. void OffMeshNavigationManager::RemoveCustomLink(const MNM::OffMeshLinkID& linkID)
  159. {
  160.         TLinkInfoMap::iterator linkIt = m_links.find(linkID);
  161.         if (linkIt != m_links.end())
  162.         {
  163.                 SLinkInfo& linkInfo = linkIt->second;
  164.  
  165.                 // Select the corresponding off-mesh navigation object
  166.                 assert(m_offMeshMap.validate(linkInfo.meshID));
  167.                 MNM::OffMeshNavigation& offMeshNavigation = m_offMeshMap[linkInfo.meshID];
  168.                 NavigationMesh& mesh = gAIEnv.pNavigationSystem->GetMesh(linkInfo.meshID);
  169.  
  170.                 // Remove link
  171.                 // NOTE: There should only ever be one element in the link array
  172.                 offMeshNavigation.RemoveLink(mesh, linkInfo.startTriangleID, linkID);
  173.  
  174.                 gAIEnv.pNavigationSystem->RemoveOffMeshLinkIslandsConnectionBetweenTriangles(linkInfo.meshID, linkInfo.startTriangleID, linkInfo.endTriangleID, linkID);
  175.  
  176.                 // Remove cached data
  177.                 m_links.erase(linkIt);
  178.         }
  179. }
  180.  
  181. void OffMeshNavigationManager::ProcessQueuedRequests()
  182. {
  183.         if (!m_operations.empty())
  184.         {
  185.                 for (Operations::iterator it = m_operations.begin(); it != m_operations.end(); ++it)  // notice: the callbacks might add new operations, so we cannot simply cache end()
  186.                 {
  187.                         switch (it->operationType)
  188.                         {
  189.                         case MNM::eOffMeshOperationType_Add:
  190.                                 {
  191.                                         const bool linkGotSuccessfullyAdded = AddCustomLink(it->meshId, it->pLinkData, it->linkId, it->bCloneLinkData);
  192.                                         if (it->callback)
  193.                                         {
  194.                                                 it->callback(MNM::SOffMeshOperationCallbackData(it->linkId, linkGotSuccessfullyAdded));
  195.                                         }
  196.                                 }
  197.                                 break;
  198.                         case MNM::eOffMeshOperationType_Remove:
  199.                                 NotifyAllListenerAboutLinkDeletion(it->linkId);
  200.                                 RemoveCustomLink(it->linkId);
  201.                                 break;
  202.                         default:
  203.                                 assert(0);
  204.                         }
  205.  
  206.                 }
  207.  
  208.                 stl::free_container(m_operations);
  209.         }
  210. }
  211.  
  212. void OffMeshNavigationManager::NotifyAllListenerAboutLinkDeletion(const MNM::OffMeshLinkID& linkID)
  213. {
  214.         for (Listeners::Notifier notifier(m_listeners); notifier.IsValid(); notifier.Next())
  215.         {
  216.                 notifier->OnOffMeshLinkGoingToBeRemoved(linkID);
  217.         }
  218. }
  219.  
  220. MNM::OffMeshLink* OffMeshNavigationManager::GetOffMeshLink(const MNM::OffMeshLinkID& linkID)
  221. {
  222.         TLinkInfoMap::iterator linkIt = m_links.find(linkID);
  223.         if (linkIt != m_links.end())
  224.         {
  225.                 SLinkInfo& linkInfo = linkIt->second;
  226.                 return linkInfo.offMeshLink.get();
  227.         }
  228.  
  229.         return NULL;
  230. }
  231.  
  232. const MNM::OffMeshLink* OffMeshNavigationManager::GetOffMeshLink(const MNM::OffMeshLinkID& linkID) const
  233. {
  234.         TLinkInfoMap::const_iterator linkIt = m_links.find(linkID);
  235.         if (linkIt != m_links.end())
  236.         {
  237.                 const SLinkInfo& linkInfo = linkIt->second;
  238.                 return linkInfo.offMeshLink.get();
  239.         }
  240.  
  241.         return NULL;
  242. }
  243.  
  244. void OffMeshNavigationManager::RegisterListener(IOffMeshNavigationListener* pListener, const char* listenerName)
  245. {
  246.         m_listeners.Add(pListener, listenerName);
  247. }
  248.  
  249. void OffMeshNavigationManager::UnregisterListener(IOffMeshNavigationListener* pListener)
  250. {
  251.         m_listeners.Remove(pListener);
  252. }
  253.  
  254. void OffMeshNavigationManager::RemoveAllQueuedAdditionRequestForEntity(const EntityId requestOwner)
  255. {
  256.         m_operations.erase(std::remove_if(m_operations.begin(), m_operations.end(), MNM::IsOffMeshAdditionOperationRequestRelatedToEntity(requestOwner)), m_operations.end());
  257. }
  258. //////////////////////////////////////////////////////////////////////////
  259. //////////////////////////////////////////////////////////////////////////
  260. class CRegisterSOHelper
  261. {
  262. public:
  263.         struct SHelperInfo
  264.         {
  265.                 SHelperInfo(const MNM::TriangleID& _triangleID, const Vec3& _position, SmartObjectHelper* _pHelper)
  266.                         : triangleID(_triangleID)
  267.                         , position(_position)
  268.                         , pHelper(_pHelper)
  269.                 {
  270.  
  271.                 }
  272.  
  273.                 SmartObjectHelper* pHelper;
  274.                 MNM::TriangleID    triangleID;
  275.                 Vec3               position;
  276.         };
  277.         typedef std::vector<SHelperInfo> THelpersInfo;
  278.  
  279.         struct SHelpersLink
  280.         {
  281.                 SHelpersLink(int from, int to)
  282.                         : fromIndex(from)
  283.                         , toIndex(to)
  284.                 {
  285.  
  286.                 }
  287.  
  288.                 bool operator==(const SHelpersLink& other) const
  289.                 {
  290.                         return (fromIndex == other.fromIndex) && (toIndex == other.toIndex);
  291.                 }
  292.  
  293.                 int fromIndex;
  294.                 int toIndex;
  295.         };
  296.         typedef std::vector<SHelpersLink> TObjectLinks;
  297.  
  298.         struct SAgentTypeInfo
  299.         {
  300.                 friend class CRegisterSOHelper;
  301.  
  302.                 SAgentTypeInfo(NavigationAgentTypeID _agentTypeID)
  303.                         : agentTypeID(_agentTypeID)
  304.                 {
  305.  
  306.                 }
  307.  
  308.                 ILINE NavigationAgentTypeID GetAgentTypeID() const { return agentTypeID; }
  309.  
  310.                 bool                        IsUserClassCompatible(const char* userClass)
  311.                 {
  312.                         for (size_t i = 0; i < userClasses.size(); ++i)
  313.                         {
  314.                                 if (strcmp(userClasses[i].c_str(), userClass))
  315.                                         continue;
  316.  
  317.                                 return true;
  318.                         }
  319.  
  320.                         return false;
  321.                 }
  322.  
  323.         private:
  324.  
  325.                 ILINE void AddUserClass(const char* userClass) { stl::push_back_unique(userClasses, userClass); }
  326.  
  327.                 NavigationAgentTypeID agentTypeID;
  328.                 std::vector<string>   userClasses;
  329.         };
  330.  
  331.         CRegisterSOHelper(CSmartObject& smartObject, CSmartObjectClass& smartObjectClass)
  332.                 : m_smartObject(smartObject)
  333.                 , m_smartObjectClass(smartObjectClass)
  334.                 , m_navigationSystem(*gAIEnv.pNavigationSystem)
  335.         {
  336.                 GenerateCompatibleTypes();
  337.         }
  338.  
  339.         bool GetAgentInfo(SAgentTypeInfo& agentInfo)
  340.         {
  341.                 if (m_currentElement < m_supportedAgentTypes.size())
  342.                 {
  343.                         agentInfo = m_supportedAgentTypes[m_currentElement];
  344.                         m_currentElement++;
  345.                         return true;
  346.                 }
  347.  
  348.                 return false;
  349.         }
  350.  
  351.         bool CanRegister() const
  352.         {
  353.                 return !(m_supportedAgentTypes.empty());
  354.         }
  355.  
  356. private:
  357.  
  358.         void GenerateCompatibleTypes()
  359.         {
  360.                 const CSmartObjectClass::THelperLinks::const_iterator itLinksBegin = m_smartObjectClass.m_vHelperLinks.begin();
  361.                 const CSmartObjectClass::THelperLinks::const_iterator itLinksEnd = m_smartObjectClass.m_vHelperLinks.end();
  362.  
  363.                 size_t agentTypeCount = m_navigationSystem.GetAgentTypeCount();
  364.                 m_supportedAgentTypes.reserve(agentTypeCount);
  365.  
  366.                 for (size_t agentIdx = 0; agentIdx < agentTypeCount; ++agentIdx)
  367.                 {
  368.                         const NavigationAgentTypeID agentTypeId = m_navigationSystem.GetAgentTypeID(agentIdx);
  369.                         bool addAgentTypeInfo = false;
  370.                         SAgentTypeInfo agentTypeInfo(agentTypeId);
  371.  
  372.                         for (CSmartObjectClass::THelperLinks::const_iterator linkIt = itLinksBegin; linkIt != itLinksEnd; ++linkIt)
  373.                         {
  374.                                 const CSmartObjectClass::HelperLink& helperLink = *linkIt;
  375.                                 const char* userClassName = (helperLink.condition && helperLink.condition->pUserClass) ? helperLink.condition->pUserClass->GetName().c_str() : NULL;
  376.  
  377.                                 if (userClassName && m_navigationSystem.AgentTypeSupportSmartObjectUserClass(agentTypeId, userClassName))
  378.                                 {
  379.                                         agentTypeInfo.AddUserClass(userClassName);
  380.                                         addAgentTypeInfo = true;
  381.                                 }
  382.                         }
  383.  
  384.                         if (addAgentTypeInfo)
  385.                         {
  386.                                 m_supportedAgentTypes.push_back(agentTypeInfo);
  387.                         }
  388.                 }
  389.  
  390.                 m_currentElement = 0;
  391.         }
  392.  
  393.         typedef std::vector<SAgentTypeInfo> TSupportedAgentTypes;
  394.         TSupportedAgentTypes m_supportedAgentTypes;
  395.         size_t               m_currentElement;
  396.  
  397.         CSmartObject&        m_smartObject;
  398.         CSmartObjectClass&   m_smartObjectClass;
  399.         NavigationSystem&    m_navigationSystem;
  400. };
  401.  
  402. void OffMeshNavigationManager::RegisterSmartObject(CSmartObject* pSmartObject, CSmartObjectClass* pSmartObjectClass)
  403. {
  404.         assert(pSmartObject && pSmartObjectClass);
  405.  
  406.         if (!CanRegisterObject() || pSmartObjectClass->IsSmartObjectUser())
  407.                 return;
  408.  
  409.         //Filter out non-compatible smart-objects first...
  410.         CRegisterSOHelper registerSOHelper(*pSmartObject, *pSmartObjectClass);
  411.         if (!registerSOHelper.CanRegister())
  412.                 return;
  413.  
  414.         //////////////////////////////////////////////////////////////////////////
  415.         /// If this smart object class is already associated with this object, unregister
  416.         /// all related links to ensure we don't duplicate.
  417.         if (ObjectRegistered(pSmartObject->GetEntityId(), pSmartObjectClass->GetName()))
  418.         {
  419.                 UnregisterSmartObject(pSmartObject, pSmartObjectClass->GetName());
  420.         }
  421.  
  422.         //////////////////////////////////////////////////////////////////////////
  423.         /// Register the object, no matter what, so we keep track of it
  424.         TRegisteredObjects::iterator registeredObjectIt = m_registeredObjects.find(pSmartObject->GetEntityId());
  425.         if (registeredObjectIt == m_registeredObjects.end())
  426.         {
  427.                 std::pair<TRegisteredObjects::iterator, bool> newObjectIt = m_registeredObjects.insert(TRegisteredObjects::value_type(pSmartObject->GetEntityId(), TSOClassInfo()));
  428.                 assert(newObjectIt.second);
  429.  
  430.                 registeredObjectIt = newObjectIt.first;
  431.         }
  432.  
  433.         //////////////////////////////////////////////////////////////////////////
  434.         /// Iterate through all compatible agent types for the smart object
  435.         CRegisterSOHelper::SAgentTypeInfo agentTypeInfo(NavigationAgentTypeID(0));
  436.         std::vector<SmartObjectHelper*> validHelpers;
  437.  
  438.         while (registerSOHelper.GetAgentInfo(agentTypeInfo))
  439.         {
  440.                 NavigationAgentTypeID agentTypeID = agentTypeInfo.GetAgentTypeID();
  441.                 NavigationMeshID targetMeshID;
  442.  
  443.                 validHelpers.clear();
  444.                 validHelpers.reserve(pSmartObjectClass->m_vHelperLinks.size());
  445.  
  446.                 std::vector<SmartObjectHelper*> validHelpers;
  447.  
  448.                 //////////////////////////////////////////////////////////////////////////
  449.                 /// Find out to which mesh the object should belong
  450.                 for (CSmartObjectClass::SetHelpers::iterator itHelpersEnd = pSmartObjectClass->m_setNavHelpers.end(),
  451.                      itHelpers = pSmartObjectClass->m_setNavHelpers.begin(); itHelpers != itHelpersEnd; ++itHelpers)
  452.                 {
  453.                         SmartObjectHelper* pHelper = *itHelpers;
  454.  
  455.                         // Calculate position
  456.                         const Vec3 helperPosition = pSmartObject->GetHelperPos(pHelper);
  457.  
  458.                         NavigationMeshID meshID = gAIEnv.pNavigationSystem->GetEnclosingMeshID(agentTypeID, helperPosition);
  459.  
  460.                         if (targetMeshID && (targetMeshID != meshID))
  461.                         {
  462.                                 //Bail out, not all helpers are connected to the same mesh
  463.                                 return;
  464.                         }
  465.  
  466.                         targetMeshID = meshID;
  467.                         validHelpers.push_back(pHelper);
  468.                 }
  469.  
  470.                 //////////////////////////////////////////////////////////////////////////
  471.                 /// Object belongs to a mesh; Create a new link
  472.                 if (targetMeshID)
  473.                 {
  474.                         // Grab the begin and end links of the smart object class
  475.                         const CSmartObjectClass::THelperLinks::const_iterator itLinksBegin = pSmartObjectClass->m_vHelperLinks.begin();
  476.                         const CSmartObjectClass::THelperLinks::const_iterator itLinksEnd = pSmartObjectClass->m_vHelperLinks.end();
  477.  
  478.                         // Cache of registered object links to prevent duplication during iteration
  479.                         CRegisterSOHelper::TObjectLinks registeredLinks;
  480.                         registeredLinks.reserve(pSmartObjectClass->m_vHelperLinks.size());
  481.  
  482.                         // Grab the link ID list
  483.                         // This is the link ID's generated for this smart object class on this smart object and are used as keys into m_links
  484.                         uint32 smartObjectClassNameCrC = CCrc32::ComputeLowercase(pSmartObjectClass->GetName().c_str());
  485.                         OffMeshLinkIDList& linkIDList = registeredObjectIt->second[smartObjectClassNameCrC];
  486.  
  487.                         // Iterate over each helper link, adding their start/end points as off-mesh links if compatible with the
  488.                         // chosen user class.
  489.                         for (CSmartObjectClass::THelperLinks::const_iterator linkIt = itLinksBegin; linkIt != itLinksEnd; ++linkIt)
  490.                         {
  491.                                 const CSmartObjectClass::HelperLink& helperLink = *linkIt;
  492.                                 const char* userClassName = (helperLink.condition && helperLink.condition->pUserClass) ? helperLink.condition->pUserClass->GetName().c_str() : NULL;
  493.  
  494.                                 if (!userClassName || !agentTypeInfo.IsUserClassCompatible(userClassName))
  495.                                         continue;  // Invalid smart object class name or not compatible with user smart object class
  496.  
  497.                                 // Determine to/from helper indexes of this helper link
  498.                                 int helperIndex = 0;
  499.                                 int fromIndex = -1;
  500.                                 int toIndex = -1;
  501.                                 CSmartObjectClass::SetHelpers& helpers = pSmartObjectClass->m_setNavHelpers;
  502.                                 CSmartObjectClass::SetHelpers::iterator itHelpersEnd = helpers.end();
  503.                                 for (CSmartObjectClass::SetHelpers::iterator itHelpers = helpers.begin(); itHelpers != itHelpersEnd; ++itHelpers, ++helperIndex)
  504.                                 {
  505.                                         if (linkIt->from == *itHelpers)
  506.                                         {
  507.                                                 fromIndex = helperIndex;
  508.                                         }
  509.                                         else if (linkIt->to == *itHelpers)
  510.                                         {
  511.                                                 toIndex = helperIndex;
  512.                                         }
  513.                                 }
  514.  
  515.                                 // If both helper indexes are valid, attempt to register link
  516.                                 if ((fromIndex != -1) && (toIndex != -1))
  517.                                 {
  518.                                         const bool alreadyRegistered = stl::find(registeredLinks, CRegisterSOHelper::SHelpersLink(fromIndex, toIndex));
  519.                                         if (!alreadyRegistered)
  520.                                         {
  521.                                                 const EntityId smartObjectEntityId = pSmartObject->GetEntityId();
  522.                                                 // Create a smart object off-mesh link data
  523.                                                 MNM::OffMeshLinkPtr linkData(new OffMeshLink_SmartObject(smartObjectEntityId, pSmartObject, pSmartObjectClass, validHelpers[fromIndex], validHelpers[toIndex]));
  524.  
  525.                                                 // Register the new link with the off-mesh navigation system
  526.                                                 MNM::OffMeshLinkID linkID = MNM::Constants::eOffMeshLinks_InvalidOffMeshLinkID;
  527.  
  528.                                                 MNM::LinkAdditionRequest request(smartObjectEntityId, targetMeshID, linkData, linkID);
  529.                                                 request.SetCallback(functor(linkIDList, &OffMeshNavigationManager::OffMeshLinkIDList::OnLinkAdditionRequestForSmartObjectServiced));
  530.                                                 QueueCustomLinkAddition(request);
  531.  
  532.                                                 // Prevent duplicate registration
  533.                                                 registeredLinks.push_back(CRegisterSOHelper::SHelpersLink(fromIndex, toIndex));
  534.                                         }
  535.                                 }
  536.                         }
  537.                 }
  538.         }
  539. }
  540.  
  541. void OffMeshNavigationManager::UnregisterSmartObjectForAllClasses(CSmartObject* pSmartObject)
  542. {
  543.         CSmartObjectClasses& classes = pSmartObject->GetClasses();
  544.         CSmartObjectClasses::iterator it, itEnd = classes.end();
  545.  
  546.         for (it = classes.begin(); it != itEnd; ++it)
  547.         {
  548.                 UnregisterSmartObject(pSmartObject, (*it)->GetName());
  549.         }
  550. }
  551.  
  552. void OffMeshNavigationManager::UnregisterSmartObject(CSmartObject* pSmartObject, const string& smartObjectClassName)
  553. {
  554.         assert(pSmartObject);
  555.  
  556.         // Attempt to find the object in the registered list
  557.         const EntityId objectId = pSmartObject->GetEntityId();
  558.         TRegisteredObjects::iterator objectIt = m_registeredObjects.find(objectId);
  559.  
  560.         if (objectIt != m_registeredObjects.end())
  561.         {
  562.                 uint32 smartObjectClassNameCrC = CCrc32::ComputeLowercase(smartObjectClassName.c_str());
  563.                 TSOClassInfo::iterator classIt = objectIt->second.find(smartObjectClassNameCrC);
  564.                 if (classIt != objectIt->second.end())
  565.                 {
  566.                         // Remove associated links
  567.                         const OffMeshLinkIDList::TLinkIDList& linkList = classIt->second.GetLinkIDList();
  568.                         for (int i = 0; i < linkList.size(); ++i)
  569.                         {
  570.                                 MNM::LinkRemovalRequest request(objectId, linkList[i]);
  571.                                 QueueCustomLinkRemoval(request);
  572.                         }
  573.  
  574.                         // Remove object from registration
  575.                         objectIt->second.erase(classIt);
  576.                 }
  577.  
  578.                 // If there aren't any classes remaining on this registered object, remove it.
  579.                 if (objectIt->second.size() == 0)
  580.                 {
  581.                         RemoveAllQueuedAdditionRequestForEntity(objectId);
  582.                         m_registeredObjects.erase(objectIt);
  583.                 }
  584.         }
  585. }
  586.  
  587. void OffMeshNavigationManager::RefreshConnections(const NavigationMeshID meshID, const MNM::TileID tileID)
  588. {
  589.         if (m_offMeshMap.validate(meshID))
  590.         {
  591.                 MNM::OffMeshNavigation& offMeshNavigation = m_offMeshMap[meshID];
  592.                 NavigationMesh& mesh = gAIEnv.pNavigationSystem->GetMesh(meshID);
  593.  
  594.                 //////////////////////////////////////////////////////////////////////////
  595.                 // Invalidate links for the tile.
  596.                 // Because the tile has been regenerated, all outgoing off-mesh links are invalid now
  597.                 offMeshNavigation.InvalidateLinks(tileID);
  598.  
  599.                 //////////////////////////////////////////////////////////////////////////
  600.                 /// Refresh all links tied to this mesh and tile
  601.                 /// NOTE: This only re-adds them to the Tile with the cached data.
  602.                 TLinkInfoMap::iterator iter;
  603.                 for (iter = m_links.begin(); iter != m_links.end(); )
  604.                 {
  605.                         // Find out if object is bound to the modified mesh and tile
  606.                         SLinkInfo& linkInfo = iter->second;
  607.                         if (linkInfo.meshID != meshID)
  608.                         {
  609.                                 ++iter;
  610.                                 continue;  // Mismatched mesh id
  611.                         }
  612.  
  613.                         const bool isLinkOutgoingFromThisTile = (tileID == MNM::ComputeTileID(linkInfo.startTriangleID));
  614.                         const bool isLinkIncomingToThisTile = (tileID == MNM::ComputeTileID(linkInfo.endTriangleID));
  615.  
  616.                         // is the link completely unrelated to given tile?
  617.                         if (!isLinkOutgoingFromThisTile && !isLinkIncomingToThisTile)
  618.                         {
  619.                                 ++iter;
  620.                                 continue;
  621.                         }
  622.  
  623.                         // is the link incoming from a different tile?
  624.                         // -> need to remove it before it can potentially become a dangling link (i. e. the triangleID where it ends would no longer exist or would have morphed into a different one)
  625.                         //    (in fact, it *is* already a dangling link because given tile has just been regenerated and all its triangleIDs most likely have changed!)
  626.                         //    Notice that InvalidateLinks(tileID) only cares about outgoing links and also doesn't remove the link-information from the NavMesh, so we need
  627.                         //    to call RemoveLink() to get the NavMesh patched as well.
  628.                         if (isLinkIncomingToThisTile && !isLinkOutgoingFromThisTile)
  629.                         {
  630.                                 const MNM::OffMeshLinkID& linkID = iter->first;
  631.                                 offMeshNavigation.RemoveLink(mesh, linkInfo.startTriangleID, linkID);
  632.                         }
  633.  
  634.                         // disconnect whatever islands were connected by the offmesh-link
  635.                         // TODO pavloi 2016.02.05: actually, it will remove all links, which have the same owner as this link, from same meshID.
  636.                         // We probably should call RemoveOffMeshLinkIslandsConnectionBetweenTriangles(), but we need to know start and end triangles to
  637.                         // get the start and end island. Right now, I'm not sure, whether the triangleId's in linkInfo are valid at this stage, so I leave this
  638.                         // call as it is.
  639.                         gAIEnv.pNavigationSystem->RemoveAllIslandConnectionsForObject(linkInfo.meshID, linkInfo.offMeshLink->GetEntityIdForOffMeshLink());
  640.  
  641.                         // Try to re-connect everything later on, but only if it was not explicitly requested to be deleted by an outside source.
  642.                         // For example: if, at the exact same update the tile was refreshed but an outside source also requested the explicit
  643.                         // removal of a link then we should basically not re-apply the link.
  644.                         const MNM::OffMeshLinkID& linkID = iter->first;
  645.                         if (!IsLinkRemovalRequested(linkID))
  646.                         {
  647.                                 MNM::LinkAdditionRequest request(linkInfo.offMeshLink->GetEntityIdForOffMeshLink(), meshID, linkInfo.offMeshLink, linkID);
  648.  
  649.                                 // Link data was already cloned when it was added the first time. If we clone it again, the game-side of the link have no way
  650.                                 // to know, that link data was cloned (there is no event about refreshed connections). That means, if the game-side holds a
  651.                                 // pointer to the link, it will become dangling and will lead to crash.
  652.                                 request.bCloneLinkData = false;
  653.  
  654.                                 OffMeshLinkIDList* linkIDList = GetClassInfoFromLinkInfo(linkInfo);
  655.                                 if (linkIDList)
  656.                                 {
  657.                                         //stored linkID is removed from OffMeshLinkIDList in callback, when the link cannot be added again.
  658.                                         request.SetCallback(functor(*linkIDList, &OffMeshNavigationManager::OffMeshLinkIDList::OnLinkRepairRequestForSmartObjectServiced));
  659.                                 }
  660.                                 QueueCustomLinkAddition(request);
  661.                         }
  662.  
  663.                         // But for the meantime, also remove the entry from m_links because the .triangleID member was referencing a triangle in the now regenerated tile (!)
  664.                         //
  665.                         // Carefully read this:
  666.                         //
  667.                         //    If we didn't do this, then remove-link requests and add-link requests in the m_operations queue could use that "dead" triangle reference
  668.                         //    to try to remove offmesh-links in the NavMesh where there was none, OR try to add offmesh-links in the NavMesh where there was one already, OR
  669.                         //    (even worse, as no assert will catch this scenario) it would manipulate *foreign* offmesh-links in the NavMesh.
  670.                         //
  671.                         m_links.erase(iter++);
  672.                 }
  673.  
  674.                 std::vector<EntityId> tempObjectIds;
  675.                 tempObjectIds.reserve(m_registeredObjects.size());
  676.  
  677.                 //////////////////////////////////////////////////////////////////////////
  678.                 /// Find object's smart classes which were unable to register before to be
  679.                 /// registered again because of the change
  680.                 for (auto objectIt = m_registeredObjects.cbegin(), iterEnd = m_registeredObjects.cend(); objectIt != iterEnd; ++objectIt)
  681.                 {
  682.                         const TSOClassInfo classInfos = objectIt->second;
  683.                         for (TSOClassInfo::const_iterator classIt = classInfos.begin(); classIt != classInfos.end(); ++classIt)
  684.                         {
  685.                                 const OffMeshLinkIDList::TLinkIDList& linkList = classIt->second.GetLinkIDList();
  686.                                 if (linkList.empty() == false)
  687.                                         continue;
  688.  
  689.                                 tempObjectIds.push_back(objectIt->first);
  690.                         }
  691.                 }
  692.  
  693.                 //////////////////////////////////////////////////////////////////////////
  694.                 /// Register again those objects which could have been affected by the change
  695.                 for (auto objectIt = tempObjectIds.cbegin(), iterEnd = tempObjectIds.cend(); objectIt != iterEnd; ++objectIt)
  696.                 {
  697.                         CSmartObject* pSmartObject = CSmartObjectManager::GetSmartObject(*objectIt);
  698.                         assert(pSmartObject);
  699.                         if (pSmartObject)
  700.                         {
  701.                                 CSmartObjectClasses& classes = pSmartObject->GetClasses();
  702.                                 CSmartObjectClasses::iterator it, itEnd = classes.end();
  703.                                 for (it = classes.begin(); it != itEnd; ++it)
  704.                                 {
  705.                                         CSmartObjectClass* pSmartObjectClass = *it;
  706.  
  707.                                         RegisterSmartObject(pSmartObject, pSmartObjectClass);
  708.                                 }
  709.                         }
  710.                 }
  711.         }
  712. }
  713.  
  714. OffMeshNavigationManager::OffMeshLinkIDList* OffMeshNavigationManager::GetClassInfoFromLinkInfo(const SLinkInfo& linkInfo)
  715. {
  716.         EntityId entityId = linkInfo.offMeshLink->GetEntityIdForOffMeshLink();
  717.         TRegisteredObjects::iterator objectIt = m_registeredObjects.find(entityId);
  718.         if (objectIt != m_registeredObjects.end())
  719.         {
  720.                 TSOClassInfo* classInfos = &objectIt->second;
  721.                 for (TSOClassInfo::iterator classIt = classInfos->begin(); classIt != classInfos->end(); ++classIt)
  722.                 {
  723.                         const OffMeshLinkIDList::TLinkIDList& linkList = classIt->second.GetLinkIDList();
  724.                         for (size_t i = 0; i < linkList.size(); ++i)
  725.                         {
  726.                                 if (linkList[i] == linkInfo.offMeshLink->GetLinkId())
  727.                                 {
  728.                                         return &classIt->second;
  729.                                 }
  730.                         }
  731.                 }
  732.         }
  733.         assert(0);
  734.         return nullptr;
  735. }
  736.  
  737. void OffMeshNavigationManager::Clear()
  738. {
  739.         m_offMeshMap.clear();
  740.         m_registeredObjects.clear();
  741.         m_links.clear();
  742.         m_objectRegistrationEnabled = false;
  743.  
  744.         stl::free_container(m_operations);
  745. }
  746.  
  747. void OffMeshNavigationManager::Enable()
  748. {
  749.         m_objectRegistrationEnabled = true;
  750. }
  751.  
  752. void OffMeshNavigationManager::OnNavigationMeshCreated(const NavigationMeshID& meshID)
  753. {
  754.         assert(!m_offMeshMap.validate(meshID));
  755.  
  756.         m_offMeshMap.insert(meshID, MNM::OffMeshNavigation());
  757. }
  758.  
  759. void OffMeshNavigationManager::OnNavigationMeshDestroyed(const NavigationMeshID& meshID)
  760. {
  761.         assert(m_offMeshMap.validate(meshID));
  762.  
  763.         m_offMeshMap.erase(meshID);
  764.  
  765.         //////////////////////////////////////////////////////////////////////////
  766.         /// Remove all existing links for this mesh
  767.         OffMeshLinkIDList::TLinkIDList removedLinkIDs;
  768.         TLinkInfoMap::iterator iter;
  769.         for (iter = m_links.begin(); iter != m_links.end(); )
  770.         {
  771.                 // Find out if object is bound to the modified mesh and tile
  772.                 SLinkInfo& linkInfo = iter->second;
  773.                 if (linkInfo.meshID != meshID)
  774.                 {
  775.                         ++iter;
  776.                         continue;  // Mismatched mesh id
  777.                 }
  778.  
  779.                 const MNM::OffMeshLinkID& linkID = iter->first;
  780.                 removedLinkIDs.push_back(linkID);
  781.  
  782.                 NotifyAllListenerAboutLinkDeletion(linkID);
  783.  
  784.                 m_links.erase(iter++);
  785.         }
  786.  
  787.         //////////////////////////////////////////////////////////////////////////
  788.         /// Remove smart object references to removed link IDs
  789.         for (TRegisteredObjects::iterator objectIt = m_registeredObjects.begin(); objectIt != m_registeredObjects.end(); ++objectIt)
  790.         {
  791.                 for (TSOClassInfo::iterator classInfoIt = objectIt->second.begin(); classInfoIt != objectIt->second.end(); ++classInfoIt)
  792.                 {
  793.                         OffMeshLinkIDList::TLinkIDList& linkList = classInfoIt->second.GetLinkIDList();
  794.                         for (int i = 0; i < removedLinkIDs.size(); ++i)
  795.                         {
  796.                                 stl::find_and_erase(linkList, removedLinkIDs[i]);
  797.                         }
  798.                 }
  799.         }
  800. }
  801.  
  802. void OffMeshNavigationManager::OnNavigationLoadedComplete()
  803. {
  804.         //////////////////////////////////////////////////////////////////////////
  805.         //Only after the navigation loaded process is completed off-mesh links can be created
  806.         //Off-mesh links are created after the mesh is loaded, they are not stored within the mesh when exported
  807.         Enable();
  808. }
  809.  
  810. bool OffMeshNavigationManager::ObjectRegistered(const EntityId objectId, const string& smartObjectClassName) const
  811. {
  812.         uint32 smartObjectClassNameCrC = CCrc32::ComputeLowercase(smartObjectClassName.c_str());
  813.         TRegisteredObjects::const_iterator itFoundObject = m_registeredObjects.find(objectId);
  814.         return (itFoundObject != m_registeredObjects.end() && itFoundObject->second.find(smartObjectClassNameCrC) != itFoundObject->second.end());
  815. }
  816.  
  817. bool OffMeshNavigationManager::IsObjectLinkedWithNavigationMesh(const EntityId objectId) const
  818. {
  819.         TRegisteredObjects::const_iterator objectIt = m_registeredObjects.find(objectId);
  820.  
  821.         return (objectIt != m_registeredObjects.end()) ? !objectIt->second.empty() : false;
  822. }
  823.  
  824. //////////////////////////////////////////////////////////////////////////
  825. //////////////////////////////////////////////////////////////////////////
  826.  
  827. #if DEBUG_MNM_ENABLED
  828.  
  829. void OffMeshNavigationManager::UpdateEditorDebugHelpers()
  830. {
  831.         if (!gEnv->IsEditing())
  832.                 return;
  833.  
  834.         static float time = 0.0f;
  835.  
  836.         time += (gEnv->pTimer->GetFrameTime() * 2.5f);
  837.  
  838.         IRenderAuxGeom* pRenderAux = gEnv->pRenderer->GetIRenderAuxGeom();
  839.  
  840.         SAuxGeomRenderFlags oldFlags = pRenderAux->GetRenderFlags();
  841.         SAuxGeomRenderFlags renderFlags(oldFlags);
  842.  
  843.         renderFlags.SetAlphaBlendMode(e_AlphaBlended);
  844.         renderFlags.SetDepthWriteFlag(e_DepthWriteOff);
  845.  
  846.         pRenderAux->SetRenderFlags(renderFlags);
  847.  
  848.         TRegisteredObjects::const_iterator objectIt = m_registeredObjects.begin();
  849.         TRegisteredObjects::const_iterator endIt = m_registeredObjects.end();
  850.  
  851.         const float alpha = clamp_tpl((1.0f + sinf(time)) * 0.5f, 0.25f, 0.7f);
  852.         const ColorB color(255, 0, 0, (uint8)(alpha * 255));
  853.  
  854.         for (; objectIt != endIt; ++objectIt)
  855.         {
  856.                 if (!objectIt->second.empty())
  857.                         continue;
  858.  
  859.                 IEntity* pObjectEntity = gEnv->pEntitySystem->GetEntity(objectIt->first);
  860.                 if (pObjectEntity)
  861.                 {
  862.                         uint32 numSOFound = 0;
  863.                         gAIEnv.pSmartObjectManager->GetSOClassTemplateIStatObj(pObjectEntity, NULL, numSOFound);
  864.  
  865.                         ISmartObjectManager::IStatObjPtr* ppStatObjects = NULL;
  866.                         if (numSOFound)
  867.                         {
  868.                                 ppStatObjects = new ISmartObjectManager::IStatObjPtr[numSOFound];
  869.                                 if (gAIEnv.pSmartObjectManager->GetSOClassTemplateIStatObj(pObjectEntity, ppStatObjects, numSOFound) > 0)
  870.                                 {
  871.                                         pRenderAux->DrawAABB(ppStatObjects[0]->GetAABB(), pObjectEntity->GetWorldTM(), true, color, eBBD_Faceted);
  872.                                 }
  873.  
  874.                                 SAFE_DELETE_ARRAY(ppStatObjects);
  875.                         }
  876.                 }
  877.  
  878.         }
  879.  
  880.         pRenderAux->SetRenderFlags(oldFlags);
  881. }
  882.  
  883. OffMeshNavigationManager::ProfileMemoryStats OffMeshNavigationManager::GetMemoryStats(ICrySizer* pSizer, const NavigationMeshID meshID) const
  884. {
  885.         const size_t initialSize = pSizer->GetTotalSize();
  886.         ProfileMemoryStats memStats;
  887.  
  888.         // for all links: track memory of the ones with given mesh ID
  889.         for (TLinkInfoMap::const_iterator it = m_links.begin(); it != m_links.end(); ++it)
  890.         {
  891.                 const SLinkInfo& linkInfo = it->second;
  892.  
  893.                 if (linkInfo.meshID == meshID)
  894.                 {
  895.                         const size_t sizeBeforeLinkInfo = pSizer->GetTotalSize();
  896.                         pSizer->AddObjectSize(&linkInfo);
  897.                         memStats.linkInfoSize += pSizer->GetTotalSize() - sizeBeforeLinkInfo;
  898.                 }
  899.         }
  900.  
  901.         memStats.totalSize = pSizer->GetTotalSize() - initialSize;
  902.  
  903.         return memStats;
  904. }
  905.  
  906. #endif
  907.  
downloadOffMeshNavigationManager.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top