BVB Source Codes

CRYENGINE Show MovementSystem.cpp Source code

Return Download CRYENGINE: download MovementSystem.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 "MovementSystem.h"
  5. #include <CryAISystem/MovementRequest.h>
  6. #include <CryAISystem/MovementUpdateContext.h>
  7. #include "MovementPlanner.h"
  8. #include "AIConsoleVariables.h"
  9.  
  10. #include "MovementBlock_DefaultEmpty.h"
  11.  
  12. #if defined(COMPILE_WITH_MOVEMENT_SYSTEM_DEBUG)
  13.         #include <CryAISystem/IAIDebugRenderer.h>
  14. #endif
  15.  
  16. bool IsActorValidForMovementUpdateContextCreation(MovementActor& actor)
  17. {
  18.         if (actor.callbacks.getPathFollowerFunction && actor.callbacks.getPathFollowerFunction())
  19.         {
  20.                 assert(actor.planner.get() != NULL);
  21.                 IF_UNLIKELY (actor.planner.get() == NULL)
  22.                         return false;
  23.  
  24.                 return true;
  25.         }
  26.  
  27.         return false;
  28. }
  29.  
  30. MovementUpdateContext CreateMovementUpdateContextFrom(
  31.   MovementActor& actor, MovementSystem& system, const float updateTime)
  32. {
  33.         IPathFollower* pathFollower = actor.callbacks.getPathFollowerFunction();
  34.  
  35.         assert(pathFollower);
  36.  
  37.         return MovementUpdateContext(
  38.           actor,
  39.           system,
  40.           *pathFollower,
  41.           *actor.planner.get(),
  42.           updateTime);
  43. }
  44.  
  45. class ActorMatchesIdPredicate
  46. {
  47. public:
  48.         ActorMatchesIdPredicate(const EntityId entityID)
  49.                 : m_entityID(entityID)
  50.         {
  51.         }
  52.  
  53.         bool operator()(const MovementActor& actor)
  54.         {
  55.                 return actor.entityID == m_entityID;
  56.         }
  57.  
  58. private:
  59.         EntityId m_entityID;
  60. };
  61.  
  62. MovementSystem::MovementSystem() : m_nextUniqueRequestID(0)
  63. {
  64. }
  65.  
  66. void MovementSystem::RegisterEntity(const EntityId entityId, MovementActorCallbacks callbacksConfiguration, IMovementActorAdapter& adapter)
  67. {
  68.         MovementActor& actor = MovementSystem::GetExistingActorOrCreateNewOne(entityId, adapter);
  69.  
  70.         actor.callbacks = callbacksConfiguration;
  71. }
  72.  
  73. void MovementSystem::UnregisterEntity(const EntityId entityId)
  74. {
  75.         m_actors.erase(std::remove_if(m_actors.begin(), m_actors.end(), ActorMatchesIdPredicate(entityId)), m_actors.end());
  76. }
  77.  
  78. MovementRequestID MovementSystem::QueueRequest(const MovementRequest& request)
  79. {
  80.         assert(request.entityID);
  81.  
  82.         const MovementRequestID requestID = GenerateUniqueMovementRequestID();
  83.  
  84.         MovementActor* pActor = GetExistingActor(request.entityID);
  85.  
  86.         if (!pActor)
  87.         {
  88.                 return MovementRequestID::Invalid();
  89.         }
  90.  
  91.         pActor->requestQueue.push_back(requestID);
  92.  
  93.         m_requests.push_back(MovementRequestPair(requestID, request));
  94.  
  95.         return requestID;
  96. }
  97.  
  98. class RequestMatchesIdPredicate
  99. {
  100. public:
  101.         RequestMatchesIdPredicate(const MovementRequestID& id)
  102.                 : m_id(id)
  103.         {
  104.         }
  105.  
  106.         bool operator()(const MovementSystem::MovementRequestPair& requestPair) const
  107.         {
  108.                 return requestPair.first == m_id;
  109.         }
  110.  
  111. private:
  112.         MovementRequestID m_id;
  113. };
  114.  
  115. void MovementSystem::CancelRequest(const MovementRequestID& requestID)
  116. {
  117.         const Requests::iterator requestIt = std::find_if(m_requests.begin(), m_requests.end(), RequestMatchesIdPredicate(requestID));
  118.  
  119.         if (requestIt != m_requests.end())
  120.         {
  121.                 const MovementRequest& request = requestIt->second;
  122.  
  123.                 const Actors::iterator actorIt = std::find_if(m_actors.begin(), m_actors.end(), ActorMatchesIdPredicate(request.entityID));
  124.  
  125.                 if (actorIt != m_actors.end())
  126.                 {
  127.                         MovementActor& actor = *actorIt;
  128.  
  129.                         if (IsPlannerWorkingOnRequestID(actor, requestID))
  130.                         {
  131.                                 actor.planner->CancelCurrentRequest(actor);
  132.                                 actor.requestIdCurrentlyInPlanner = 0;
  133.                         }
  134.  
  135.                         stl::find_and_erase(actor.requestQueue, requestID);
  136.                 }
  137.  
  138.                 m_requests.erase(requestIt);
  139.         }
  140. }
  141.  
  142. void MovementSystem::GetRequestStatus(const MovementRequestID& requestID, MovementRequestStatus& status) const
  143. {
  144.         status.id = MovementRequestStatus::NotQueued;
  145.  
  146.         Actors::const_iterator actorIt = m_actors.begin();
  147.         Actors::const_iterator actorEnd = m_actors.end();
  148.  
  149.         for (; actorIt != actorEnd; ++actorIt)
  150.         {
  151.                 const MovementActor& actor = *actorIt;
  152.  
  153.                 // Is the request being processed right now?
  154.                 if (IsPlannerWorkingOnRequestID(actor, requestID))
  155.                 {
  156.                         actor.planner->GetStatus(status);
  157.                         return;
  158.                 }
  159.  
  160.                 // See if it's at least queued
  161.                 MovementRequestQueue::const_iterator requestIt = actor.requestQueue.begin();
  162.                 MovementRequestQueue::const_iterator requestEnd = actor.requestQueue.end();
  163.  
  164.                 for (; requestIt != requestEnd; ++requestIt)
  165.                 {
  166.                         if (*requestIt == requestID)
  167.                         {
  168.                                 status.id = MovementRequestStatus::Queued;
  169.                                 return;
  170.                         }
  171.                 }
  172.         }
  173. }
  174.  
  175. void MovementSystem::Update(float updateTime)
  176. {
  177.         UpdateActors(updateTime);
  178.  
  179. #if defined(COMPILE_WITH_MOVEMENT_SYSTEM_DEBUG)
  180.         if (gAIEnv.CVars.DebugMovementSystem)
  181.         {
  182.                 DrawDebugInformation();
  183.         }
  184.         if (gAIEnv.CVars.DebugMovementSystemActorRequests)
  185.         {
  186.                 if (gAIEnv.CVars.DebugMovementSystemActorRequests == 1)
  187.                 {
  188.                         Actors::const_iterator itActor = std::find_if(m_actors.begin(), m_actors.end(), ActorMatchesIdPredicate(GetAISystem()->GetAgentDebugTarget()));
  189.                         if (itActor != m_actors.end())
  190.                         {
  191.                                 DrawMovementRequestsForActor(*itActor);
  192.                         }
  193.                 }
  194.                 else if (gAIEnv.CVars.DebugMovementSystemActorRequests == 2)
  195.                 {
  196.                         for (Actors::const_iterator itActor = m_actors.begin(); itActor != m_actors.end(); ++itActor)
  197.                         {
  198.                                 DrawMovementRequestsForActor(*itActor);
  199.                         }
  200.                 }
  201.         }
  202. #endif
  203. }
  204.  
  205. void MovementSystem::Reset()
  206. {
  207.         m_nextUniqueRequestID = 0;
  208.  
  209.         stl::free_container(m_actors);
  210.         stl::free_container(m_requests);
  211. }
  212.  
  213. void MovementSystem::RegisterFunctionToConstructMovementBlockForCustomNavigationType(Movement::CustomNavigationBlockCreatorFunction blockFactoryFunction)
  214. {
  215.         m_createMovementBlockToHandleCustomNavigationType = blockFactoryFunction;
  216. }
  217.  
  218. Movement::BlockPtr MovementSystem::CreateCustomBlock(const CNavPath& path, const PathPointDescriptor::OffMeshLinkData& mnmData, const MovementStyle& style)
  219. {
  220.         if (m_createMovementBlockToHandleCustomNavigationType)
  221.         {
  222.                 return m_createMovementBlockToHandleCustomNavigationType(path, mnmData, style);
  223.         }
  224.         else
  225.         {
  226.                 AIError("The movement block to handle a path point of the NAV_CUSTOM_NAVIGATION type is not defined.");
  227.                 static Movement::BlockPtr emptyBlock(new Movement::MovementBlocks::DefaultEmpty());
  228.                 return emptyBlock;
  229.         }
  230. }
  231.  
  232. MovementRequestID MovementSystem::GenerateUniqueMovementRequestID()
  233. {
  234.         while (!++m_nextUniqueRequestID)
  235.                 ;
  236.         return m_nextUniqueRequestID;
  237. }
  238.  
  239. void MovementSystem::FinishRequest(
  240.   MovementActor& actor,
  241.   const MovementRequestID requestId, // pass requestId by value to make a copy to be sure, that it is not changed due to the callback
  242.   MovementRequestResult::Result resultID,
  243.   MovementRequestResult::FailureReason failureReason)
  244. {
  245.         Requests::iterator itRequest = std::find_if(m_requests.begin(), m_requests.end(), RequestMatchesIdPredicate(requestId));
  246.         if (itRequest != m_requests.end())
  247.         {
  248.                 MovementRequest::Callback& callback = itRequest->second.callback;
  249.                 if (callback)
  250.                 {
  251.                         MovementRequestResult result(requestId, resultID, failureReason);
  252.                         callback(result); // Caution! The user callback code might invalidate iterators.
  253.                 }
  254.         }
  255.  
  256.         CleanUpAfterFinishedRequest(actor, requestId);
  257. }
  258.  
  259. void MovementSystem::CleanUpAfterFinishedRequest(MovementActor& actor, MovementRequestID activeRequestID)
  260. {
  261.         Requests::iterator itRequest = std::find_if(m_requests.begin(), m_requests.end(), RequestMatchesIdPredicate(activeRequestID));
  262.         if (itRequest != m_requests.end())
  263.         {
  264.                 m_requests.erase(itRequest);
  265.         }
  266.  
  267.         MovementRequestQueue::iterator itActorRequest = std::find(actor.requestQueue.begin(), actor.requestQueue.end(), activeRequestID);
  268.         if (itActorRequest != actor.requestQueue.end())
  269.         {
  270.                 actor.requestQueue.erase(itActorRequest);
  271.         }
  272.  
  273.         if (actor.requestIdCurrentlyInPlanner == activeRequestID)
  274.         {
  275.                 actor.requestIdCurrentlyInPlanner = 0;
  276.         }
  277. }
  278.  
  279. MovementRequest& MovementSystem::GetActiveRequest(MovementActor& actor, MovementRequestID* outRequestID)
  280. {
  281.         MovementRequestQueue& queue = actor.requestQueue;
  282.         assert(!queue.empty());
  283.  
  284.         MovementRequestID requestID = 0;
  285.         if (!queue.empty())
  286.                 requestID = queue.front();
  287.         else
  288.                 requestID = 0;
  289.  
  290.         if (outRequestID)
  291.                 *outRequestID = requestID;
  292.  
  293.         Requests::iterator it = std::find_if(m_requests.begin(), m_requests.end(), RequestMatchesIdPredicate(requestID));
  294.  
  295.         if (it != m_requests.end())
  296.                 return it->second;
  297.         else
  298.         {
  299.                 assert(0);
  300.                 static MovementRequest dummy;
  301.                 return dummy;
  302.         }
  303. }
  304.  
  305. MovementActor& MovementSystem::GetExistingActorOrCreateNewOne(const EntityId entityId, IMovementActorAdapter& adapter)
  306. {
  307.         Actors::iterator actorIt = std::find_if(m_actors.begin(), m_actors.end(), ActorMatchesIdPredicate(entityId));
  308.  
  309.         if (actorIt != m_actors.end())
  310.         {
  311.                 // Return existing actor
  312.                 return *actorIt;
  313.         }
  314.         else
  315.         {
  316.                 // Create new actor
  317.                 MovementActor actor(entityId, &adapter);
  318.                 actor.planner.reset(new Movement::GenericPlanner(adapter.GetNavigationAgentTypeID()));
  319.                 m_actors.push_back(actor);
  320.                 return m_actors.back();
  321.         }
  322. }
  323.  
  324. MovementActor* MovementSystem::GetExistingActor(const EntityId entityId)
  325. {
  326.         Actors::iterator actorIt = std::find_if(m_actors.begin(), m_actors.end(), ActorMatchesIdPredicate(entityId));
  327.  
  328.         if (actorIt != m_actors.end())
  329.         {
  330.                 // Return existing actor
  331.                 return &(*actorIt);
  332.         }
  333.  
  334.         return NULL;
  335. }
  336.  
  337. bool MovementSystem::IsPlannerWorkingOnRequestID(const MovementActor& actor, const MovementRequestID& id) const
  338. {
  339.         return (actor.requestIdCurrentlyInPlanner == id) && (id != MovementRequestID::Invalid());
  340. }
  341.  
  342. void MovementSystem::UpdateActors(float updateTime)
  343. {
  344.         using namespace Movement;
  345.  
  346.         Actors::iterator actorIt = m_actors.begin();
  347.  
  348.         while (actorIt != m_actors.end())
  349.         {
  350.                 MovementActor& actor = *actorIt;
  351.  
  352.                 const ActorUpdateStatus status = UpdateActor(actor, updateTime);
  353.  
  354.                 ++actorIt;
  355.         }
  356. }
  357.  
  358. MovementSystem::ActorUpdateStatus MovementSystem::UpdateActor(MovementActor& actor, float updateTime)
  359. {
  360.         // Construct a movement context which contains everything needed for
  361.         // updating the passed in actor. Everything is validated once, here,
  362.         // before anything else is called, so there's no need to validate again!
  363.  
  364.         IF_UNLIKELY (!IsActorValidForMovementUpdateContextCreation(actor))
  365.         {
  366.                 return ActorCanBeRemoved;
  367.         }
  368.  
  369.         MovementUpdateContext context = CreateMovementUpdateContextFrom(actor, *this, updateTime);
  370.  
  371.         StartWorkingOnNewRequestIfPossible(context);
  372.  
  373.         if (context.planner.IsUpdateNeeded())
  374.         {
  375.                 UpdatePlannerAndDealWithResult(context);
  376.         }
  377.  
  378.         if (!actor.requestQueue.empty() || context.planner.IsUpdateNeeded())
  379.                 return KeepUpdatingActor;
  380.         else
  381.                 return ActorCanBeRemoved;
  382. }
  383.  
  384. void MovementSystem::StartWorkingOnNewRequestIfPossible(const MovementUpdateContext& context)
  385. {
  386.         using namespace Movement;
  387.  
  388.         MovementActor& actor = static_cast<MovementActor&>(context.actor);
  389.         MovementRequestQueue& requestQueue = actor.requestQueue;
  390.  
  391.         if (!requestQueue.empty())
  392.         {
  393.                 MovementRequestID frontRequestID;
  394.                 MovementRequest& request = GetActiveRequest(actor, OUT & frontRequestID);
  395.  
  396.                 IPlanner& planner = context.planner;
  397.                 if (!IsPlannerWorkingOnRequestID(actor, frontRequestID) && planner.IsReadyForNewRequest())
  398.                 {
  399.                         planner.StartWorkingOnRequest(frontRequestID, request, context);
  400.                         actor.requestIdCurrentlyInPlanner = frontRequestID;
  401.                 }
  402.         }
  403. }
  404.  
  405. void MovementSystem::UpdatePlannerAndDealWithResult(const MovementUpdateContext& context)
  406. {
  407.         using namespace Movement;
  408.  
  409.         IPlanner& planner = context.planner;
  410.         const IPlanner::Status status = planner.Update(context);
  411.  
  412.         // The front request could have been canceled and removed but
  413.         // the planner is still executing a plan that was produced to
  414.         // satisfy it.
  415.         // It's therefore important to be informed whether the planner is
  416.         // working on the front request or not before reacting to the
  417.         // result of the plan execution.
  418.  
  419.         MovementActor& actor = static_cast<MovementActor&>(context.actor);
  420.         MovementRequestQueue& requestQueue = actor.requestQueue;
  421.  
  422.         if (!requestQueue.empty() && IsPlannerWorkingOnRequestID(actor, requestQueue.front()))
  423.         {
  424.                 if (status.HasPathfinderFailed())
  425.                         FinishRequest(actor, status.GetRequestId(), MovementRequestResult::Failure, MovementRequestResult::CouldNotFindPathToRequestedDestination);
  426.                 else if (status.HasMovingAlongPathFailed())
  427.                         FinishRequest(actor, status.GetRequestId(), MovementRequestResult::Failure, MovementRequestResult::CouldNotMoveAlongDesignerDesignedPath);
  428.                 else if (status.HasReachedTheMaximumNumberOfReplansAllowed())
  429.                         FinishRequest(actor, status.GetRequestId(), MovementRequestResult::Failure, MovementRequestResult::FailedToProduceSuccessfulPlanAfterMaximumNumberOfAttempts);
  430.                 else if (status.HasRequestBeenSatisfied())
  431.                         FinishRequest(actor, status.GetRequestId(), MovementRequestResult::Success);
  432.         }
  433. }
  434.  
  435. #if defined(COMPILE_WITH_MOVEMENT_SYSTEM_DEBUG)
  436. void MovementSystem::DrawDebugInformation() const
  437. {
  438.         const float fontSize = 1.25f;
  439.         const float lineHeight = 11.5f * fontSize;
  440.         const float x = 10.0f;
  441.         float y = 30.0f;
  442.  
  443.         IAIDebugRenderer* renderer = gEnv->pAISystem->GetAIDebugRenderer();
  444.  
  445.         // Draw title
  446.         renderer->Draw2dLabel(x, y, fontSize, Col_White, false, "Movement System Information");
  447.         y += lineHeight;
  448.  
  449.         Actors::const_iterator actorIt = m_actors.begin();
  450.  
  451.         for (; actorIt != m_actors.end(); ++actorIt)
  452.         {
  453.                 const MovementActor& actor = *actorIt;
  454.  
  455.                 y += lineHeight;
  456.  
  457.                 // Draw actor's name
  458.                 renderer->Draw2dLabel(x, y, fontSize, Col_LightBlue, false, "%s", actor.GetName());
  459.                 y += lineHeight;
  460.  
  461.                 // Draw actor's movement status
  462.                 MovementRequestStatus status;
  463.                 actor.planner->GetStatus(OUT status);
  464.                 stack_string statusText;
  465.                 ConstructHumanReadableText(status, statusText);
  466.                 renderer->Draw2dLabel(x, y, fontSize, Col_White, false, "%s", statusText.c_str());
  467.                 y += lineHeight;
  468.         }
  469. }
  470.  
  471. void MovementSystem::DrawMovementRequestsForActor(const MovementActor& actor) const
  472. {
  473.         if (const IEntity* pEntity = gEnv->pEntitySystem->GetEntity(actor.GetEntityId()))
  474.         {
  475.                 const float spacing = 0.5f;
  476.  
  477.                 Vec3 renderPos = pEntity->GetPos();
  478.                 renderPos.z += 2.0f + (float)actor.requestQueue.size() * spacing;
  479.  
  480.                 for (MovementRequestQueue::const_iterator itQ = actor.requestQueue.begin(); itQ != actor.requestQueue.end(); ++itQ)
  481.                 {
  482.                         const MovementRequestID& requestID = *itQ;
  483.                         Requests::const_iterator itRequest = std::find_if(m_requests.begin(), m_requests.end(), RequestMatchesIdPredicate(requestID));
  484.  
  485.                         if (itRequest != m_requests.end())
  486.                         {
  487.                                 const MovementRequest& request = itRequest->second;
  488.                                 const char* requestTypeStr = MovementRequest::GetTypeAsDebugName(request.type);
  489.                                 IAIDebugRenderer* renderer = gEnv->pAISystem->GetAIDebugRenderer();
  490.                                 renderer->Draw3dLabelEx(renderPos, 2.0f, IsPlannerWorkingOnRequestID(actor, requestID) ? Col_LightBlue : Col_White, true, false, false, false, "type = %s, id = %i", requestTypeStr, requestID.id);
  491.                                 renderPos.z -= spacing;
  492.                         }
  493.                 }
  494.         }
  495. }
  496.  
  497. #endif // COMPILE_WITH_MOVEMENT_SYSTEM_DEBUG
  498.  
downloadMovementSystem.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