BVB Source Codes

CRYENGINE Show ActionController.cpp Source code

Return Download CRYENGINE: download ActionController.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. //
  4. ////////////////////////////////////////////////////////////////////////////
  5.  
  6. #include "StdAfx.h"
  7.  
  8. #include "ActionController.h"
  9. #include "ActionScope.h"
  10.  
  11. #include "AnimationDatabase.h"
  12.  
  13. #include <CryExtension/CryCreateClassInstance.h>
  14.  
  15. #include "MannequinUtils.h"
  16. #include "MannequinDebug.h"
  17.  
  18. const uint32 MAX_ALLOWED_QUEUE_SIZE = 10;
  19.  
  20. CActionController::TActionControllerList CActionController::s_actionControllers;
  21. CActionController::TActionList CActionController::s_actionList;
  22. CActionController::TActionList CActionController::s_tickedActions;
  23.  
  24. bool CActionController::s_registeredCVars = false;
  25. uint32 CActionController::s_blendChannelCRCs[MANN_NUMBER_BLEND_CHANNELS];
  26.  
  27. #if CRYMANNEQUIN_WARN_ABOUT_VALIDITY()
  28. int CActionController::s_mnFatalErrorOnInvalidCharInst = 0;
  29. int CActionController::s_mnFatalErrorOnInvalidEntity = 0;
  30. #endif
  31.  
  32. #ifndef _RELEASE
  33.  
  34. CActionController* CActionController::s_debugAC = NULL;
  35. ICVar* CActionController::s_cvarMnDebug = NULL;
  36. int CActionController::s_mnDebugFragments = 0;
  37.  
  38. void ChangeDebug(ICVar* pICVar)
  39. {
  40.         if (!pICVar)
  41.                 return;
  42.  
  43.         const char* pVal = pICVar->GetString();
  44.         CActionController::ChangeDebug(pVal);
  45. }
  46.  
  47. void DumpSequence(IConsoleCmdArgs* pArgs)
  48. {
  49.         const int argCount = pArgs->GetArgCount();
  50.         if (argCount >= 2)
  51.         {
  52.                 const char* pVal = pArgs->GetArg(1);
  53.                 if (pVal)
  54.                 {
  55.                         float dumpTime = (argCount >= 3) ? (float)atof(pArgs->GetArg(2)) : -1.0f;
  56.  
  57.                         CActionController::DumpSequence(pVal, dumpTime);
  58.                 }
  59.         }
  60. }
  61.  
  62. struct SACEntityNameAutoComplete : public IConsoleArgumentAutoComplete
  63. {
  64.         virtual int GetCount() const
  65.         {
  66.                 return CActionController::GetGlobalActionControllers().size();
  67.         };
  68.  
  69.         virtual const char* GetValue(int nIndex) const
  70.         {
  71.                 return CActionController::GetGlobalActionControllers()[nIndex]->GetSafeEntityName();
  72.         };
  73. };
  74.  
  75. static SACEntityNameAutoComplete s_ACEntityNameAutoComplete;
  76.  
  77. #endif //!_RELEASE
  78.  
  79. void CActionController::RegisterCVars()
  80. {
  81.         if (!s_registeredCVars)
  82.         {
  83.                 IConsole* pConsole = gEnv->pConsole;
  84.                 assert(pConsole);
  85.                 if (!pConsole)
  86.                         return;
  87.  
  88. #ifndef _RELEASE
  89.                 s_cvarMnDebug = REGISTER_STRING_CB("mn_debug", "", VF_CHEAT, "Entity to display debug information for action controller for", ::ChangeDebug);
  90.                 REGISTER_COMMAND("mn_dump", ::DumpSequence, VF_CHEAT, "Dumps specified entity's CryMannequin history in the path specified by mn_sequence_path");
  91.  
  92.                 if (gEnv->pConsole != NULL)
  93.                 {
  94.                         gEnv->pConsole->RegisterAutoComplete("mn_debug", &s_ACEntityNameAutoComplete);
  95.                         gEnv->pConsole->RegisterAutoComplete("mn_dump", &s_ACEntityNameAutoComplete);
  96.                 }
  97.                 REGISTER_CVAR3("mn_debugfragments", s_mnDebugFragments, 0, VF_CHEAT, "Log out fragment queues");
  98. #endif //!_RELEASE
  99.  
  100. #if CRYMANNEQUIN_WARN_ABOUT_VALIDITY()
  101.                 REGISTER_CVAR3("mn_fatalerroroninvalidentity", s_mnFatalErrorOnInvalidEntity, 1, VF_CHEAT, "Throw a fatal error when an invalid entity is detected");
  102.                 REGISTER_CVAR3("mn_fatalerroroninvalidcharinst", s_mnFatalErrorOnInvalidCharInst, 1, VF_CHEAT, "Throw a fatal error when an invalid character instance is detected");
  103. #endif //!CRYMANNEQUIN_WARN_ABOUT_VALIDITY()
  104.  
  105.                 char channelName[10];
  106.                 cry_strcpy(channelName, "channel0");
  107.                 for (uint32 i = 0; i < MANN_NUMBER_BLEND_CHANNELS; i++)
  108.                 {
  109.                         channelName[7] = '0' + i;
  110.                         s_blendChannelCRCs[i] = MannGenCRC(channelName);
  111.                 }
  112.  
  113.                 s_registeredCVars = true;
  114.         }
  115. }
  116.  
  117. void CActionController::UnregisterCVars()
  118. {
  119.         if (s_registeredCVars)
  120.         {
  121.                 IConsole* pConsole = gEnv->pConsole;
  122.                 if (pConsole)
  123.                 {
  124. #ifndef _RELEASE
  125.                         pConsole->UnRegisterAutoComplete("mn_debug");
  126.                         pConsole->UnRegisterAutoComplete("mn_dump");
  127.                         pConsole->UnregisterVariable("mn_debug");
  128.                         pConsole->RemoveCommand("mn_dump");
  129.                         pConsole->UnregisterVariable("mn_debugfragments");
  130. #endif //!_RELEASE
  131.  
  132. #if CRYMANNEQUIN_WARN_ABOUT_VALIDITY()
  133.                         pConsole->UnregisterVariable("mn_fatalerroroninvalidentity");
  134.                         pConsole->UnregisterVariable("mn_fatalerroroninvalidcharinst");
  135. #endif // !CRYMANNEQUIN_WARN_ABOUT_VALIDITY()
  136.  
  137.                         s_registeredCVars = false;
  138.                 }
  139.         }
  140. }
  141.  
  142. void CActionController::Register(CActionController* ac)
  143. {
  144.         RegisterCVars();
  145.  
  146.         s_actionControllers.push_back(ac);
  147.  
  148. #ifndef _RELEASE
  149.         ::ChangeDebug(s_cvarMnDebug);
  150. #endif //_RELEASE
  151. }
  152.  
  153. void CActionController::Unregister(CActionController* ac)
  154. {
  155.         TActionControllerList::iterator iter = std::find(s_actionControllers.begin(), s_actionControllers.end(), ac);
  156.         if (iter != s_actionControllers.end())
  157.         {
  158.                 s_actionControllers.erase(iter);
  159.  
  160.                 if (s_actionControllers.empty())
  161.                 {
  162.                         stl::free_container(s_actionControllers);
  163.                         stl::free_container(s_actionList);
  164.                         stl::free_container(s_tickedActions);
  165.                         UnregisterCVars();
  166.                 }
  167.         }
  168.  
  169. #ifndef _RELEASE
  170.         if (ac == s_debugAC)
  171.         {
  172.                 s_debugAC = NULL;
  173.         }
  174. #endif //_RELEASE
  175. }
  176.  
  177. void CActionController::OnShutdown()
  178. {
  179.         const uint32 numControllers = s_actionControllers.size();
  180.  
  181.         if (numControllers > 0)
  182.         {
  183.                 for (TActionControllerList::iterator iter = s_actionControllers.begin(); iter != s_actionControllers.end(); ++iter)
  184.                 {
  185.                         CActionController* pAC = *iter;
  186.                         CryLogAlways("ActionController not released - Owner Controller Def: %s", pAC->GetContext().controllerDef.m_filename.c_str());
  187.                 }
  188.                 CryFatalError("ActionControllers (%u) not released at shutdown", numControllers);
  189.         }
  190. }
  191.  
  192. IActionController* CActionController::FindActionController(const IEntity& entity)
  193. {
  194.         const EntityId id = entity.GetId();
  195.         for (TActionControllerList::iterator iter = s_actionControllers.begin(); iter != s_actionControllers.end(); ++iter)
  196.         {
  197.                 CActionController* pAC = *iter;
  198.                 if (pAC->GetEntityId() == id)
  199.                         return pAC;
  200.         }
  201.         return NULL;
  202. }
  203.  
  204. #ifndef _RELEASE
  205. void CActionController::ChangeDebug(const char* entName)
  206. {
  207.         CActionController* debugAC = NULL;
  208.         if (entName && entName[0])
  209.         {
  210.                 for (TActionControllerList::iterator iter = s_actionControllers.begin(); iter != s_actionControllers.end(); ++iter)
  211.                 {
  212.                         CActionController* ac = *iter;
  213.                         if (stricmp(ac->GetSafeEntityName(), entName) == 0)
  214.                         {
  215.                                 debugAC = ac;
  216.                                 break;
  217.                         }
  218.                 }
  219.         }
  220.  
  221.         if (debugAC != s_debugAC)
  222.         {
  223.                 if (s_debugAC)
  224.                 {
  225.                         s_debugAC->SetFlag(AC_DebugDraw, false);
  226.                 }
  227.                 if (debugAC)
  228.                 {
  229.                         debugAC->SetFlag(AC_DebugDraw, true);
  230.                 }
  231.                 s_debugAC = debugAC;
  232.         }
  233. }
  234.  
  235. void BuildFilename(stack_string& filename, const char* entityName)
  236. {
  237.         char dateTime[128];
  238.         time_t ltime;
  239.         time(&ltime);
  240.         tm* pTm = localtime(&ltime);
  241.         strftime(dateTime, 128, "_%d_%b_%Y_%H_%M_%S.xml", pTm);
  242.  
  243.         ICVar* pSequencePathCVar = gEnv->pConsole->GetCVar("mn_sequence_path");
  244.         if (pSequencePathCVar)
  245.         {
  246.                 filename.append(pSequencePathCVar->GetString());
  247.         }
  248.  
  249.         filename.append(entityName);
  250.         filename.append(dateTime);
  251. }
  252.  
  253. void CActionController::DumpSequence(const char* entName, float dumpTime)
  254. {
  255.         CActionController* debugAC = NULL;
  256.         for (TActionControllerList::iterator iter = s_actionControllers.begin(); iter != s_actionControllers.end(); ++iter)
  257.         {
  258.                 CActionController* ac = *iter;
  259.                 if (stricmp(ac->GetSafeEntityName(), entName) == 0)
  260.                 {
  261.                         debugAC = ac;
  262.                         break;
  263.                 }
  264.         }
  265.  
  266.         if (!debugAC)
  267.         {
  268.                 debugAC = s_debugAC;
  269.         }
  270.  
  271.         if (debugAC)
  272.         {
  273.                 stack_string filename;
  274.                 BuildFilename(filename, debugAC->GetSafeEntityName());
  275.                 debugAC->DumpHistory(filename.c_str(), dumpTime);
  276.         }
  277. }
  278. #endif //!_RELEASE
  279.  
  280. CActionController::CActionController(IEntity* pEntity, SAnimationContext& context)
  281.         : m_entityId(pEntity ? pEntity->GetId() : 0)
  282.         , m_cachedEntity(pEntity)
  283.         , m_context(context)
  284.         , m_scopeCount(context.controllerDef.m_scopeIDs.GetNum())
  285.         , m_scopeArray(static_cast<CActionScope*>(CryModuleMalloc(sizeof(CActionScope) * m_scopeCount)))
  286.         , m_activeScopes(ACTION_SCOPES_NONE)
  287.         , m_flags(0)
  288.         , m_timeScale(1.f)
  289.         , m_scopeFlushMask(ACTION_SCOPES_NONE)
  290. #ifndef _RELEASE
  291.         , m_historySlot(0)
  292. #endif //_RELEASE
  293.         , m_lastTagStateRecorded(TAG_STATE_EMPTY)
  294. {
  295.         const uint32 numScopeContexts = context.controllerDef.m_scopeContexts.GetNum();
  296.         m_scopeContexts = new SScopeContext[numScopeContexts];
  297.         for (uint32 i = 0; i < numScopeContexts; i++)
  298.         {
  299.                 m_scopeContexts[i].Reset(i);
  300.         }
  301.  
  302.         for (uint32 i = 0; i < m_scopeCount; i++)
  303.         {
  304.                 const SScopeDef& scopeDef = context.controllerDef.m_scopeDef[i];
  305.                 const SScopeContextDef& scopeContextDef = context.controllerDef.m_scopeContextDef[scopeDef.context];
  306.                 const TagState additionalTags = context.controllerDef.m_tags.GetUnion(scopeDef.additionalTags, scopeContextDef.additionalTags);
  307.                 new(m_scopeArray + i)CActionScope(context.controllerDef.m_scopeIDs.GetTagName(i), i, *this, context, m_scopeContexts[scopeDef.context], scopeDef.layer, scopeDef.numLayers, additionalTags);
  308.         }
  309.  
  310.         Register(this);
  311. }
  312.  
  313. CActionController::~CActionController()
  314. {
  315.         Unregister(this);
  316.  
  317.         if (!m_owningControllers.empty())
  318.         {
  319.                 const uint32 numOwningControllers = m_owningControllers.size();
  320.                 for (uint32 i = 0; i < numOwningControllers; i++)
  321.                 {
  322.                         m_owningControllers[i]->FlushSlaveController(*this);
  323.                 }
  324.                 m_owningControllers.clear();
  325.         }
  326.  
  327.         for (uint32 i = 0; i < m_scopeCount; i++)
  328.         {
  329.                 CActionScope& scope = m_scopeArray[i];
  330.                 if (scope.m_pAction && (&scope.m_pAction->GetRootScope() == &scope) && scope.m_pAction->IsStarted())
  331.                 {
  332.                         scope.m_pAction->Exit();
  333.                 }
  334.         }
  335.  
  336.         ReleaseScopes();
  337.         ReleaseScopeContexts();
  338.  
  339.         uint32 numProcContexts = m_procContexts.size();
  340.         for (uint32 i = 0; i < numProcContexts; i++)
  341.         {
  342.                 m_procContexts[i].pContext.reset();
  343.         }
  344. }
  345.  
  346. void CActionController::Release()
  347. {
  348.         delete this;
  349. }
  350.  
  351. bool CActionController::CanInstall(const IAction& action, TagID subContext, const ActionScopes& scopeMask, float timeStep, float& timeTillInstall) const
  352. {
  353.         timeTillInstall = 0.0f;
  354.  
  355.         //--- Ensure we test against all effected scopes
  356.         ActionScopes expandedScopeMask = ExpandOverlappingScopes(scopeMask);
  357.         expandedScopeMask &= m_activeScopes;
  358.  
  359.         //--- Calc frag tag state
  360.         SFragTagState fragTagState(m_context.state.GetMask(), action.GetFragTagState());
  361.         if (subContext != TAG_ID_INVALID)
  362.         {
  363.                 const SSubContext subContextDef = m_context.controllerDef.m_subContext[subContext];
  364.                 fragTagState.globalTags = m_context.controllerDef.m_tags.GetUnion(fragTagState.globalTags, subContextDef.additionalTags);
  365.         }
  366.  
  367.         ActionScopes scopeFlag = 1;
  368.         for (uint32 i=0; i<m_scopeCount; i++, scopeFlag <<= 1)
  369.         {
  370.                 if (scopeFlag & expandedScopeMask)
  371.                 {
  372.                         const CActionScope& scope = m_scopeArray[i];
  373.                         {
  374.                                 SScopeContext& scopeContext = m_scopeContexts[scope.GetContextID()];
  375.                                 CActionController* pSlaveAC = scopeContext.pEnslavedController;
  376.  
  377.                                 if (!pSlaveAC)
  378.                                 {
  379.                                         float timeRemaining;
  380.                                         SAnimBlend animBlend;
  381.                                         EPriorityComparison priorityComp = Higher;
  382.                                         const bool isRequeue = (&action == scope.m_pAction);
  383.                                         const IActionPtr pCompareAction = scope.m_pAction ? scope.m_pAction : scope.m_pExitingAction;
  384.                                         if (pCompareAction)
  385.                                         {
  386.                                                 if (isRequeue && (action.m_rootScope != &scope))
  387.                                                 {
  388.                                                         //--- If this is a requeued action, only use the primary scope to time transitions
  389.                                                         priorityComp = Higher;
  390.                                                 }
  391.                                                 else if (pCompareAction->m_rootScope != &scope)
  392.                                                 {
  393.                                                         //--- Only test the action on its root scope, as that is timing the action
  394.                                                         continue;
  395.                                                 }
  396.                                                 else
  397.                                                 {
  398.                                                         priorityComp = action.DoComparePriority(*pCompareAction);
  399.                                                 }
  400.  
  401.                                                 expandedScopeMask &= ~pCompareAction->GetInstalledScopeMask();
  402.                                         }
  403.  
  404.                                         if (!scope.CanInstall(priorityComp, action.GetFragmentID(), fragTagState, isRequeue, timeRemaining))
  405.                                         {
  406.                                                 return false;
  407.                                         }
  408.  
  409.                                         timeTillInstall = max(timeTillInstall, timeRemaining);
  410.                                 }
  411.                                 else
  412.                                 {
  413.                                         //--- Ensure that we time our transitions based on the target too
  414.                                         const uint32 fragCRC = m_context.controllerDef.m_fragmentIDs.GetTagCRC(action.GetFragmentID());
  415.                                         const FragmentID tgtFragID = pSlaveAC->GetContext().controllerDef.m_fragmentIDs.Find(fragCRC);
  416.                                         SFragTagState childFragTagState;
  417.                                         childFragTagState.globalTags = pSlaveAC->GetContext().state.GetMask();
  418.                                         childFragTagState.fragmentTags = action.GetFragTagState();
  419.                                         const ActionScopes childScopeMask = pSlaveAC->GetContext().controllerDef.GetScopeMask(tgtFragID, childFragTagState);
  420.                                         float tgtTimeTillInstall;
  421.                                         if (!pSlaveAC->CanInstall(action, TAG_ID_INVALID, childScopeMask, timeStep, tgtTimeTillInstall))
  422.                                         {
  423.                                                 return false;
  424.                                         }
  425.  
  426.                                         timeTillInstall = max(timeTillInstall, tgtTimeTillInstall);
  427.                                 }
  428.                         }
  429.                 }
  430.         }
  431.  
  432.         return (timeStep >= timeTillInstall);
  433. }
  434.  
  435. bool CActionController::CanInstall(const IAction& action, const ActionScopes& scopeMask, float timeStep, float& timeTillInstall) const
  436. {
  437.         return CanInstall(action, action.GetSubContext(), scopeMask, timeStep, timeTillInstall);
  438. }
  439.  
  440. bool CActionController::IsDifferent(const FragmentID fragID, const TagState& fragmentTags, const ActionScopes& scopeMask) const
  441. {
  442.         const uint32 numScopes = GetTotalScopes();
  443.         const ActionScopes mask = GetActiveScopeMask() & scopeMask;
  444.  
  445.         uint32 installedContexts = 0;
  446.         for (uint32 i = 0; i < numScopes; i++)
  447.         {
  448.                 if (BIT64(i) & mask)
  449.                 {
  450.                         const CActionScope& scope = m_scopeArray[i];
  451.                         if (scope.NeedsInstall(installedContexts))
  452.                         {
  453.                                 installedContexts |= scope.GetContextMask();
  454.                                 if (scope.IsDifferent(fragID, fragmentTags))
  455.                                 {
  456.                                         return true;
  457.                                 }
  458.                         }
  459.                 }
  460.         }
  461.  
  462.         return false;
  463. }
  464.  
  465. void CActionController::RequestInstall(const IAction& action, const ActionScopes& scopeMask)
  466. {
  467.         //--- Ensure we test against all effected scopes
  468.         ActionScopes expandedScopeMask = ExpandOverlappingScopes(scopeMask);
  469.         expandedScopeMask &= m_activeScopes;
  470.  
  471.         uint32 contextIDs = 0;
  472.         for (uint32 i = 0; i < m_scopeCount; i++)
  473.         {
  474.                 if (BIT64(i) & expandedScopeMask)
  475.                 {
  476.                         CActionScope& scope = m_scopeArray[i];
  477.                         if (scope.NeedsInstall(contextIDs))
  478.                         {
  479.                                 contextIDs |= scope.GetContextMask();
  480.                                 IAction* const pScopeAction = scope.m_pAction.get();
  481.                                 if (pScopeAction && (pScopeAction->m_rootScope == &scope))
  482.                                 {
  483.                                         EPriorityComparison priorityComp = action.DoComparePriority(*pScopeAction);
  484.                                         pScopeAction->OnRequestBlendOut(priorityComp);
  485.                                 }
  486.                         }
  487.                 }
  488.         }
  489. }
  490.  
  491. void CActionController::InsertEndingAction(IAction& action)
  492. {
  493.         stl::push_back_unique(m_endedActions, IActionPtr(&action));
  494. }
  495.  
  496. void CActionController::Install(IAction& action, float timeRemaining)
  497. {
  498.         const FragmentID fragmentID = action.GetFragmentID();
  499.         const bool isReinstall = (action.GetStatus() == IAction::Installed);
  500.         const TagID subContext = action.GetSubContext();
  501.         uint32 optionIdx = action.GetOptionIdx();
  502.  
  503.         if (optionIdx == OPTION_IDX_RANDOM)
  504.         {
  505.                 optionIdx = m_context.randGenerator.GenerateUint32();
  506.         }
  507.  
  508.         action.BeginInstalling();
  509.         if (!isReinstall)
  510.         {
  511.                 action.Install();
  512.         }
  513.  
  514.         //--- Setup scope mask
  515.         ActionScopes scopeMask = action.GetForcedScopeMask() | QueryScopeMask(action.GetFragmentID(), action.GetFragTagState(), action.GetSubContext());
  516.         ActionScopes filteredScope = scopeMask & m_activeScopes;
  517.         SFragTagState tagState = SFragTagState(m_context.state.GetMask(), action.GetFragTagState());
  518.  
  519.         ActionScopes overlappedScopes = ExpandOverlappingScopes(filteredScope);
  520.         m_scopeFlushMask |= overlappedScopes;
  521.  
  522.         RecordTagState();
  523.         Record(SMannHistoryItem(action.GetForcedScopeMask(), fragmentID, tagState.fragmentTags, optionIdx, true));
  524.  
  525.         if (subContext != TAG_ID_INVALID)
  526.         {
  527.                 const SSubContext subContextDef = m_context.controllerDef.m_subContext[subContext];
  528.                 tagState.globalTags = m_context.controllerDef.m_tags.GetUnion(tagState.globalTags, m_context.subStates[subContext].GetMask());
  529.                 tagState.globalTags = m_context.controllerDef.m_tags.GetUnion(tagState.globalTags, subContextDef.additionalTags);
  530.         }
  531.  
  532.         action.m_installedScopeMask = filteredScope;
  533.         m_scopeFlushMask &= ~filteredScope;
  534.  
  535.         //--- Now install action into scopes & animations on all other contexts
  536.         ActionScopes rootScope = SCOPE_ID_INVALID;
  537.         uint32 installedContexts = 0;
  538.         bool isOneShot = (fragmentID != FRAGMENT_ID_INVALID);
  539.         ActionScopes scopeFlag = 1;
  540.         for (uint32 i=0; i<m_scopeCount; i++, scopeFlag <<= 1)
  541.         {
  542.                 CActionScope& scope = m_scopeArray[i];
  543.                 IActionPtr pExitingAction = scope.m_pAction;
  544.                 bool exitCurrentAction = false;
  545.  
  546.                 if (scopeFlag & filteredScope)
  547.                 {
  548.                         bool higherPriority = true;
  549.                         if (pExitingAction)
  550.                         {
  551.                                 higherPriority = (action.DoComparePriority(*pExitingAction) == Higher);
  552.                         }
  553.  
  554.                         scope.Install(action); // do this before QueueFragment so QueueFragment can call OnAnimInstalled on the action
  555.  
  556.                         //--- Flush any previously existing exiting action, as this has already been overridden
  557.                         if (scope.m_pExitingAction)
  558.                         {
  559.                                 InsertEndingAction(*scope.m_pExitingAction);
  560.                                 scope.m_pExitingAction->m_flags &= ~IAction::TransitioningOut;
  561.                                 scope.m_pExitingAction = NULL;
  562.                         }
  563.  
  564.                         SScopeContext& scopeContext = m_scopeContexts[scope.GetContextID()];
  565.                         CActionController* pSlaveAC = scopeContext.pEnslavedController;
  566.  
  567.                         const bool rootContextInstallation = scope.NeedsInstall(installedContexts);
  568.                         const bool waitingOnRootScope = (rootScope == SCOPE_ID_INVALID);
  569.  
  570.                         if (pSlaveAC != NULL)
  571.                         {
  572.                                 //--- Ensure that our slave tags are up to date
  573.                                 SynchTagsToSlave(scopeContext, true);
  574.  
  575.                                 uint32 fragCRC = m_context.controllerDef.m_fragmentIDs.GetTagCRC(fragmentID);
  576.                                 FragmentID slaveFragID = pSlaveAC->GetContext().controllerDef.m_fragmentIDs.Find(fragCRC);
  577.  
  578.                                 if (slaveFragID != FRAGMENT_ID_INVALID)
  579.                                 {
  580.                                         IActionPtr pDummyAction = action.CreateSlaveAction(slaveFragID, tagState.fragmentTags, pSlaveAC->GetContext());
  581.                                         pDummyAction->m_mannequinParams = action.m_mannequinParams;
  582.                                         pDummyAction->Initialise(pSlaveAC->m_context);
  583.                                         pDummyAction->m_optionIdx = optionIdx;
  584.                                         pSlaveAC->Install(*pDummyAction, timeRemaining);
  585.  
  586.                                         if (pDummyAction->GetInstalledScopeMask() != ACTION_SCOPES_NONE)
  587.                                         {
  588.                                                 pSlaveAC->m_triggeredActions.push_back(std::make_pair(pDummyAction, false));
  589.                                                 action.m_slaveActions.push_back(pDummyAction);
  590.  
  591.                                                 pSlaveAC->ResolveActionStates();
  592.  
  593.                                                 //--- Copy the timing settings back from the target
  594.                                                 CActionScope* pTargetScope = (CActionScope*)&pDummyAction->GetRootScope();
  595.                                                 scope.ClearSequencers();
  596.                                                 scope.m_lastFragmentID = fragmentID;
  597.                                                 scope.m_fragmentDuration = pTargetScope->m_fragmentDuration;
  598.                                                 scope.m_transitionDuration = pTargetScope->m_transitionDuration;
  599.                                                 scope.m_transitionOutroDuration = pTargetScope->m_transitionOutroDuration;
  600.                                                 scope.m_fragmentTime = pTargetScope->m_fragmentTime;
  601.                                                 scope.m_sequenceFlags = pTargetScope->m_sequenceFlags;
  602.                                                 scope.QueueAnimFromSequence(0, 0, false);
  603.                                         }
  604.                                         else
  605.                                         {
  606.                                                 pDummyAction.reset();
  607.                                         }
  608.                                 }
  609.                         }
  610.                         else if (!isReinstall || scope.m_isOneShot || scope.IsDifferent(action.m_fragmentID, action.m_fragTags, action.m_subContext))
  611.                         {
  612.                                 if (scope.QueueFragment(fragmentID, tagState, optionIdx, timeRemaining, action.GetUserToken(), waitingOnRootScope, higherPriority, rootContextInstallation))
  613.                                 {
  614.                                         if (scope.HasOutroTransition() && pExitingAction)
  615.                                         {
  616.                                                 pExitingAction->TransitionOutStarted();
  617.                                         }
  618.                                 }
  619.                         }
  620.  
  621.                         if (waitingOnRootScope && scope.HasFragment())
  622.                         {
  623.                                 float rootStartTime = scope.GetFragmentStartTime();
  624.                                 timeRemaining = rootStartTime;
  625.                                 rootScope = i;
  626.  
  627.                                 isOneShot = scope.m_isOneShot;
  628.                         }
  629.  
  630.                         installedContexts |= scope.GetContextMask();
  631.  
  632.                         exitCurrentAction = (pExitingAction && (pExitingAction->m_rootScope == &scope));
  633.                 }
  634.                 else
  635.                 {
  636.                         exitCurrentAction = (pExitingAction && ((scopeFlag & overlappedScopes) != 0));
  637.                 }
  638.  
  639.                 if (exitCurrentAction && (pExitingAction != &action))
  640.                 {
  641.                         InsertEndingAction(*pExitingAction);
  642.                         pExitingAction->m_eStatus = IAction::Exiting;
  643.                 }
  644.         }
  645.  
  646.         if (isOneShot)
  647.         {
  648.                 action.m_flags |= IAction::FragmentIsOneShot;
  649.         }
  650.         else
  651.         {
  652.                 action.m_flags &= ~IAction::FragmentIsOneShot;
  653.         }
  654.  
  655.         if (rootScope == SCOPE_ID_INVALID)
  656.         {
  657.                 rootScope = GetLeastSignificantBit(filteredScope);
  658.         }
  659.         action.m_rootScope = &m_scopeArray[rootScope];
  660. }
  661.  
  662. bool CActionController::TryInstalling(IAction& action, float timePassed)
  663. {
  664.         const FragmentID fragmentID = action.GetFragmentID();
  665.  
  666.         const TagID subContext = action.GetSubContext();
  667.         ActionScopes scopeMask = action.GetForcedScopeMask() | QueryScopeMask(fragmentID, action.GetFragTagState(), subContext);
  668.         ActionScopes filteredScope = scopeMask & m_activeScopes;
  669.  
  670.         //--- Request Install
  671.         RequestInstall(action, filteredScope);
  672.  
  673.         //--- Can I install now?
  674.         float timeRemaining;
  675.         if (CanInstall(action, filteredScope, timePassed, timeRemaining))
  676.         {
  677.                 Install(action, timeRemaining);
  678.  
  679.                 return true;
  680.         }
  681.  
  682.         return false;
  683. }
  684.  
  685. bool CActionController::QueryDuration(IAction& action, float& fragmentDuration, float& transitionDuration) const
  686. {
  687.         const TagID subContext = action.GetSubContext();
  688.         ActionScopes scopeMask = action.GetForcedScopeMask() | QueryScopeMask(action.GetFragmentID(), action.GetFragTagState(), subContext);
  689.         scopeMask = scopeMask & m_activeScopes;
  690.         uint32 optionIdx = action.GetOptionIdx();
  691.         if (optionIdx == OPTION_IDX_RANDOM)
  692.         {
  693.                 optionIdx = m_context.randGenerator.GenerateUint32();
  694.                 action.SetOptionIdx(optionIdx);
  695.         }
  696.  
  697.         SFragTagState tagState = SFragTagState(m_context.state.GetMask(), action.GetFragTagState());
  698.         if (subContext != TAG_ID_INVALID)
  699.         {
  700.                 const SSubContext subContextDef = m_context.controllerDef.m_subContext[subContext];
  701.                 tagState.globalTags = m_context.controllerDef.m_tags.GetUnion(tagState.globalTags, m_context.subStates[subContext].GetMask());
  702.                 tagState.globalTags = m_context.controllerDef.m_tags.GetUnion(tagState.globalTags, subContextDef.additionalTags);
  703.         }
  704.         ActionScopes scopeFlag = 1;
  705.         for (uint32 i=0; i<m_scopeCount; i++, scopeFlag <<= 1)
  706.         {
  707.                 if (scopeFlag & scopeMask)
  708.                 {
  709.                         const CActionScope& scope = m_scopeArray[i];
  710.  
  711.                         bool higherPriority = true;
  712.                         if (scope.m_pAction)
  713.                         {
  714.                                 higherPriority = (action.DoComparePriority(*scope.m_pAction) == Higher);
  715.                         }
  716.  
  717.                         SBlendQuery query;
  718.                         scope.FillBlendQuery(query, action.GetFragmentID(), tagState, higherPriority, NULL);
  719.  
  720.                         const SScopeContext& scopeContext = m_scopeContexts[scope.GetContextID()];
  721.                         SFragmentData fragData;
  722.                         IAnimationSet* pAnimSet = scopeContext.pCharInst ? scopeContext.pCharInst->GetIAnimationSet() : NULL;
  723.                         // Normally, a scope context must have an animation database associated in order to be active, but enslavement may break this, so we check just in case
  724.                         bool hasFound = scopeContext.pDatabase && (scopeContext.pDatabase->Query(fragData, query, optionIdx, pAnimSet) & eSF_Fragment) != 0;
  725.  
  726.                         if (hasFound)
  727.                         {
  728.                                 fragmentDuration = transitionDuration = 0.0f;
  729.                                 for (uint32 p = 0; p < SFragmentData::PART_TOTAL; p++)
  730.                                 {
  731.                                         if (fragData.transitionType[p] == eCT_Normal)
  732.                                         {
  733.                                                 fragmentDuration += fragData.duration[p];
  734.                                         }
  735.                                         else
  736.                                         {
  737.                                                 transitionDuration += fragData.duration[p];
  738.                                         }
  739.                                 }
  740.  
  741.                                 return true;
  742.                         }
  743.                 }
  744.         }
  745.  
  746.         return false;
  747. }
  748.  
  749. void CActionController::ReleaseScopes()
  750. {
  751.         for (uint32 i = 0; i < m_scopeCount; i++)
  752.         {
  753.                 CActionScope& scope = m_scopeArray[i];
  754.                 if (scope.m_pAction && (&scope.m_pAction->GetRootScope() == &scope) && scope.m_pAction->IsStarted())
  755.                 {
  756.                         scope.m_pAction->Exit();
  757.                 }
  758.  
  759.                 if (scope.m_pExitingAction && (&scope.m_pExitingAction->GetRootScope() == &scope) && scope.m_pExitingAction->IsStarted())
  760.                 {
  761.                         scope.m_pExitingAction->Exit();
  762.                 }
  763.         }
  764.  
  765.         for (uint32 i = 0; i < m_scopeCount; ++i)
  766.         {
  767.                 CActionScope& scope = m_scopeArray[i];
  768.                 scope.Flush(FM_Normal);
  769.         }
  770.  
  771.         for (uint32 i = 0; i < m_scopeCount; ++i)
  772.         {
  773.                 CActionScope& scope = m_scopeArray[i];
  774.  
  775.                 IAction* const pScopeAction = scope.m_pAction.get();
  776.                 if (pScopeAction && pScopeAction->m_rootScope == &scope)
  777.                 {
  778.                         pScopeAction->m_eStatus = IAction::None;
  779.                         pScopeAction->m_flags &= ~IAction::Requeued;
  780.  
  781.                         pScopeAction->m_rootScope = NULL;
  782.                 }
  783.                 scope.m_pAction = NULL;
  784.  
  785.                 IAction* const pExitAction = scope.m_pExitingAction.get();
  786.                 if (pExitAction && pExitAction->m_rootScope == &scope)
  787.                 {
  788.                         pExitAction->m_eStatus = IAction::None;
  789.                         pExitAction->m_flags &= ~IAction::Requeued;
  790.  
  791.                         pExitAction->m_rootScope = NULL;
  792.                 }
  793.                 scope.m_pExitingAction = NULL;
  794.         }
  795.  
  796.         for (uint32 i = 0; i < m_queuedActions.size(); ++i)
  797.         {
  798.                 m_queuedActions[i]->m_eStatus = IAction::None;
  799.         }
  800.  
  801.         for (uint32 i = 0; i < m_scopeCount; ++i)
  802.         {
  803.                 m_scopeArray[i].~CActionScope();
  804.         }
  805.         CryModuleFree(m_scopeArray);
  806.  
  807.         m_queuedActions.clear();
  808.         m_activeScopes = 0;
  809. }
  810.  
  811. void CActionController::ReleaseScopeContexts()
  812. {
  813.         //--- Remove ourselves from any enslaved characters
  814.         const uint32 numContexts = m_context.controllerDef.m_scopeContexts.GetNum();
  815.         for (uint32 i = 0; i < numContexts; i++)
  816.         {
  817.                 SScopeContext& scopeContext = m_scopeContexts[i];
  818.                 if (scopeContext.pEnslavedController)
  819.                 {
  820.                         SynchTagsToSlave(scopeContext, false);
  821.                         scopeContext.pEnslavedController->UnregisterOwner(*this);
  822.                 }
  823.         }
  824.         delete[] m_scopeContexts;
  825.         m_scopeContexts = NULL;
  826. }
  827.  
  828. void CActionController::FlushScope(uint32 scopeID, ActionScopes scopeFlag, EFlushMethod flushMethod)
  829. {
  830.         CActionScope& scope = m_scopeArray[scopeID];
  831.  
  832.         if (scope.m_pAction && (&scope.m_pAction->GetRootScope() == &scope))
  833.         {
  834.                 EndActionsOnScope(scopeFlag, NULL, true, flushMethod);
  835.         }
  836.         scope.m_pAction = NULL;
  837.  
  838.         scope.Flush(flushMethod);
  839. }
  840.  
  841. void CActionController::SetScopeContext(uint32 scopeContextID, IEntity& entity, ICharacterInstance* pCharacter, const IAnimationDatabase* animDatabase)
  842. {
  843.         if (scopeContextID >= (uint32)m_context.controllerDef.m_scopeContexts.GetNum())
  844.         {
  845.                 CryFatalError("[SetScopeContext] Invalid scope context id %u used for %s", scopeContextID, m_cachedEntity->GetName());
  846.         }
  847.  
  848.         SScopeContext& scopeContext = m_scopeContexts[scopeContextID];
  849.  
  850.         if ((pCharacter != scopeContext.pCharInst) || (animDatabase != scopeContext.pDatabase))
  851.         {
  852.                 if (scopeContext.pEnslavedController)
  853.                 {
  854.                         SynchTagsToSlave(scopeContext, false);
  855.                         scopeContext.pEnslavedController->UnregisterOwner(*this);
  856.                 }
  857.  
  858.                 if (scopeContext.pCharInst)
  859.                 {
  860.                         scopeContext.pCharInst->SetPlaybackScale(1.f);
  861.                 }
  862.  
  863.                 // CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_INFO, "***SetScopeContext %2d on entity %s (id=%d; %p) to entity=%s (id=%8d; %p), char=%x", scopeContextID, GetSafeEntityName(), m_entityId, m_cachedEntity, entity.GetName(), entity.GetId(), &entity, pCharacter);
  864.  
  865.                 // Flush all scopes for the specified scopeContext
  866.                 ActionScopes scopesUsingContext = FlushScopesByScopeContext(scopeContextID);
  867.  
  868.                 // Fill context data
  869.                 scopeContext.pCharInst = pCharacter;
  870.                 scopeContext.pDatabase = (CAnimationDatabase*)animDatabase;
  871.                 scopeContext.entityId = entity.GetId();
  872.                 scopeContext.pCachedEntity = &entity;
  873.                 scopeContext.pEnslavedController = NULL;
  874.  
  875.                 if (pCharacter)
  876.                 {
  877.                         pCharacter->SetPlaybackScale(GetTimeScale());
  878.                 }
  879.  
  880.                 // If the new context is valid, activate its scopes
  881.                 bool scopeContextIsValid = UpdateScopeContextValidity(scopeContextID);
  882.                 CRY_ASSERT(scopeContextIsValid);
  883.                 if (scopeContextIsValid && animDatabase)
  884.                         m_activeScopes |= scopesUsingContext;
  885.                 else
  886.                         m_activeScopes &= ~scopesUsingContext;
  887.         }
  888. }
  889.  
  890. void CActionController::ClearScopeContext(uint32 scopeContextID, bool flushAnimations)
  891. {
  892.         if (scopeContextID >= (uint32)m_context.controllerDef.m_scopeContexts.GetNum())
  893.         {
  894.                 CryFatalError("[ClearScopeContext] Invalid scope context id %u used for %s", scopeContextID, m_cachedEntity->GetName());
  895.         }
  896.  
  897.         //-- Flush all scopes that use this scopecontext
  898.         ActionScopes scopesUsingContext = FlushScopesByScopeContext(scopeContextID, flushAnimations ? FM_Normal : FM_NormalLeaveAnimations);
  899.  
  900.         SScopeContext& scopeContext = m_scopeContexts[scopeContextID];
  901.  
  902.         if (scopeContext.pEnslavedController)
  903.         {
  904.                 SynchTagsToSlave(scopeContext, false);
  905.                 scopeContext.pEnslavedController->UnregisterOwner(*this);
  906.         }
  907.  
  908.         if (scopeContext.pCharInst)
  909.         {
  910.                 scopeContext.pCharInst->SetPlaybackScale(1.f);
  911.         }
  912.  
  913.         //--- Clear context data
  914.         scopeContext.pCharInst.reset();
  915.         scopeContext.pDatabase = NULL;
  916.         scopeContext.entityId = 0;
  917.         scopeContext.pCachedEntity = NULL;
  918.         scopeContext.pEnslavedController = NULL;
  919.  
  920.         //--- Disable scopes that use this context
  921.         m_activeScopes &= ~scopesUsingContext;
  922. }
  923.  
  924. IScope* CActionController::GetScope(uint32 scopeID)
  925. {
  926.         CRY_ASSERT_MESSAGE((scopeID < m_scopeCount), "Invalid scope id");
  927.  
  928.         if (scopeID < m_scopeCount)
  929.         {
  930.                 return &m_scopeArray[scopeID];
  931.         }
  932.  
  933.         return NULL;
  934. }
  935.  
  936. const IScope* CActionController::GetScope(uint32 scopeID) const
  937. {
  938.         CRY_ASSERT_MESSAGE((scopeID < m_scopeCount), "Invalid scope id");
  939.  
  940.         if (scopeID < m_scopeCount)
  941.         {
  942.                 return &m_scopeArray[scopeID];
  943.         }
  944.  
  945.         return NULL;
  946. }
  947.  
  948. #ifdef _DEBUG
  949. void CActionController::ValidateActions()
  950. {
  951.         for (uint32 i = 0, scopeFlag = 1; i < m_scopeCount; i++, scopeFlag <<= 1)
  952.         {
  953.                 CActionScope& scope = m_scopeArray[i];
  954.  
  955.                 if (scope.m_pAction)
  956.                 {
  957.                         CRY_ASSERT(scope.m_pAction->m_installedScopeMask & scopeFlag);
  958.                 }
  959.         }
  960. }
  961. #endif //_DEBUG
  962.  
  963. void CActionController::ResolveActionStates()
  964. {
  965.         m_scopeFlushMask &= m_activeScopes;
  966.         ActionScopes scopeFlag=1;
  967.         for (uint32 i=0; i<m_scopeCount; i++, scopeFlag <<= 1)
  968.         {
  969.                 if (scopeFlag & m_scopeFlushMask)
  970.                 {
  971.                         CActionScope& scope = m_scopeArray[i];
  972.                         scope.BlendOutFragments();
  973.                         scope.m_pAction.reset();
  974.                 }
  975.         }
  976.         m_scopeFlushMask = 0;
  977.  
  978.         //--- Now delete dead actions
  979.         for (uint32 i = 0; i < m_endedActions.size(); i++)
  980.         {
  981.                 IAction* action = m_endedActions[i];
  982.  
  983.                 if (action->IsTransitioningOut())
  984.                 {
  985.                         CActionScope* pActionScope = (CActionScope*)&action->GetRootScope();
  986.                         pActionScope->m_pExitingAction = action;
  987.                 }
  988.                 else
  989.                 {
  990.                         EndAction(*action);
  991.                 }
  992.         }
  993.         m_endedActions.clear();
  994.  
  995. #ifdef _DEBUG
  996.         ValidateActions();
  997. #endif //_DEBUG
  998.  
  999.         //--- Now install actions
  1000.         for (uint32 i = 0; i < m_triggeredActions.size(); i++)
  1001.         {
  1002.                 IAction* action = m_triggeredActions[i].first.get();
  1003.                 const bool isReinstall = m_triggeredActions[i].second;
  1004.  
  1005.                 for (TActionList::iterator iter = m_queuedActions.begin(); iter != m_queuedActions.end(); ++iter)
  1006.                 {
  1007.                         if (*iter == action)
  1008.                         {
  1009.                                 m_queuedActions.erase(iter);
  1010.                                 break;
  1011.                         }
  1012.                 }
  1013.  
  1014.                 if (action->GetStatus() == IAction::Installed)
  1015.                 {
  1016.                         CActionScope& rootScope = (CActionScope&) action->GetRootScope();
  1017.                         if (isReinstall)
  1018.                         {
  1019.                                 //--- Reinstallation? -> remove queue's additional reference and wipe flag
  1020.                                 action->m_flags &= ~(IAction::Requeued);
  1021.                         }
  1022.                         else if (!rootScope.HasOutroTransition())
  1023.                         {
  1024.                                 action->Enter();
  1025.                         }
  1026.                 }
  1027.  
  1028.                 action->EndInstalling();
  1029.         }
  1030.         m_triggeredActions.clear();
  1031. }
  1032.  
  1033. bool CActionController::ResolveActionInstallations(float timePassed)
  1034. {
  1035.         bool changed = false;
  1036.  
  1037.         ActionScopes scopeMaskAcc = 0;
  1038.  
  1039.         for (uint32 i = 0; i < m_scopeCount; i++)
  1040.         {
  1041.                 IAction* pScopeAction = m_scopeArray[i].GetPlayingAction();
  1042.                 if (pScopeAction && (pScopeAction->m_rootScope == &m_scopeArray[i]))
  1043.                 {
  1044.                         pScopeAction->OnResolveActionInstallations();
  1045.                 }
  1046.         }
  1047.  
  1048.         const uint32 numActions = m_queuedActions.size();
  1049.  
  1050.         s_actionList = m_queuedActions;
  1051.         for (uint32 i = 0; i < numActions; i++)
  1052.         {
  1053.                 IAction& action = *s_actionList[i];
  1054.  
  1055.                 ActionScopes scopeMask = action.GetForcedScopeMask() | QueryScopeMask(action.GetFragmentID(), action.GetFragTagState(), action.GetSubContext());
  1056.                 ActionScopes scopeMaskFiltered = scopeMask & m_activeScopes;
  1057.                 action.m_rootScope = scopeMaskFiltered ? &m_scopeArray[GetLeastSignificantBit(scopeMaskFiltered)] : nullptr;
  1058.                 const bool isRequeue = ((action.m_flags & IAction::Requeued) != 0);
  1059.  
  1060.                 if (!isRequeue && !stl::find(s_tickedActions, &action) && action.m_rootScope)
  1061.                 {
  1062.                         action.UpdatePending(timePassed);
  1063.                         s_tickedActions.push_back(&action);
  1064.                 }
  1065.  
  1066.                 IAction::EStatus status = action.GetStatus();
  1067.  
  1068.                 if ((status == IAction::Finished) || (action.m_flags & IAction::Stopping) || ((status != IAction::Installed) && isRequeue))
  1069.                 {
  1070.                         //--- Remove from queue & clear requeued flag
  1071.                         for (TActionList::iterator iter = m_queuedActions.begin(); iter != m_queuedActions.end(); ++iter)
  1072.                         {
  1073.                                 if (*iter == &action)
  1074.                                 {
  1075.                                         m_queuedActions.erase(iter);
  1076.                                         break;
  1077.                                 }
  1078.                         }
  1079.                         action.m_flags &= ~IAction::Requeued;
  1080.                 }
  1081.                 else
  1082.                 {
  1083.                         if (scopeMaskFiltered)
  1084.                         {
  1085.                                 const bool canTrigger = (scopeMaskAcc & scopeMaskFiltered) == 0;
  1086.                                 const bool isReinstall = (action.GetStatus() == IAction::Installed);
  1087.  
  1088.                                 scopeMaskAcc |= scopeMaskFiltered;
  1089.  
  1090.                                 if (canTrigger && TryInstalling(action, timePassed))
  1091.                                 {
  1092.                                         m_triggeredActions.push_back(std::make_pair(&action, isReinstall));
  1093.                                         changed = true;
  1094.                                 }
  1095.                         }
  1096.                 }
  1097.         }
  1098.         s_actionList.clear();
  1099.  
  1100.         ResolveActionStates();
  1101.  
  1102.         if (BlendOffActions(timePassed))
  1103.         {
  1104.                 changed = true;
  1105.         }
  1106.  
  1107.         return changed;
  1108. }
  1109.  
  1110. bool CActionController::BlendOffActions(float timePassed)
  1111. {
  1112.         bool hasEndedAction = false;
  1113.  
  1114.         //--- Check for any already finished actions and flush them here
  1115.         for (uint32 i = 0; i < m_scopeCount; i++)
  1116.         {
  1117.                 CActionScope& rootScope = m_scopeArray[i];
  1118.                 IActionPtr pExitingAction = rootScope.m_pAction;
  1119.  
  1120.                 if (pExitingAction
  1121.                     && (&pExitingAction->GetRootScope() == &rootScope)
  1122.                     && (rootScope.GetFragmentTime() > 0.0f)
  1123.                     && ((pExitingAction->m_flags & IAction::TransitionPending) == 0)) // No blend off if there is a fragment we are waiting to blend to already
  1124.                 {
  1125.                         float timeLeft = 0.0f;
  1126.                         EPriorityComparison priority = (pExitingAction->GetStatus() == IAction::Finished) ? Higher : Lower;
  1127.                         if (rootScope.CanInstall(priority, FRAGMENT_ID_INVALID, SFragTagState(), false, timeLeft) && (timePassed >= timeLeft))
  1128.                         {
  1129.                                 const ActionScopes installedScopes = pExitingAction->GetInstalledScopeMask() & m_activeScopes;
  1130.                                 ActionScopes scopeFlag = 1;
  1131.                                 for (uint32 s=0; s<m_scopeCount; s++, scopeFlag<<=1)
  1132.                                 {
  1133.                                         if ((scopeFlag & installedScopes) != 0)
  1134.                                         {
  1135.                                                 CActionScope& scope = m_scopeArray[s];
  1136.                                                 scope.QueueFragment(FRAGMENT_ID_INVALID, SFragTagState(m_context.state.GetMask()), OPTION_IDX_RANDOM, 0.0f, 0, priority == Higher);
  1137.                                                 scope.m_pAction = NULL;
  1138.                                         }
  1139.                                 }
  1140.  
  1141.                                 if (rootScope.HasOutroTransition())
  1142.                                 {
  1143.                                         rootScope.m_pExitingAction = pExitingAction;
  1144.                                         pExitingAction->TransitionOutStarted();
  1145.                                 }
  1146.                                 else
  1147.                                 {
  1148.                                         EndAction(*pExitingAction);
  1149.                                 }
  1150.  
  1151.                                 hasEndedAction = true;
  1152.                         }
  1153.                 }
  1154.         }
  1155.  
  1156. #ifdef _DEBUG
  1157.         ValidateActions();
  1158. #endif //_DEBUG
  1159.  
  1160.         return hasEndedAction;
  1161. }
  1162.  
  1163. void CActionController::PruneQueue()
  1164. {
  1165.         int numTooManyActions = m_queuedActions.size() - MAX_ALLOWED_QUEUE_SIZE;
  1166.  
  1167.         if (numTooManyActions > 0)
  1168.         {
  1169.                 // print the remaining action queue before shrinking it
  1170.                 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "--- Mannequin Error, attempting to queue too many actions on entity '%s' (queue size = %" PRISIZE_T ", but only up to %u allowed) ---", GetSafeEntityName(), m_queuedActions.size(), MAX_ALLOWED_QUEUE_SIZE);
  1171.                 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "    %" PRISIZE_T " actions in queue:", m_queuedActions.size());
  1172.                 for (size_t k = 0; k < m_queuedActions.size(); k++)
  1173.                 {
  1174.                         CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "    #%" PRISIZE_T ": %s", k, m_queuedActions[k]->GetName());
  1175.                 }
  1176.  
  1177.                 do
  1178.                 {
  1179.                         bool removedAction = false;
  1180.                         // Remove from the back of the list
  1181.                         for (int i = (int)m_queuedActions.size() - 1; i >= 0; --i)
  1182.                         {
  1183.                                 IActionPtr pOtherAction = m_queuedActions[i];
  1184.                                 const bool isInterruptable = ((pOtherAction->GetFlags() & IAction::Interruptable) != 0);
  1185.                                 if (!isInterruptable)
  1186.                                 {
  1187.                                         CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "Ditching other action '%s' (%p) (at queue index %d)", pOtherAction->GetName(), pOtherAction.get(), i);
  1188.                                         m_queuedActions.erase(m_queuedActions.begin() + i);
  1189.                                         pOtherAction->Fail(AF_QueueFull);
  1190.                                         numTooManyActions = m_queuedActions.size() - MAX_ALLOWED_QUEUE_SIZE;  // need to re-compute the overflow as IAction::Fail() might have just queued new actions
  1191.                                         removedAction = true;
  1192.                                         break;
  1193.                                 }
  1194.                         }
  1195.                         // Can't remove anything - so just bail out
  1196.                         if (removedAction == false)
  1197.                         {
  1198.                                 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "Can't remove anything");
  1199.                                 break;
  1200.                         }
  1201.                 }
  1202.                 while (numTooManyActions > 0);
  1203.                 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "---------------------");
  1204.         }
  1205. }
  1206.  
  1207. void CActionController::Update(float timePassed)
  1208. {
  1209.         if ((m_flags & AC_PausedUpdate) == 0)
  1210.         {
  1211.                 timePassed *= GetTimeScale();
  1212.  
  1213.                 SetFlag(AC_IsInUpdate, true);
  1214.                 UpdateValidity();
  1215.  
  1216.                 RecordTagState();
  1217.  
  1218.                 for (uint32 i = 0; i < m_scopeCount; i++)
  1219.                 {
  1220.                         CActionScope& scope = m_scopeArray[i];
  1221.                         IActionPtr pScopeAction = scope.GetPlayingAction();
  1222.                         if (pScopeAction && (pScopeAction->m_rootScope == &scope))
  1223.                         {
  1224.                                 //--- Insert user data into the parameter system
  1225.                                 ICharacterInstance* pInst = scope.GetCharInst();
  1226.                                 if (pInst)
  1227.                                 {
  1228.                                         for (uint32 ch = 0; ch < MANN_NUMBER_BLEND_CHANNELS; ch++)
  1229.                                         {
  1230.                                                 pScopeAction->SetParam(s_blendChannelCRCs[ch], pInst->GetISkeletonAnim()->GetUserData(ch));
  1231.                                         }
  1232.                                 }
  1233.  
  1234.                                 const float scaledDeltaTime = timePassed * pScopeAction->GetSpeedBias();
  1235.                                 pScopeAction->Update(scaledDeltaTime);
  1236.  
  1237.                                 //--- Reset the pending transition flag
  1238.                                 //--- If the transition still exists it'll be reset in the blend code
  1239.                                 pScopeAction->m_flags &= ~IAction::TransitionPending;
  1240.                         }
  1241.                 }
  1242.  
  1243.                 for (uint32 i = 0; i < m_scopeCount; i++)
  1244.                 {
  1245.                         CActionScope& scope = m_scopeArray[i];
  1246.                         IActionPtr pScopeAction = scope.GetPlayingAction();
  1247.                         if (pScopeAction && (pScopeAction->m_rootScope == &scope))
  1248.                         {
  1249.                                 // Detect early blend-out
  1250.                                 if (scope.m_isOneShot)
  1251.                                 {
  1252.                                         const float scaledDeltaTime = timePassed * pScopeAction->GetSpeedBias();
  1253.                                         const float timeToCompletion = scope.CalculateFragmentTimeRemaining() - scope.m_blendOutDuration;
  1254.                                         const bool reachedCompletionPoint = timeToCompletion >= 0.0f && timeToCompletion < scaledDeltaTime;
  1255.                                         if (reachedCompletionPoint)
  1256.                                         {
  1257.                                                 pScopeAction->OnActionFinished();
  1258.                                         }
  1259.                                 }
  1260.                         }
  1261.                 }
  1262.  
  1263.                 CRY_ASSERT(s_tickedActions.empty());
  1264.                 uint32 numIts;
  1265.                 const uint32 MAX_ITERATIONS = 5;
  1266.                 for (numIts = 0; numIts < MAX_ITERATIONS; numIts++)
  1267.                 {
  1268.                         if (!ResolveActionInstallations(timePassed))
  1269.                                 break;
  1270.                 }
  1271.                 s_tickedActions.clear();
  1272.  
  1273.                 if (numIts == MAX_ITERATIONS)
  1274.                 {
  1275.                         CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_ERROR, "Error, cannot resolve action changes in %u iterations for '%s'", MAX_ITERATIONS, GetSafeEntityName());
  1276.                 }
  1277.                 else if (numIts > 0)
  1278.                 {
  1279.                         //--- Something has changed, update state
  1280.                         mannequin::debug::WebDebugState(*this);
  1281.                 }
  1282.  
  1283.                 PruneQueue();
  1284.  
  1285.                 //--- Update scope sequencers
  1286.                 for (uint32 i = 0; i < m_scopeCount; i++)
  1287.                 {
  1288.                         if (BIT64(i) & m_activeScopes)
  1289.                         {
  1290.                                 CActionScope& scope = m_scopeArray[i];
  1291.                                 scope.Update(timePassed);
  1292.                         }
  1293.                 }
  1294.  
  1295.                 uint32 numProcContexts = m_procContexts.size();
  1296.                 for (uint32 i = 0; i < numProcContexts; i++)
  1297.                 {
  1298.                         m_procContexts[i].pContext->Update(timePassed);
  1299.                 }
  1300.                 SetFlag(AC_IsInUpdate, false);
  1301.         }
  1302.  
  1303. #ifndef _RELEASE
  1304.         if (m_flags & AC_DumpState)
  1305.         {
  1306.                 stack_string filename;
  1307.                 BuildFilename(filename, GetSafeEntityName());
  1308.                 DumpHistory(filename.c_str(), -1.0f);
  1309.  
  1310.                 m_flags &= ~AC_DumpState;
  1311.         }
  1312.  
  1313.         if (m_flags & AC_DebugDraw)
  1314.         {
  1315.                 DebugDraw();
  1316.         }
  1317. #endif //!_RELEASE
  1318. }
  1319.  
  1320. void CActionController::SetSlaveController(IActionController& target, uint32 targetContext, bool enslave, const IAnimationDatabase* piOptionTargetDatabase)
  1321. {
  1322.         const bool doFullEnslavement = !piOptionTargetDatabase;
  1323.  
  1324.         if (targetContext >= m_context.controllerDef.m_scopeContexts.GetNum())
  1325.         {
  1326.                 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "SetSlaveController: invalid scope context index!");
  1327.                 return;
  1328.         }
  1329.  
  1330.         UpdateValidity();
  1331.  
  1332.         CActionController& targetController = static_cast<CActionController&>(target);
  1333.         SScopeContext& scopeContext = m_scopeContexts[targetContext];
  1334.  
  1335.         if (enslave)
  1336.         {
  1337.                 targetController.UpdateValidity();
  1338.                 CRY_ASSERT(targetController.GetEntityId());
  1339.  
  1340.                 if (scopeContext.pEnslavedController)
  1341.                 {
  1342.                         SynchTagsToSlave(scopeContext, false);
  1343.                         scopeContext.pEnslavedController->UnregisterOwner(*this);
  1344.                         scopeContext.pEnslavedController = NULL;
  1345.                 }
  1346.  
  1347.                 if (targetController.GetEntityId())
  1348.                 {
  1349.                         IEntity& targetEnt = targetController.GetEntity();
  1350.  
  1351.                         if (doFullEnslavement)
  1352.                         {
  1353.                                 SetScopeContext(targetContext, targetEnt, NULL, NULL);
  1354.  
  1355.                                 targetController.RegisterOwner(*this);
  1356.  
  1357.                                 //--- Enable all associated scopes
  1358.                                 ActionScopes scopeFlag = 1;
  1359.                                 for (size_t i = 0; i < m_scopeCount; i++, scopeFlag <<= 1)
  1360.                                 {
  1361.                                         const CActionScope& scope = m_scopeArray[i];
  1362.                                         if (scope.GetContextID() == targetContext)
  1363.                                         {
  1364.                                                 m_activeScopes |= scopeFlag;
  1365.                                         }
  1366.                                 }
  1367.  
  1368.                                 scopeContext.pEnslavedController = &targetController;
  1369.  
  1370.                                 const SControllerDef& controllerDef = GetContext().controllerDef;
  1371.                                 const CTagDefinition& tagDef = controllerDef.m_tags;
  1372.                                 const CTagDefinition& tagDefSlave = targetController.GetContext().controllerDef.m_tags;
  1373.                                 const SScopeContextDef& scopeContextDef = controllerDef.m_scopeContextDef[targetContext];
  1374.                                 scopeContext.sharedTags = tagDef.GetIntersection(tagDef.GetSharedTags(tagDefSlave), scopeContextDef.sharedTags);
  1375.                                 scopeContext.sharedTags = tagDef.GetUnion(scopeContext.sharedTags, scopeContextDef.additionalTags);
  1376.                                 scopeContext.setTags = TAG_STATE_EMPTY;
  1377.  
  1378.                                 SynchTagsToSlave(scopeContext, true);
  1379.                         }
  1380.                         else
  1381.                         {
  1382.                                 //--- Hookup all the scopes
  1383.                                 const ActionScopes targetScopeMask = targetController.GetActiveScopeMask();
  1384.                                 const ActionScopes rootScope = GetLeastSignificantBit(targetScopeMask);
  1385.                                 CActionScope& targetScope = targetController.m_scopeArray[rootScope];
  1386.                                 CRY_ASSERT(piOptionTargetDatabase);
  1387.                                 SetScopeContext(targetContext, targetScope.GetEntity(), targetScope.GetCharInst(), piOptionTargetDatabase);
  1388.  
  1389.                                 const ActionScopes clearMask = targetController.m_activeScopes & ~BIT64(rootScope);
  1390.                                 ActionScopes scopeMask = 1;
  1391.                                 for (uint32 i=0; i<targetController.m_scopeCount; i++, scopeMask <<= 1)
  1392.                                 {
  1393.                                         if (scopeMask & clearMask)
  1394.                                         {
  1395.                                                 CActionScope& scope = targetController.m_scopeArray[i];
  1396.                                                 scope.BlendOutFragments();
  1397.                                                 scope.UpdateSequencers(0.0f);
  1398.                                         }
  1399.                                 }
  1400.                                 targetController.EndActionsOnScope(targetScopeMask, NULL);
  1401.                         }
  1402.                 }
  1403.         }
  1404.         else
  1405.         {
  1406.                 ClearScopeContext(targetContext);
  1407.         }
  1408.  
  1409.         if (!doFullEnslavement)
  1410.         {
  1411.                 targetController.SetFlag(AC_PausedUpdate, enslave);
  1412.         }
  1413. }
  1414.  
  1415. void CActionController::FlushSlaveController(IActionController& target)
  1416. {
  1417.         const uint32 numScopeContexts = m_context.controllerDef.m_scopeContexts.GetNum();
  1418.         for (uint32 i = 0; i < numScopeContexts; i++)
  1419.         {
  1420.                 SScopeContext& scopeContext = m_scopeContexts[i];
  1421.                 if (scopeContext.pEnslavedController == &target)
  1422.                 {
  1423.                         scopeContext.pCharInst.reset();
  1424.                         scopeContext.pDatabase = NULL;
  1425.                         scopeContext.entityId = 0;
  1426.                         scopeContext.pCachedEntity = NULL;
  1427.                         scopeContext.pEnslavedController = NULL;
  1428.  
  1429.                         //--- Disable scopes that use this context
  1430.                         ActionScopes scopeFlag = 1;
  1431.                         for (size_t s = 0; s < m_scopeCount; s++, scopeFlag <<= 1)
  1432.                         {
  1433.                                 CActionScope& scope = m_scopeArray[s];
  1434.                                 if (scope.GetContextID() == i)
  1435.                                 {
  1436.                                         m_activeScopes &= ~scopeFlag;
  1437.                                         if (scope.m_pAction)
  1438.                                         {
  1439.                                                 scope.m_pAction->m_installedScopeMask &= ~scopeFlag;
  1440.                                                 scope.m_pAction.reset();
  1441.                                         }
  1442.                                 }
  1443.                         }
  1444.                 }
  1445.         }
  1446. }
  1447.  
  1448. void CActionController::SynchTagsToSlave(SScopeContext& scopeContext, bool enable)
  1449. {
  1450.         CActionController* const pTargetController = scopeContext.pEnslavedController;
  1451.  
  1452.         if (pTargetController)
  1453.         {
  1454.                 const CTagDefinition& tagDefSlave = pTargetController->GetContext().controllerDef.m_tags;
  1455.                 CTagState& targetTagState = pTargetController->GetContext().state;
  1456.  
  1457.                 //--- Clear previous setting
  1458.                 for (uint32 i = 0; i < tagDefSlave.GetNum(); i++)
  1459.                 {
  1460.                         if (tagDefSlave.IsSet(scopeContext.setTags, i))
  1461.                         {
  1462.                                 targetTagState.Set(i, false);
  1463.                         }
  1464.                 }
  1465.  
  1466.                 scopeContext.setTags = TAG_STATE_EMPTY;
  1467.  
  1468.                 if (enable)
  1469.                 {
  1470.                         const CTagDefinition& tagDef = GetContext().controllerDef.m_tags;
  1471.                         TagState sourceTagState = GetContext().state.GetMask();
  1472.                         sourceTagState = tagDef.GetUnion(sourceTagState, GetContext().controllerDef.m_scopeContextDef[scopeContext.id].additionalTags);
  1473.  
  1474.                         for (uint32 i = 0; i < tagDef.GetNum(); i++)
  1475.                         {
  1476.                                 TagID groupID = tagDef.GetGroupID(i);
  1477.                                 const bool isKnown = ((groupID != TAG_ID_INVALID) && tagDef.IsGroupSet(scopeContext.sharedTags, groupID))
  1478.                                                      || tagDef.IsSet(scopeContext.sharedTags, i);
  1479.                                 if (isKnown && (tagDef.IsSet(sourceTagState, i)))
  1480.                                 {
  1481.                                         int tagCRC = tagDef.GetTagCRC(i);
  1482.                                         TagID tagID = tagDefSlave.Find(tagCRC);
  1483.                                         targetTagState.Set(tagID, true);
  1484.                                         tagDefSlave.Set(scopeContext.setTags, tagID, true);
  1485.                                 }
  1486.                         }
  1487.                 }
  1488.         }
  1489. }
  1490.  
  1491. void CActionController::Reset()
  1492. {
  1493.         Flush();
  1494.  
  1495.         const uint32 numScopeContexts = (uint32)m_context.controllerDef.m_scopeContexts.GetNum();
  1496.         for (uint32 itContext = 0; itContext < numScopeContexts; ++itContext)
  1497.         {
  1498.                 ClearScopeContext(itContext, false);
  1499.         }
  1500. }
  1501.  
  1502. void CActionController::Flush()
  1503. {
  1504.         if (m_flags & AC_IsInUpdate)
  1505.         {
  1506.                 CryFatalError("Flushing the action controller in the middle of an update, this is bad!");
  1507.         }
  1508.         UpdateValidity();
  1509.         ActionScopes scopeFlag = 1;
  1510.         for (uint32 i=0; i<m_scopeCount; i++, scopeFlag <<= 1)
  1511.         {
  1512.                 CActionScope& scope = m_scopeArray[i];
  1513.                 FlushScope(i, scopeFlag);
  1514.         }
  1515.  
  1516.         const uint32 numQueuedActions = m_queuedActions.size();
  1517.         for (uint32 i = 0; i < numQueuedActions; i++)
  1518.         {
  1519.                 IActionPtr pAction = m_queuedActions[i];
  1520.                 CRY_ASSERT(pAction != NULL);
  1521.  
  1522.                 if (pAction)
  1523.                 {
  1524.                         pAction->m_eStatus = IAction::None;
  1525.                 }
  1526.         }
  1527.         m_queuedActions.clear();
  1528.  
  1529.         FlushProceduralContexts();
  1530. }
  1531.  
  1532. void CActionController::FlushProceduralContexts()
  1533. {
  1534.         uint32 numProcContexts = m_procContexts.size();
  1535.         for (uint32 i = 0; i < numProcContexts; i++)
  1536.         {
  1537.                 m_procContexts[i].pContext.reset();
  1538.         }
  1539.         m_procContexts.clear();
  1540. }
  1541.  
  1542. void CActionController::RegisterListener(IMannequinListener* listener)
  1543. {
  1544.         m_listeners.push_back(listener);
  1545. }
  1546.  
  1547. void CActionController::UnregisterListener(IMannequinListener* listener)
  1548. {
  1549.         const uint32 numListeners = m_listeners.size();
  1550.         for (uint32 i = 0; i < numListeners; i++)
  1551.         {
  1552.                 if (m_listeners[i] == listener)
  1553.                 {
  1554.                         m_listeners.erase(m_listeners.begin() + i);
  1555.                         return;
  1556.                 }
  1557.         }
  1558.  
  1559.         CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "Attempting to remove an unknown listener!");
  1560. }
  1561.  
  1562. void CActionController::EndAction(IAction& action, EFlushMethod flushMethod)
  1563. {
  1564.         for (uint32 i = 0; i < m_scopeCount; i++)
  1565.         {
  1566.                 CRY_ASSERT(m_scopeArray[i].m_pAction != &action);
  1567.         }
  1568.  
  1569.         switch (flushMethod)
  1570.         {
  1571.         case FM_Normal:
  1572.         case FM_NormalLeaveAnimations:
  1573.                 if (action.Interrupt())
  1574.                 {
  1575.                         action.Initialise(m_context);
  1576.  
  1577.                         if (action.m_flags & IAction::Requeued)
  1578.                         {
  1579.                                 action.m_flags &= ~IAction::Requeued;
  1580.                         }
  1581.                         else
  1582.                         {
  1583.                                 PushOntoQueue(action);
  1584.                         }
  1585.                 }
  1586.                 else
  1587.                 {
  1588.                         if (action.m_flags & IAction::Requeued)
  1589.                         {
  1590.                                 for (TActionList::iterator iter = m_queuedActions.begin(); iter != m_queuedActions.end(); ++iter)
  1591.                                 {
  1592.                                         if (*iter == &action)
  1593.                                         {
  1594.                                                 m_queuedActions.erase(iter);
  1595.                                                 break;
  1596.                                         }
  1597.                                 }
  1598.                         }
  1599.                 }
  1600.                 break;
  1601.         case FM_Failure:
  1602.                 action.Fail(AF_InvalidContext);
  1603.                 break;
  1604.         default:
  1605.                 CRY_ASSERT(false);
  1606.         }
  1607. }
  1608.  
  1609. void CActionController::StartAction(IAction& action)
  1610. {
  1611.         action.Enter();
  1612. }
  1613.  
  1614. ActionScopes CActionController::ExpandOverlappingScopes(ActionScopes scopeMask) const
  1615. {
  1616.         ActionScopes expandedScopeMask = scopeMask;
  1617.         for (uint32 i = 0; i < m_scopeCount; i++)
  1618.         {
  1619.                 const CActionScope& scope = m_scopeArray[i];
  1620.                 const IAction* const pScopeAction = scope.m_pAction.get();
  1621.                 if (pScopeAction && (pScopeAction->m_eStatus != IAction::Exiting) && ((pScopeAction->GetInstalledScopeMask() & scopeMask) != 0))
  1622.                 {
  1623.                         expandedScopeMask |= pScopeAction->GetInstalledScopeMask();
  1624.                 }
  1625.         }
  1626.  
  1627.         return expandedScopeMask;
  1628. }
  1629.  
  1630. ActionScopes CActionController::EndActionsOnScope(ActionScopes scopeMask, IAction* pPendingAction, bool blendOut, EFlushMethod flushMethod)
  1631. {
  1632.         TActionList deleteActionList;
  1633.         //--- Expand the scope mask to all overlapped scopes
  1634.         ActionScopes expandedScopeMask = ExpandOverlappingScopes(scopeMask);
  1635.  
  1636.         //--- Clean up scopes
  1637.         ActionScopes scopeFlag = 1;
  1638.         for (uint32 i=0; i<m_scopeCount; i++, scopeFlag<<=1)
  1639.         {
  1640.                 CActionScope& scope = m_scopeArray[i];
  1641.                 if (scope.m_pAction && (scope.m_pAction->GetInstalledScopeMask() & expandedScopeMask))
  1642.                 {
  1643.                         if ((scope.m_pAction->m_rootScope == &scope) && (pPendingAction != scope.m_pAction))
  1644.                         {
  1645.                                 deleteActionList.push_back(scope.m_pAction);
  1646.                         }
  1647.  
  1648.                         scope.m_pAction = NULL;
  1649.  
  1650.                         if (blendOut && (scope.m_scopeContext.pDatabase != NULL))
  1651.                         {
  1652.                                 scope.BlendOutFragments();
  1653.                         }
  1654.                 }
  1655.         }
  1656.  
  1657.         //--- Clean up actions
  1658.         for (uint32 i = 0; i < deleteActionList.size(); i++)
  1659.         {
  1660.                 EndAction(*deleteActionList[i]);
  1661.         }
  1662.  
  1663.         return expandedScopeMask;
  1664. }
  1665.  
  1666. void CActionController::PushOntoQueue(IAction& action)
  1667. {
  1668.         const int priority = action.GetPriority();
  1669.         const bool requeued = ((action.GetFlags() & IAction::Requeued) != 0);
  1670.  
  1671.         for (TActionList::iterator iter = m_queuedActions.begin(); iter != m_queuedActions.end(); ++iter)
  1672.         {
  1673.                 const EPriorityComparison comparison = action.DoComparePriority(**iter);
  1674.  
  1675.                 bool insertHere = false;
  1676.                 if (comparison == Higher)
  1677.                 {
  1678.                         insertHere = true;
  1679.                 }
  1680.                 else if (comparison == Equal)
  1681.                 {
  1682.                         const bool otherRequeued = (((*iter)->GetFlags() & IAction::Requeued) != 0);
  1683.  
  1684.                         if (requeued && !otherRequeued)
  1685.                         {
  1686.                                 insertHere = true;
  1687.                         }
  1688.                 }
  1689.  
  1690.                 if (insertHere)
  1691.                 {
  1692.                         m_queuedActions.insert(iter, &action);
  1693.                         return;
  1694.                 }
  1695.         }
  1696.         m_queuedActions.push_back(&action);
  1697. }
  1698.  
  1699. ActionScopes CActionController::QueryScopeMask(FragmentID fragID, const TagState& fragTags, const TagID subContext) const
  1700. {
  1701.         ActionScopes scopeMask = 0;
  1702.  
  1703.         SFragTagState fragTagState(m_context.state.GetMask(), fragTags);
  1704.  
  1705.         if (fragID != FRAGMENT_ID_INVALID)
  1706.         {
  1707.                 scopeMask = m_context.controllerDef.GetScopeMask(fragID, fragTagState);
  1708.         }
  1709.  
  1710.         if (subContext != TAG_ID_INVALID)
  1711.         {
  1712.                 scopeMask |= m_context.controllerDef.m_subContext[subContext].scopeMask;
  1713.         }
  1714.  
  1715.         return scopeMask;
  1716. }
  1717.  
  1718. void CActionController::Queue(IAction& action, float time)
  1719. {
  1720.         action.m_queueTime = time;
  1721.         action.Initialise(m_context);
  1722.  
  1723.         PushOntoQueue(action);
  1724. }
  1725.  
  1726. void CActionController::Requeue(IAction& action)
  1727. {
  1728.         CRY_ASSERT(action.GetStatus() == IAction::Installed);
  1729.  
  1730.         PushOntoQueue(action);
  1731. }
  1732.  
  1733. void CActionController::OnEvent(const SGameObjectEvent& event)
  1734. {
  1735.         UpdateValidity();
  1736.  
  1737.         for (uint32 i = 0; i < m_scopeCount; i++)
  1738.         {
  1739.                 CActionScope& scope = m_scopeArray[i];
  1740.                 IAction* const pAction = scope.m_pAction.get();
  1741.                 if (pAction && (&pAction->GetRootScope() == &scope))
  1742.                 {
  1743.                         pAction->OnEvent(event);
  1744.                 }
  1745.         }
  1746. }
  1747.  
  1748. void CActionController::OnAnimationEvent(ICharacterInstance* pCharacter, const AnimEventInstance& event)
  1749. {
  1750.         UpdateValidity();
  1751.  
  1752.         for (uint32 i = 0; i < m_scopeCount; i++)
  1753.         {
  1754.                 CActionScope& scope = m_scopeArray[i];
  1755.                 IAction* const pAction = scope.m_pAction.get();
  1756.                 if (pAction && (&pAction->GetRootScope() == &scope) && (pAction->GetStatus() == IAction::Installed))
  1757.                 {
  1758.                         pAction->OnAnimationEvent(pCharacter, event);
  1759.                 }
  1760.         }
  1761. }
  1762.  
  1763. void CActionController::Record(const SMannHistoryItem& item)
  1764. {
  1765.         const uint32 numListeners = m_listeners.size();
  1766. #ifndef _RELEASE
  1767.         const float curTime = gEnv->pTimer->GetCurrTime();
  1768.  
  1769.         m_history[m_historySlot] = item;
  1770.         m_history[m_historySlot].time = curTime;
  1771.         m_historySlot = (m_historySlot + 1) % TOTAL_HISTORY_SLOTS;
  1772. #endif //_RELEASE
  1773.  
  1774.         for (uint32 i = 0; i < numListeners; i++)
  1775.         {
  1776.                 m_listeners[i]->OnEvent(item, *this);
  1777.         }
  1778. }
  1779.  
  1780. void CActionController::RecordTagState()
  1781. {
  1782.         const TagState newTagState = m_context.state.GetMask();
  1783.         if (m_lastTagStateRecorded != newTagState)
  1784.         {
  1785.                 SMannHistoryItem tagItem(newTagState);
  1786.                 Record(tagItem);
  1787.                 m_lastTagStateRecorded = newTagState;
  1788.         }
  1789. }
  1790.  
  1791. #ifndef _RELEASE
  1792.  
  1793. void CActionController::DumpHistory(const char* filename, float timeDelta) const
  1794. {
  1795.         XmlNodeRef root = GetISystem()->CreateXmlNode("History");
  1796.  
  1797.         float endTime = gEnv->pTimer->GetCurrTime();
  1798.         float startTime = (timeDelta > 0.0f) ? endTime - timeDelta : 0.0f;
  1799.         root->setAttr("StartTime", startTime);
  1800.         root->setAttr("EndTime", endTime);
  1801.  
  1802.         for (uint32 i = 0; i < TOTAL_HISTORY_SLOTS; i++)
  1803.         {
  1804.                 uint32 slotID = (i + m_historySlot + 1) % TOTAL_HISTORY_SLOTS;
  1805.                 const SMannHistoryItem& item = m_history[slotID];
  1806.  
  1807.                 if (item.time >= startTime)
  1808.                 {
  1809.                         //--- Save slot out
  1810.                         XmlNodeRef event = GetISystem()->CreateXmlNode("Item");
  1811.                         event->setAttr("Time", item.time);
  1812.                         switch (item.type)
  1813.                         {
  1814.                         case SMannHistoryItem::Fragment:
  1815.                                 {
  1816.                                         if (item.fragment != FRAGMENT_ID_INVALID)
  1817.                                         {
  1818.                                                 event->setAttr("FragmentID", m_context.controllerDef.m_fragmentIDs.GetTagName(item.fragment));
  1819.                                                 const CTagDefinition* tagDef = m_context.controllerDef.GetFragmentTagDef(item.fragment);
  1820.                                                 if ((item.tagState != TAG_STATE_EMPTY) && tagDef)
  1821.                                                 {
  1822.                                                         CryStackStringT<char, 512> sTagState;
  1823.                                                         tagDef->FlagsToTagList(item.tagState, sTagState);
  1824.                                                         event->setAttr("TagState", sTagState.c_str());
  1825.                                                 }
  1826.                                         }
  1827.                                         CryStackStringT<char, 512> sScopeMask;
  1828.                                         m_context.controllerDef.m_scopeIDs.IntegerFlagsToTagList(item.scopeMask, sScopeMask);
  1829.                                         event->setAttr("ScopeMask", sScopeMask.c_str());
  1830.                                         event->setAttr("OptionIdx", item.optionIdx);
  1831.                                         event->setAttr("Trump", item.trumpsPrevious);
  1832.                                         break;
  1833.                                 }
  1834.                         case SMannHistoryItem::Tag:
  1835.                                 {
  1836.                                         CryStackStringT<char, 512> sTagState;
  1837.                                         m_context.controllerDef.m_tags.FlagsToTagList(item.tagState, sTagState);
  1838.                                         event->setAttr("TagState", sTagState.c_str());
  1839.                                         break;
  1840.                                 }
  1841.                         case SMannHistoryItem::None:
  1842.                                 continue;
  1843.                                 break;
  1844.                         }
  1845.  
  1846.                         root->addChild(event);
  1847.                 }
  1848.         }
  1849.  
  1850.         const bool success = root->saveToFile(filename);
  1851.         if (!success)
  1852.         {
  1853.                 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "Error saving CryMannequin history to '%s'", filename);
  1854.         }
  1855. }
  1856.  
  1857. void CActionController::DebugDrawLocation(const QuatT& location, ColorB colorPos, ColorB colorX, ColorB colorY, ColorB colorZ) const
  1858. {
  1859.         IRenderAuxGeom* pAuxGeom = gEnv->pRenderer->GetIRenderAuxGeom();
  1860.  
  1861.         const float thickness = 7.0f;
  1862.         const Vec3 pushUp(0.0f, 0.03f, 0.0f);
  1863.  
  1864.         pAuxGeom->DrawLine(location.t + pushUp, colorX, location.t + pushUp + location.q.GetColumn0(), colorX, thickness);
  1865.         pAuxGeom->DrawLine(location.t + pushUp, colorY, location.t + pushUp + location.q.GetColumn1(), colorY, thickness);
  1866.         pAuxGeom->DrawLine(location.t + pushUp, colorZ, location.t + pushUp + location.q.GetColumn2(), colorZ, thickness);
  1867.  
  1868.         const float radius = 0.06f;
  1869.         pAuxGeom->DrawSphere(location.t + pushUp, radius, colorPos);
  1870. }
  1871.  
  1872. float g_mannequinYPosEnd = 0;
  1873.  
  1874. void CActionController::DebugDraw() const
  1875. {
  1876.         g_mannequinYPosEnd = 0;
  1877.  
  1878.         static float XPOS_SCOPELIST = 50.0f;
  1879.         static float XPOS_SCOPEACTIONLIST = 250.0f;
  1880.         static float XPOS_QUEUE = 900.0f;
  1881.         static float XINC_PER_LETTER = 6.0f;
  1882.         static float YPOS = 10.0f;
  1883.         static float XPOS_SEQUENCE = XPOS_SCOPELIST + 8.0f;
  1884.         static float YINC = 12.0f;
  1885.         static float YINC_SEQUENCE = 12.0f;
  1886.         static float YINC_SCOPES = 4.0f;
  1887.         static float FONT_SIZE = 1.3f;
  1888.         static float FONT_SIZE_ANIMLIST = 1.2f;
  1889.         static float FONT_COLOUR[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
  1890.         static float FONT_COLOUR_INACTIVE[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
  1891.         static float FONT_COLOUR_ANIM_PENDING[4] = { 1.0f, 1.0f, 0.5f, 1.0f };
  1892.         static float FONT_COLOUR_ANIM_INSTALLED[4] = { 0.5f, 1.0f, 0.5f, 1.0f };
  1893.         static float FONT_COLOUR_PROC_PENDING[4] = { 0.5f, 1.0f, 1.0f, 1.0f };
  1894.         static float FONT_COLOUR_PROC_INSTALLED[4] = { 0.5f, 0.5f, 1.0f, 1.0f };
  1895.         static float FONT_COLOUR_ACTION_QUEUE[4] = { 0.5f, 1.0f, 0.5f, 1.0f };
  1896.  
  1897.         float ypos = YPOS;
  1898.  
  1899.         const SControllerDef& controllerDef = m_context.controllerDef;
  1900.         if (m_flags & AC_PausedUpdate)
  1901.         {
  1902.                 IRenderAuxText::Draw2dLabel(XPOS_SCOPELIST, ypos, FONT_SIZE, FONT_COLOUR, false, "[PAUSED ACTION CONTROLLER]");
  1903.                 ypos += YINC;
  1904.         }
  1905.         CryStackStringT<char, 1024> sTagState;
  1906.         m_context.controllerDef.m_tags.FlagsToTagList(m_context.state.GetMask(), sTagState);
  1907.         IRenderAuxText::Draw2dLabel(XPOS_SCOPELIST, ypos, FONT_SIZE, FONT_COLOUR, false, "TagState: %s", sTagState.c_str());
  1908.         ypos += YINC;
  1909.  
  1910.         for (uint32 i = 0; i < m_context.subStates.size(); i++)
  1911.         {
  1912.                 CryStackStringT<char, 1024> sSubState;
  1913.                 m_context.controllerDef.m_tags.FlagsToTagList(m_context.subStates[i].GetMask(), sSubState);
  1914.                 IRenderAuxText::Draw2dLabel(XPOS_SCOPELIST, ypos, FONT_SIZE, FONT_COLOUR, false, "%s: %s", controllerDef.m_subContextIDs.GetTagName(i), sSubState.c_str());
  1915.                 ypos += YINC;
  1916.         }
  1917.         ypos += YINC;
  1918.  
  1919.         for (uint32 i = 0; i < m_scopeCount; i++)
  1920.         {
  1921.                 CryStackStringT<char, 1024> sMessage;
  1922.                 const CActionScope& scope = m_scopeArray[i];
  1923.  
  1924.                 FragmentID fragID = scope.GetLastFragmentID();
  1925.                 const char* fragName = (fragID != FRAGMENT_ID_INVALID) ? controllerDef.m_fragmentIDs.GetTagName(fragID) : "NoFragment";
  1926.                 if (scope.HasFragment())
  1927.                 {
  1928.                         controllerDef.m_tags.FlagsToTagList(scope.m_lastFragSelection.tagState.globalTags, sMessage);
  1929.  
  1930.                         const CTagDefinition* pFragTags = controllerDef.GetFragmentTagDef(fragID);
  1931.  
  1932.                         if (pFragTags && (scope.m_lastFragSelection.tagState.fragmentTags != TAG_STATE_EMPTY))
  1933.                         {
  1934.                                 CryStackStringT<char, 1024> sFragmentTags;
  1935.                                 pFragTags->FlagsToTagList(scope.m_lastFragSelection.tagState.fragmentTags, sFragmentTags);
  1936.                                 if (!sFragmentTags.empty())
  1937.                                 {
  1938.                                         CryStackStringT<char, 1024> sLastOptionIdx;
  1939.                                         sLastOptionIdx.Format("%u", scope.GetLastOptionIdx());
  1940.  
  1941.                                         if (scope.m_lastFragSelection.tagState.globalTags != TAG_STATE_EMPTY)
  1942.                                                 sMessage += "+";
  1943.                                         sMessage += "[" + sFragmentTags + "] option " + sLastOptionIdx;
  1944.                                 }
  1945.                         }
  1946.                 }
  1947.                 else
  1948.                 {
  1949.                         sMessage = "No Match: ";
  1950.  
  1951.                         if (scope.m_pAction)
  1952.                         {
  1953.                                 // scope tags (aka additional tags)
  1954.                                 CryStackStringT<char, 1024> sAdditionalTags;
  1955.                                 controllerDef.m_tags.FlagsToTagList(scope.m_additionalTags, sAdditionalTags);
  1956.                                 sMessage += sAdditionalTags;
  1957.  
  1958.                                 // scope context tags (aka additional tags)
  1959.                                 CryStackStringT<char, 1024> sScopeContext;
  1960.                                 controllerDef.m_tags.FlagsToTagList(controllerDef.m_scopeContextDef[scope.m_scopeContext.id].additionalTags, sScopeContext);
  1961.                                 sMessage += sScopeContext;
  1962.  
  1963.                                 // frag tags (aka fragment-specific tags)
  1964.                                 FragmentID fragIDNotMatched = scope.m_pAction->GetFragmentID();
  1965.                                 if (fragIDNotMatched != FRAGMENT_ID_INVALID)
  1966.                                 {
  1967.                                         const CTagDefinition* pFragTags = controllerDef.GetFragmentTagDef(fragIDNotMatched);
  1968.  
  1969.                                         if (pFragTags && scope.m_pAction->GetFragTagState() != TAG_STATE_EMPTY)
  1970.                                         {
  1971.                                                 CryStackStringT<char, 1024> sFragmentTags;
  1972.                                                 pFragTags->FlagsToTagList(scope.m_pAction->GetFragTagState(), sFragmentTags);
  1973.                                                 if (!sFragmentTags.empty())
  1974.                                                 {
  1975.                                                         CryStackStringT<char, 1024> sLastOptionIdx;
  1976.                                                         sLastOptionIdx.Format("%u", scope.GetLastOptionIdx());
  1977.                                                         if (scope.m_additionalTags != TAG_STATE_EMPTY)
  1978.                                                                 sMessage += "+";
  1979.                                                         sMessage += "[" + sFragmentTags + "] option " + sLastOptionIdx;
  1980.                                                 }
  1981.                                         }
  1982.                                 }
  1983.                         }
  1984.                         else
  1985.                         {
  1986.                                 sMessage = "No Action";
  1987.                         }
  1988.                 }
  1989.  
  1990.                 float *colour = (m_activeScopes & BIT64(1<<i)) ? FONT_COLOUR : FONT_COLOUR_INACTIVE;
  1991.                 IRenderAuxText::Draw2dLabel(XPOS_SCOPELIST, ypos, FONT_SIZE, colour, false, "%s:", scope.m_name.c_str());
  1992.  
  1993.                 CryStackStringT<char, 1024> sExitingAction;
  1994.                 if (scope.m_pExitingAction)
  1995.                         sExitingAction = scope.m_pExitingAction->GetName();
  1996.  
  1997.                 sExitingAction += scope.m_pAction ? scope.m_pAction->GetName() : " --- ";
  1998.                 if (scope.m_pAction)
  1999.                         IRenderAuxText::Draw2dLabel(XPOS_SCOPEACTIONLIST, ypos, FONT_SIZE, colour, false, "%s \t%s(%s)\tP: %d %d TR: %f", sExitingAction.c_str(), fragName, sMessage.c_str(), scope.m_pAction ? scope.m_pAction->GetPriority() : 0, scope.m_pAction ? scope.m_pAction->m_refCount : 0, scope.CalculateFragmentTimeRemaining());
  2000.                 else
  2001.                         IRenderAuxText::Draw2dLabel(XPOS_SCOPEACTIONLIST, ypos, FONT_SIZE, colour, false, "%s", sExitingAction.c_str());
  2002.                 ypos += YINC;
  2003.  
  2004.                 if (scope.m_scopeContext.pCharInst)
  2005.                 {
  2006.                         IAnimationSet* animSet = scope.m_scopeContext.pCharInst->GetIAnimationSet();
  2007.                         for (uint32 l = 0; l < scope.m_numLayers; l++)
  2008.                         {
  2009.                                 const CActionScope::SSequencer& sequencer = scope.m_layerSequencers[l];
  2010.  
  2011.                                 if (sequencer.sequence.size() > 0)
  2012.                                 {
  2013.                                         float xpos = XPOS_SEQUENCE;
  2014.                                         for (uint32 k = 0; k < sequencer.sequence.size(); k++)
  2015.                                         {
  2016.                                                 const char* animName = sequencer.sequence[k].animation.animRef.c_str();
  2017.                                                 int letterCount = animName ? strlen(animName) : 0;
  2018.                                                 float* colourA = FONT_COLOUR;
  2019.                                                 if (k == sequencer.pos)
  2020.                                                 {
  2021.                                                         colourA = FONT_COLOUR_ANIM_PENDING;
  2022.                                                 }
  2023.                                                 else if (k == sequencer.pos - 1)
  2024.                                                 {
  2025.                                                         colourA = FONT_COLOUR_ANIM_INSTALLED;
  2026.                                                 }
  2027.                                                 IRenderAuxText::Draw2dLabel(xpos, ypos, FONT_SIZE_ANIMLIST, colourA, false, "%s", animName);
  2028.                                                 xpos += XPOS_SCOPELIST + (letterCount * XINC_PER_LETTER);
  2029.                                         }
  2030.                                         ypos += YINC_SEQUENCE;
  2031.                                 }
  2032.                         }
  2033.                 }
  2034.  
  2035.                 const uint32 numProcLayers = scope.m_procSequencers.size();
  2036.                 for (uint32 l = 0; l < numProcLayers; l++)
  2037.                 {
  2038.                         const CActionScope::SProcSequencer& procSeq = scope.m_procSequencers[l];
  2039.  
  2040.                         if (procSeq.sequence.size() > 0)
  2041.                         {
  2042.                                 float xpos = XPOS_SEQUENCE;
  2043.                                 for (uint32 k = 0; k < procSeq.sequence.size(); k++)
  2044.                                 {
  2045.                                         const SProceduralEntry& procEntry = procSeq.sequence[k];
  2046.  
  2047.                                         const bool isNone = procEntry.IsNoneType();
  2048.                                         if (!isNone)
  2049.                                         {
  2050.                                                 const char* typeName = mannequin::FindProcClipTypeName(procEntry.typeNameHash);
  2051.                                                 int letterCount = typeName ? strlen(typeName) : 0;
  2052.                                                 float* colourA = FONT_COLOUR;
  2053.                                                 if (k == procSeq.pos)
  2054.                                                 {
  2055.                                                         colourA = FONT_COLOUR_PROC_PENDING;
  2056.                                                 }
  2057.                                                 else if (k == procSeq.pos - 1)
  2058.                                                 {
  2059.                                                         colourA = FONT_COLOUR_PROC_INSTALLED;
  2060.                                                 }
  2061.  
  2062.                                                 CryStackStringT<char, 1024> sTypename(typeName);
  2063.                                                 IProceduralParams::StringWrapper infoString;
  2064.                                                 if (procEntry.pProceduralParams)
  2065.                                                 {
  2066.                                                         procEntry.pProceduralParams->GetExtraDebugInfo(infoString);
  2067.                                                 }
  2068.                                                 if (!infoString.IsEmpty())
  2069.                                                         sTypename += "(" + CryStackStringT<char, 1024>(infoString.c_str()) + ")";
  2070.  
  2071.                                                 IRenderAuxText::Draw2dLabel(xpos, ypos, FONT_SIZE_ANIMLIST, colourA, false, "%s", sTypename.c_str());
  2072.                                                 xpos += XPOS_SCOPELIST + (letterCount * XINC_PER_LETTER);
  2073.                                         }
  2074.                                 }
  2075.                                 ypos += YINC_SEQUENCE;
  2076.                         }
  2077.                 }
  2078.  
  2079.                 ypos += YINC_SCOPES;
  2080.  
  2081.                 if (scope.m_pAction)
  2082.                 {
  2083.                         QuatT targetPos(IDENTITY);
  2084.  
  2085.                         const bool success = scope.m_pAction->GetParam("TargetPos", targetPos);
  2086.                         if (success)
  2087.                         {
  2088.                                 DebugDrawLocation(
  2089.                                   targetPos,
  2090.                                   RGBA8(0x80, 0x80, 0x80, 0xff),
  2091.                                   RGBA8(0xb0, 0x80, 0x80, 0xff),
  2092.                                   RGBA8(0x80, 0xb0, 0x80, 0xff),
  2093.                                   RGBA8(0x80, 0x80, 0xb0, 0xff));
  2094.                         }
  2095.                 }
  2096.         }
  2097.  
  2098.         g_mannequinYPosEnd = ypos;
  2099.  
  2100.         ypos = YPOS;
  2101.         IRenderAuxText::Draw2dLabel(XPOS_QUEUE, ypos, FONT_SIZE, FONT_COLOUR_ACTION_QUEUE, false, "Pending Action Queue");
  2102.         ypos += YINC * 2.0f;
  2103.         for (uint32 i = 0; i < m_queuedActions.size(); i++)
  2104.         {
  2105.                 CryStackStringT<char, 1024> sScopes;
  2106.                 const IAction& action = *m_queuedActions[i];
  2107.                 bool isPending = action.GetStatus() == IAction::Pending;
  2108.  
  2109.                 bool first = true;
  2110.                 for (uint32 k = 0; k < m_scopeCount; k++)
  2111.                 {
  2112.                         if (BIT64(k) & action.GetForcedScopeMask())
  2113.                         {
  2114.                                 if (first)
  2115.                                 {
  2116.                                         sScopes = m_scopeArray[k].m_name;
  2117.                                 }
  2118.                                 else
  2119.                                 {
  2120.                                         sScopes += "|" + m_scopeArray[k].m_name;
  2121.                                 }
  2122.  
  2123.                                 first = false;
  2124.                         }
  2125.                 }
  2126.                 FragmentID fragID = action.GetFragmentID();
  2127.                 const char* fragName = (fragID != FRAGMENT_ID_INVALID) ? m_context.controllerDef.m_fragmentIDs.GetTagName(fragID) : "NoFragment";
  2128.                 IRenderAuxText::Draw2dLabel(XPOS_QUEUE, ypos, FONT_SIZE, isPending ? FONT_COLOUR_ACTION_QUEUE : FONT_COLOUR, false, "%s: %s P: %d - %s", action.GetName(), fragName, action.GetPriority(), sScopes.c_str());
  2129.  
  2130.                 ypos += YINC;
  2131.         }
  2132.  
  2133.         {
  2134.                 QuatT targetPos(IDENTITY);
  2135.  
  2136.                 const bool success = m_mannequinParams.GetParam("TargetPos", targetPos);
  2137.                 if (success)
  2138.                 {
  2139.                         DebugDrawLocation(
  2140.                           targetPos,
  2141.                           RGBA8(0xa0, 0xa0, 0xa0, 0xff),
  2142.                           RGBA8(0xc0, 0xa0, 0xa0, 0xff),
  2143.                           RGBA8(0xa0, 0xc0, 0xa0, 0xff),
  2144.                           RGBA8(0xa0, 0xa0, 0xc0, 0xff));
  2145.                 }
  2146.         }
  2147.  
  2148.         if (m_cachedEntity)
  2149.         {
  2150.                 AABB bbox;
  2151.                 m_cachedEntity->GetWorldBounds(bbox);
  2152.                 const Vec3 entityWorldPos = m_cachedEntity->GetWorldPos();
  2153.                 const Vec3 debugPos = Vec3(entityWorldPos.x, entityWorldPos.y, bbox.max.z);
  2154.                 const float radius = 0.1f;
  2155.                 IRenderAuxGeom* pAuxGeom = gEnv->pRenderer->GetIRenderAuxGeom();
  2156.                 pAuxGeom->DrawSphere(debugPos, radius, RGBA8(0xff, 0x00, 0x00, 0xff));
  2157.         }
  2158. }
  2159.  
  2160. void CActionController::GetStateString(string& state) const
  2161. {
  2162.  
  2163.         state += "[ ";
  2164.         for (uint32 i = 0; i < m_scopeCount; i++)
  2165.         {
  2166.                 state += "{ ";
  2167.  
  2168.                 const CActionScope& scope = m_scopeArray[i];
  2169.                 state += "\"scope_id\" : \"";
  2170.                 state += m_context.controllerDef.m_scopeIDs.GetTagName(i);
  2171.                 state += "\", ";
  2172.  
  2173.                 state += "\"action\" : \"";
  2174.                 state += scope.GetAction() ? scope.GetAction()->GetName() : "None";
  2175.                 state += "\", ";
  2176.  
  2177.                 state += "\"fragment\" : \"";
  2178.                 state += (scope.GetLastFragmentID() != FRAGMENT_ID_INVALID) ? m_context.controllerDef.m_fragmentIDs.GetTagName(scope.GetLastFragmentID()) : "None";
  2179.                 state += "\"";
  2180.  
  2181.                 state += "} ";
  2182.  
  2183.                 if (i < (m_scopeCount - 1))
  2184.                 {
  2185.                         state += ", ";
  2186.                 }
  2187.         }
  2188.  
  2189.         state += "] ";
  2190.  
  2191. }
  2192.  
  2193. #endif //!_RELEASE
  2194.  
  2195. IProceduralContext* CActionController::FindOrCreateProceduralContext(const char* contextName)
  2196. {
  2197.         IProceduralContext* procContext = FindProceduralContext(contextName);
  2198.         if (procContext)
  2199.                 return procContext;
  2200.  
  2201.         return CreateProceduralContext(contextName);
  2202. }
  2203.  
  2204. IProceduralContext* CActionController::CreateProceduralContext(const char* contextName)
  2205. {
  2206.         const bool hasValidRootEntity = UpdateRootEntityValidity();
  2207.         if (!hasValidRootEntity)
  2208.                 return NULL;
  2209.  
  2210.         const uint32 contextNameCRC = CCrc32::ComputeLowercase(contextName);
  2211.  
  2212.         SProcContext newProcContext;
  2213.         newProcContext.nameCRC = contextNameCRC;
  2214.         CryCreateClassInstance<IProceduralContext>(contextName, newProcContext.pContext);
  2215.         m_procContexts.push_back(newProcContext);
  2216.  
  2217.         newProcContext.pContext->Initialise(*m_cachedEntity, *this);
  2218.         return newProcContext.pContext.get();
  2219. }
  2220.  
  2221. const IProceduralContext* CActionController::FindProceduralContext(const char* contextName) const
  2222. {
  2223.         const uint32 contextNameCRC = CCrc32::ComputeLowercase(contextName);
  2224.         return FindProceduralContext(contextNameCRC);
  2225. }
  2226.  
  2227. IProceduralContext* CActionController::FindProceduralContext(const char* contextName)
  2228. {
  2229.         const uint32 contextNameCRC = CCrc32::ComputeLowercase(contextName);
  2230.         return FindProceduralContext(contextNameCRC);
  2231. }
  2232.  
  2233. IProceduralContext* CActionController::FindProceduralContext(const uint32 contextNameCRC) const
  2234. {
  2235.         const uint32 numContexts = m_procContexts.size();
  2236.         for (uint32 i = 0; i < numContexts; i++)
  2237.         {
  2238.                 if (m_procContexts[i].nameCRC == contextNameCRC)
  2239.                 {
  2240.                         return m_procContexts[i].pContext.get();
  2241.                 }
  2242.         }
  2243.         return NULL;
  2244. }
  2245.  
  2246. bool CActionController::IsActionPending(uint32 userToken) const
  2247. {
  2248.         for (uint32 i = 0; i < m_queuedActions.size(); i++)
  2249.         {
  2250.                 const IAction& action = *m_queuedActions[i];
  2251.                 if ((action.GetStatus() == IAction::Pending) && (userToken == action.GetUserToken()))
  2252.                         return true;
  2253.         }
  2254.         return false;
  2255. }
  2256.  
  2257. void CActionController::Pause()
  2258. {
  2259.         if (!GetFlag(AC_PausedUpdate))
  2260.         {
  2261.                 SetFlag(AC_PausedUpdate, true);
  2262.                 for (size_t i = 0; i < m_scopeCount; ++i)
  2263.                 {
  2264.                         m_scopeArray[i].Pause();
  2265.                 }
  2266.         }
  2267. }
  2268.  
  2269. void CActionController::Resume(uint32 resumeFlags)
  2270. {
  2271.         if (GetFlag(AC_PausedUpdate))
  2272.         {
  2273.                 SetFlag(AC_PausedUpdate, false);
  2274.                 const bool restartAnimations = ((resumeFlags & ERF_RestartAnimations) != 0);
  2275.                 if (restartAnimations)
  2276.                 {
  2277.                         for (size_t i = 0; i < m_scopeCount; ++i)
  2278.                         {
  2279.                                 CActionScope& scope = m_scopeArray[i];
  2280.                                 const float blendTime = -1;
  2281.                                 scope.Resume(blendTime, resumeFlags);
  2282.                         }
  2283.                 }
  2284.         }
  2285. }
  2286.  
  2287. ActionScopes CActionController::FlushScopesByScopeContext(uint32 scopeContextID, EFlushMethod flushMethod)
  2288. {
  2289.         ActionScopes scopesUsingContext = 0;
  2290.         ActionScopes scopeFlag = 1;
  2291.         for (size_t i = 0; i < m_scopeCount; i++, scopeFlag <<= 1)
  2292.         {
  2293.                 CActionScope& scope = m_scopeArray[i];
  2294.                 if (scope.GetContextID() == scopeContextID)
  2295.                 {
  2296.                         FlushScope(i, scopeFlag, flushMethod);
  2297.  
  2298.                         scopesUsingContext |= scopeFlag;
  2299.                 }
  2300.         }
  2301.  
  2302.         return scopesUsingContext;
  2303. }
  2304.  
  2305. void CActionController::UpdateValidity()
  2306. {
  2307.         // Validate root entity
  2308.         const bool rootEntityIsValid = UpdateRootEntityValidity();
  2309.  
  2310.         // Validate all scopecontexts (and keep track of which ones are invalid)
  2311.         const uint32 numScopeContexts = m_context.controllerDef.m_scopeContexts.GetNum();
  2312.         uint32 scopeContextsToFlush = 0;
  2313.         for (uint32 scopeContextID = 0; scopeContextID < numScopeContexts; scopeContextID++)
  2314.         {
  2315.                 const bool scopeContextIsValid = UpdateScopeContextValidity(scopeContextID);
  2316.                 if (!rootEntityIsValid || !scopeContextIsValid)
  2317.                 {
  2318.                         scopeContextsToFlush |= BIT64(scopeContextID);
  2319.                 }
  2320.         }
  2321.  
  2322.         // Flush the invalid scopecontexts
  2323.         if (scopeContextsToFlush)
  2324.         {
  2325.                 for (uint32 scopeContextID = 0; scopeContextID < numScopeContexts; scopeContextID++)
  2326.                 {
  2327.                         if (scopeContextsToFlush & BIT64(scopeContextID))
  2328.                         {
  2329.                                 ActionScopes flushedScopes = FlushScopesByScopeContext(scopeContextID, FM_Failure);
  2330.                                 m_activeScopes &= ~flushedScopes;
  2331.                         }
  2332.                 }
  2333.         }
  2334. }
  2335.  
  2336. bool CActionController::UpdateScopeContextValidity(uint32 scopeContextID)
  2337. {
  2338.         SScopeContext& scopeContext = m_scopeContexts[scopeContextID];
  2339.  
  2340.         const bool hasInvalidEntity = scopeContext.HasInvalidEntity();
  2341.         if (hasInvalidEntity)
  2342.         {
  2343. #if CRYMANNEQUIN_WARN_ABOUT_VALIDITY()
  2344.                 IEntity* expectedEntity = gEnv->pEntitySystem->GetEntity(scopeContext.entityId);
  2345.                 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_ERROR, "[CActionController::UpdateScopeContextValidity] Dangling Entity %p (expected %p for id=%u) in context '%s'", (void*)scopeContext.pCachedEntity, (void*)expectedEntity, scopeContext.entityId, m_context.controllerDef.m_scopeContexts.GetTagName(scopeContextID));
  2346.                 CRY_ASSERT_MESSAGE(0,"[CActionController::UpdateScopeContextValidity] Dangling Entity");
  2347. #endif // !CRYMANNEQUIN_WARN_ABOUT_VALIDITY()
  2348.  
  2349.                 scopeContext.pCharInst = NULL;
  2350.                 scopeContext.entityId = 0;
  2351.                 scopeContext.pCachedEntity = NULL;
  2352.         }
  2353.  
  2354.         const bool hasInvalidCharInst = scopeContext.HasInvalidCharInst();
  2355.         if (hasInvalidCharInst)
  2356.         {
  2357. #if CRYMANNEQUIN_WARN_ABOUT_VALIDITY()
  2358.                 const char* entityName = (scopeContext.pCachedEntity ? scopeContext.pCachedEntity->GetName() : "<NULL>");
  2359.                 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_ERROR, "[CActionController::UpdateScopeContextValidity] Dangling Char Inst in entity '%s' (id=%d) in context '%s'", entityName, scopeContext.entityId, m_context.controllerDef.m_scopeContexts.GetTagName(scopeContextID));
  2360.                 CRY_ASSERT_MESSAGE(0,"[CActionController::UpdateScopeContextValidity] Dangling Char Inst in entity ");
  2361. #endif // !CRYMANNEQUIN_WARN_ABOUT_VALIDITY()
  2362.  
  2363.                 scopeContext.pCharInst = NULL;
  2364.         }
  2365.  
  2366.         return !(hasInvalidEntity || hasInvalidCharInst);
  2367. }
  2368.  
  2369. bool CActionController::UpdateRootEntityValidity()
  2370. {
  2371.         const IEntity* expectedEntity = gEnv->pEntitySystem->GetEntity(m_entityId);
  2372.         const bool hasValidRootEntity = (expectedEntity == m_cachedEntity);
  2373.         if (!hasValidRootEntity)
  2374.         {
  2375. #if CRYMANNEQUIN_WARN_ABOUT_VALIDITY()
  2376.                 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_ERROR, "[CActionController::UpdateRootEntityValidity] Dangling Entity %p (expected %p for id=%u) in actioncontroller for '%s'", (void*)m_cachedEntity, (void*)expectedEntity, m_entityId, m_context.controllerDef.m_filename.c_str());
  2377.                 CRY_ASSERT_MESSAGE(0,"[CActionController::UpdateRootEntityValidity] Dangling Entity");
  2378. #endif // !CRYMANNEQUIN_WARN_ABOUT_VALIDITY()
  2379.                 m_entityId = 0;
  2380.                 m_cachedEntity = NULL;
  2381.         }
  2382.  
  2383.         return hasValidRootEntity && (m_cachedEntity || m_entityId == 0);
  2384. }
  2385.  
  2386. QuatT CActionController::ExtractLocalAnimLocation(FragmentID fragID, TagState fragTags, uint32 scopeID, uint32 optionIdx)
  2387. {
  2388.         QuatT targetLocation(IDENTITY);
  2389.  
  2390.         if (IScope* pScope = GetScope(scopeID))
  2391.         {
  2392.                 IAction* pCurrentAction = pScope->GetAction();
  2393.                 ICharacterInstance* pCharInst = pScope->GetCharInst();
  2394.  
  2395.                 const IAnimationDatabase& animDatabase = pScope->GetDatabase();
  2396.                 const IAnimationSet* pAnimationSet = pCharInst ? pCharInst->GetIAnimationSet() : NULL;
  2397.  
  2398.                 if (pAnimationSet)
  2399.                 {
  2400.                         SFragmentData fragData;
  2401.                         SBlendQuery blendQuery;
  2402.  
  2403.                         blendQuery.fragmentFrom = pCurrentAction ? pCurrentAction->GetFragmentID() : FRAGMENT_ID_INVALID;
  2404.                         blendQuery.fragmentTo = fragID;
  2405.  
  2406.                         blendQuery.tagStateFrom.globalTags = blendQuery.tagStateTo.globalTags = GetContext().state.GetMask();
  2407.                         blendQuery.tagStateFrom.fragmentTags = pCurrentAction ? pCurrentAction->GetFragTagState() : TAG_STATE_EMPTY;
  2408.                         blendQuery.tagStateTo.fragmentTags = fragTags;
  2409.  
  2410.                         blendQuery.flags = SBlendQuery::fromInstalled | SBlendQuery::toInstalled;
  2411.  
  2412.                         animDatabase.Query(fragData, blendQuery, optionIdx, pAnimationSet);
  2413.  
  2414.                         if (!fragData.animLayers.empty() && !fragData.animLayers[0].empty())
  2415.                         {
  2416.                                 int animID = pAnimationSet->GetAnimIDByCRC(fragData.animLayers[0][0].animation.animRef.crc);
  2417.                                 if (animID >= 0)
  2418.                                 {
  2419.                                         pAnimationSet->GetAnimationDCCWorldSpaceLocation(animID, targetLocation);
  2420.                                 }
  2421.                         }
  2422.                 }
  2423.         }
  2424.  
  2425.         return targetLocation;
  2426. }
  2427.  
  2428. void CActionController::SetTimeScale(float timeScale)
  2429. {
  2430.         const uint32 numContexts = m_context.controllerDef.m_scopeContexts.GetNum();
  2431.         for (uint32 i = 0; i < numContexts; ++i)
  2432.         {
  2433.                 const SScopeContext& scopeContext = m_scopeContexts[i];
  2434.                 if (scopeContext.pCharInst)
  2435.                 {
  2436.                         scopeContext.pCharInst->SetPlaybackScale(timeScale);
  2437.                 }
  2438.         }
  2439.         m_timeScale = timeScale;
  2440. }
  2441.  
downloadActionController.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