text: /*
  * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
  * its licensors.
  *
  * For complete copyright and license terms please see the LICENSE at the root of this
  * distribution (the "License"). All use of this software is governed by the License,
  * or, if provided, by the license below or the license accompanying this file. Do not
  * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *
  */
  // Original file Copyright Crytek GMBH or its affiliates, used under license.
  
  #include "CryLegacy_precompiled.h"
  #include "AnimatedCharacter.h"
  #include "CryAction.h"
  #include "AnimationGraphCVars.h"
  #include "PersistentDebug.h"
  #include "IFacialAnimation.h"
  
  #include <CryExtension/CryCreateClassInstance.h>
  
  #include "CryActionCVars.h"
  #include "Mannequin/MannequinAGState.h"
  
  #include <IViewSystem.h>
  #include "Components/IComponentPhysics.h"
  
  
  
  const char* g_szMCMString[eMCM_COUNT] = { "Undefined", "Entity", "Animation", "DecoupledCatchUp", "ClampedEntity", "SmoothedEntity", "AnimationHCollision" };
  const char* g_szColliderModeString[eColliderMode_COUNT] = { "Undefined", "Disabled", "GroundedOnly", "Pushable", "NonPushable", "PushesPlayersOnly", "Spectator" };
  const char* g_szColliderModeLayerString[eColliderModeLayer_COUNT] = { "AG", "Game", "Script", "FG", "Anim", "Sleep", "Debug" };
  
  namespace PoseAlignerBones
  {
      static const char* Head = "Bip01 Head";
  
      namespace Left
      {
          static const char* Eye = "eye_left_bone";
      }
  
      namespace Right
      {
          static const char* Eye = "eye_right_bone";
      }
  }
  
  #define ANIMCHAR_MEM_DEBUG  // Memory Allocation Tracking
  #undef  ANIMCHAR_MEM_DEBUG
  
  #define ENABLE_NAN_CHECK
  
  #ifndef _RELEASE
      #define VALIDATE_CHARACTER_PTRS ValidateCharacterPtrs();
  #else //_RELEASE
      #define VALIDATE_CHARACTER_PTRS
  #endif //_RELEASE
  
  #undef CHECKQNAN_FLT
  #if defined(ENABLE_NAN_CHECK)
  #define CHECKQNAN_FLT(x) \
      assert(((*(unsigned*)&(x)) & 0xff000000) != 0xff000000u && (*(unsigned*)&(x) != 0x7fc00000))
  #else
  #define CHECKQNAN_FLT(x) (void*)0
  #endif
  
  #ifndef CHECKQNAN_VEC
  #define CHECKQNAN_VEC(v) \
      CHECKQNAN_FLT(v.x); CHECKQNAN_FLT(v.y); CHECKQNAN_FLT(v.z)
  #endif
  
  static CAnimationPlayerProxy s_defaultAnimPlayerProxy;
  static CTimeValue lastTime;
  
  namespace
  {
      struct SAnimRoot
      {
          f32 m_NormalizedTimeAbs;
          f32 m_KeyTimeAbs;
          QuatT m_TransRot;
  
          SAnimRoot()
          {
              m_NormalizedTimeAbs =   0;
              m_KeyTimeAbs    =   0;
              m_TransRot.SetIdentity();
          };
      } _ALIGN(8);
  
      bool CheckNAN(const f32& f)
      {
          return ((*(unsigned*)&(f)) & 0xff000000) != 0xff000000u && (*(unsigned*)&(f) != 0x7fc00000);
      }
  
      bool CheckNANVec(Vec3& v, IEntity* pEntity)
      {
          if (!CheckNAN(v.x) || !CheckNAN(v.y) || !CheckNAN(v.z))
          {
              if (ICharacterInstance* pCharacter = pEntity->GetCharacter(0))
              {
                  int numAnims = pCharacter->GetISkeletonAnim()->GetNumAnimsInFIFO(0);
                  for (int i = 0; i < numAnims; ++i)
                  {
                      const CAnimation& anim = pCharacter->GetISkeletonAnim()->GetAnimFromFIFO(0, i);
                      CryLogAlways("NAN on AnimationID:%d, model:%s, entity:%s", anim.GetAnimationId(), pCharacter->GetFilePath(), pEntity->GetName());
                  }
              }
  
              v.zero();
              return false;
          }
          return true;
      }
  
      bool CheckNANVec(const Vec3& v, IEntity* pEntity)
      {
          Vec3 v1(v);
          return CheckNANVec(v1, pEntity);
      }
  }
  
  namespace AC
  {
      void RegisterEvents(IGameObjectExtension& goExt, IGameObject& gameObject)
      {
          const int eventToRegister [] =
          {
              eGFE_QueueRagdollCreation,
              eGFE_BecomeLocalPlayer,
              eGFE_OnCollision,
              eGFE_ResetAnimationGraphs,
              eGFE_QueueBlendFromRagdoll,
              eGFE_EnablePhysics,
              eGFE_DisablePhysics
          };
          gameObject.UnRegisterExtForEvents(&goExt, NULL, 0);
          gameObject.RegisterExtForEvents(&goExt, eventToRegister, sizeof(eventToRegister) / sizeof(int));
      }
  }
  
  int CAnimatedCharacter::s_debugDrawCollisionEvents = 0;
  
  DECLARE_DEFAULT_COMPONENT_FACTORY(CAnimatedCharacter, CAnimatedCharacter)
  
  CAnimatedCharacter::CAnimatedCharacter()
      : m_listeners(1)
  {
      InitVars();
  
      m_debugHistoryManager = gEnv->pGame->GetIGameFramework()->CreateDebugHistoryManager();
  
      CryCreateClassInstance("PoseAlignerLimbIK", m_pPoseAligner);
  
      REGISTER_CVAR(s_debugDrawCollisionEvents, 0, VF_DEV_ONLY, "Draws debug information on animated character collision events.");
  }
  
  CAnimatedCharacter::~CAnimatedCharacter()
  {
      SAFE_RELEASE(m_pMannequinAGState);
  
      if (m_debugHistoryManager)
      {
          m_debugHistoryManager->Release();
      }
  
      DisableRigidCollider();
      DestroyExtraSolidCollider();
  
      CRY_ASSERT_MESSAGE(!m_pActionController, "ActionController should already be deleted. If not, the Exit of actions in the destructor could involve invalid objects.");
      DeleteActionController();
  }
  
  void CAnimatedCharacter::InitVars()
  {
      m_fPrevInertia = 0.0f;
      m_fPrevInertiaAccel = 0.0f;
      m_fPrevTimeImpulseRecover = 0.0f;
      m_facialAlertness = 0;
      m_currentStance = -1;
      m_requestedStance = -1;
      m_stanceQuery = 0;
      m_disallowLookIKFlags = 0;
      m_allowAimIk = true;
      m_curFrameID = -1;
      m_lastResetFrameId = -1;
      m_updateGrabbedInputFrameID = -1;
      m_moveRequestFrameID = -1;
      m_lastSerializeReadFrameID = 0;
      m_lastPostProcessUpdateFrameID = 0;
      m_lastAnimProcFrameID = 0;
      m_shadowCharacterSlot = -1;
      m_hasShadowCharacter = false;
      m_bSimpleMovementSetOnce = false;
      m_curWeaponRaisedPose = eWeaponRaisedPose_None;
      m_isPlayer = false;
      m_isClient = false;
      m_curFrameTime = 0.0f;
      m_prevFrameTime = 0.0f;
      m_curFrameTimeOriginal = 0.0f;
      m_reqLocalEntAxxNextIndex = 0;
      m_smoothedActualEntVelo = ZERO;
      m_smoothedAmountAxx = 0.0f;
      m_avgLocalEntAxx = ZERO;
      m_requestedEntMoveDirLH4 = 0;
      m_actualEntMoveDirLH4 = 0;
      m_colliderMode = eColliderMode_Undefined;
      m_simplifiedAGSpeedInputsRequested = false;
      m_simplifiedAGSpeedInputsActual = false;
      m_requestedEntityMovementType = RequestedEntMovementType_Undefined;
      m_requestedIJump = 0;
      m_bDisablePhysicalGravity = false;
      m_simplifyMovement = false;
      m_forceDisableSlidingContactEvents = false;
      m_noMovementTimer = 0.0f;
      m_actualEntSpeed = 0.0f;
      m_actualEntSpeedHorizontal = 0.0f;
      m_actualEntMovementDirHorizontal.zero();
      m_actualEntVelocityHorizontal.zero();
      m_actualEntAccelerationHorizontal.zero();
      m_actualEntTangentialAcceleration = 0.0f;
      m_actualEntMovement.SetIdentity();
      m_entLocation.SetIdentity();
      m_entTeleportMovement.SetIdentity();
      m_pAnimTarget = NULL;
      m_pCharacter = NULL;
      m_pSkeletonAnim = NULL;
      m_pSkeletonPose = NULL;
      m_pShadowCharacter = NULL;
      m_pShadowSkeletonAnim = NULL;
      m_pShadowSkeletonPose = NULL;
      m_wasInAir = false;
      m_fallMaxHeight = 0.0f;
      m_landBobTime = 0.0f;
      m_totalLandBob = 0.0f;
      m_noMovementOverrideExternal = false;
      m_bAnimationGraphStatePaused = true;
      m_fJumpSmooth = 1.0f;
      m_fJumpSmoothRate = 1.0f;
      m_fGroundSlopeMoveDirSmooth = 0.0f;
      m_fGroundSlopeMoveDirRate = 0.0f;
      m_fGroundSlope = 0.0f;
      m_fGroundSlopeSmooth = 0.0f;
      m_fGroundSlopeRate = 0.0f;
      m_fRootHeightSmooth = 0.0f;
      m_fRootHeightRate = 0.0f;
      m_forcedRefreshColliderMode = false;
      m_prevAnimPhaseHash = 0;
      m_prevAnimEntOffsetHash = 0.0f;
      m_prevMoveVeloHash = 0.0f;
      m_prevMoveJump = 0;
      m_collisionFrameID = -1;
      m_collisionNormalCount = 0;
  #if ENABLE_CRY_PHYSICS
      m_pFeetColliderPE = NULL;
  #endif
      m_debugHistoryManager = NULL;
  #if ENABLE_CRY_PHYSICS
      m_pRigidColliderPE = NULL;
      m_characterCollisionFlags = geom_colltype_player;
  #endif
      m_groundAlignmentParams.InitVars();
      m_doMotionParams = true;
      m_pAnimContext = NULL;
      m_pActionController = NULL;
      m_pAnimDatabase1P = NULL;
      m_pAnimDatabase3P = NULL;
      m_pSoundDatabase = NULL;
      m_bPendingRagdoll = false;
      m_pMannequinAGState = NULL;
      m_proxiesInitialized = false;
  
      for (int layer = 0; layer < eAnimationGraphLayer_COUNT; ++layer)
      {
          m_pAnimationPlayerProxies[layer] = &s_defaultAnimPlayerProxy;
      }
  
      for (int slot = 0; slot < eMCMSlot_COUNT; ++slot)
      {
          m_movementControlMethodTags[slot] = "InitVars";
          m_movementControlMethod[eMCMComponent_Horizontal][slot] = eMCM_Entity;
          m_movementControlMethod[eMCMComponent_Vertical][slot] = eMCM_Entity;
      }
      for (int slot = eMCMSlotStack_Begin; slot < eMCMSlotStack_End; ++slot)
      {
          m_movementControlMethod[eMCMComponent_Horizontal][slot] = eMCM_Undefined;
          m_movementControlMethod[eMCMComponent_Vertical][slot] = eMCM_Undefined;
      }
      m_currentMovementControlMethodTags[eMCMComponent_Horizontal] = m_movementControlMethodTags[eMCMSlot_Cur];
      m_currentMovementControlMethodTags[eMCMComponent_Vertical] = m_movementControlMethodTags[eMCMSlot_Cur];
      m_elapsedTimeMCM[eMCMComponent_Horizontal] = 0.0f;
      m_elapsedTimeMCM[eMCMComponent_Vertical] = 0.0f;
  
      for (int layer = 0; layer < eColliderModeLayer_COUNT; layer++)
      {
          m_colliderModeLayersTag[layer] = "InitVars";
          m_colliderModeLayers[layer] = eColliderMode_Undefined;
      }
  
      for (int i = 0; i < NumAxxSamples; i++)
      {
          m_reqLocalEntAxx[i].zero();
          m_reqEntVelo[i].zero();
          m_reqEntTime[i].SetValue(0);
      }
  
      m_fDesiredMoveSpeedSmoothQTX = 0;
      m_fDesiredMoveSpeedSmoothRateQTX = 0;
      m_fDesiredTurnSpeedSmoothQTX = 0;
      m_fDesiredTurnSpeedSmoothRateQTX = 0;
      m_fDesiredStrafeSmoothQTX = Vec2(0, 0);
      m_fDesiredStrafeSmoothRateQTX = Vec2(0, 0);
  
      m_collisionNormal[0].zero();
      m_collisionNormal[1].zero();
      m_collisionNormal[2].zero();
      m_collisionNormal[3].zero();
  
      m_lastAnimationUpdateFrameId = 0;
      m_inGrabbedState = false;
  
      m_hasForcedMovement = false;
      m_forcedMovementRelative.SetIdentity();
  
      m_hasForcedOverrideRotation = false;
      m_forcedOverrideRotationWorld.SetIdentity();
  
      m_useMannequinAGState = false;
  }
  
  bool CAnimatedCharacter::Init(IGameObject* pGameObject)
  {
      SetGameObject(pGameObject);
      LoadAnimationGraph(pGameObject);
      return true;
  }
  
  void CAnimatedCharacter::PostInit(IGameObject* pGameObject)
  {
      AC::RegisterEvents(*this, *pGameObject);
  
      m_pComponentPrepareCharForUpdate = gEnv->pEntitySystem->CreateComponentAndRegister<CAnimatedCharacterComponent_PrepareAnimatedCharacterForUpdate>(CAnimatedCharacterComponent_Base::SComponentInitializerAnimChar(GetEntity(), this));
      gEnv->pEntitySystem->CreateComponentAndRegister<CAnimatedCharacterComponent_GenerateMoveRequest>(CAnimatedCharacterComponent_Base::SComponentInitializerAnimChar(GetEntity(), this));
      gEnv->pEntitySystem->CreateComponentAndRegister<CAnimatedCharacterComponent_StartAnimProc>(CAnimatedCharacterComponent_Base::SComponentInitializerAnimChar(GetEntity(), this));
  
      m_proxiesInitialized = true;
  
      pGameObject->EnableUpdateSlot(this, 0);
      pGameObject->SetUpdateSlotEnableCondition(this, 0, eUEC_Visible);
      pGameObject->EnablePhysicsEvent(true, eEPE_OnCollisionLogged);
  }
  
  bool CAnimatedCharacter::ReloadExtension(IGameObject* pGameObject, const SEntitySpawnParams& params)
  {
      AC::RegisterEvents(*this, *pGameObject);
      ResetGameObject();
      ResetInertiaCache();
  
      SAFE_RELEASE(m_pMannequinAGState);
  
      for (int layer = 0; layer < eAnimationGraphLayer_COUNT; ++layer)
      {
          m_pAnimationPlayerProxies[layer] = &s_defaultAnimPlayerProxy;
      }
  
      // Load the new animation graph in
      LoadAnimationGraph(pGameObject);
  
      m_pComponentPrepareCharForUpdate->ClearQueuedRotation();
  
      return true;
  }
  
  bool CAnimatedCharacter::LoadAnimationGraph(IGameObject* pGameObject)
  {
      IEntity* pEntity = GetEntity();
      SmartScriptTable pScriptTable = pEntity ? pEntity->GetScriptTable() : NULL;
      if (!pScriptTable)
      {
          return false;
      }
  
      SmartScriptTable pPropertiesTable = NULL;
      pScriptTable->GetValue("Properties", pPropertiesTable);
  
      // If the script table doesn't have an "ActionController" property, try and use the "Properties" table as a fallback
      const SmartScriptTable pSourceTable = (pScriptTable->HaveValue("ActionController") || pScriptTable->HaveValue("fileActionController")) ? pScriptTable : pPropertiesTable;
      if (!pSourceTable)
      {
          return false;
      }
  
      DeleteActionController();
  
      const char* szActionController = 0;
  
      if ((pSourceTable->GetValue("ActionController", szActionController) || pSourceTable->GetValue("fileActionController", szActionController)) && szActionController && szActionController[0])
      {
          SetActionController(szActionController);
  
          if (m_pActionController)
          {
              IMannequin& mannequinSys = gEnv->pGame->GetIGameFramework()->GetMannequinInterface();
              const char* szAnimDatabase = 0;
              const char* szSoundDatabase = 0;
              if ((pSourceTable->GetValue("AnimDatabase3P", szAnimDatabase) || pSourceTable->GetValue("fileAnimDatabase3P", szAnimDatabase)) && szAnimDatabase)
              {
                  m_pAnimDatabase3P = mannequinSys.GetAnimationDatabaseManager().Load(szAnimDatabase);
              }
              szAnimDatabase = 0;
              if ((pSourceTable->GetValue("AnimDatabase1P", szAnimDatabase) || pSourceTable->GetValue("fileAnimDatabase1P", szAnimDatabase))  && szAnimDatabase)
              {
                  m_pAnimDatabase1P = mannequinSys.GetAnimationDatabaseManager().Load(szAnimDatabase);
              }
              if ((pSourceTable->GetValue("SoundDatabase", szSoundDatabase) || pSourceTable->GetValue("fileSoundDatabase", szAnimDatabase))  && szSoundDatabase)
              {
                  m_pSoundDatabase = mannequinSys.GetAnimationDatabaseManager().Load(szSoundDatabase);
              }
          }
      }
  
      m_useMannequinAGState = false;
      pScriptTable->GetValue("UseMannequinAGState", m_useMannequinAGState);
  
      if (m_useMannequinAGState)
      {
          CRY_ASSERT(m_pActionController);
  
          m_pMannequinAGState = new MannequinAG::CMannequinAGState();
          m_pMannequinAGState->SetAnimatedCharacter(this, 0, NULL);
          m_pMannequinAGState->AddListener("animchar", this);
      }
  
      // Reset all internal variables to prepare for this new graph
      ResetVars();
  
      return true;
  }
  
  bool CAnimatedCharacter::GetEntityPoolSignature(TSerialize signature)
  {
      signature.BeginGroup("AnimatedCharacter");
      signature.EndGroup();
      return true;
  }
  
  void CAnimatedCharacter::FullSerialize(TSerialize ser)
  {
  #define SerializeMember(member)     ser.Value(#member, member)
  #define SerializeMemberType(type, member)       { type temp = member; ser.Value(#member, temp); if (isReading) {member = temp; } \
  }
  #define SerializeNamedType(type, name, type2, var)      { type temp = var; ser.Value(name, temp); if (isReading) {var = (type2)temp; } \
  }
  
      bool isReading = ser.IsReading();
  
      if (isReading)
      {
          m_lastSerializeReadFrameID = m_curFrameID;
      }                                              /*gEnv->pRenderer->GetFrameID()*/
      ;
  
      // TODO: Find out what defines an inactive character and what can be safely omitted in that case.
      // Is it safe to ignore inactive entities? Don't they have any active information?
      bool bEntityActive = true; //GetEntity()->IsActive();
      if (!ser.BeginOptionalGroup("AnimatedCharacter", bEntityActive))
      {
          return;
      }
  
      if (isReading)
      {
          ResetVars();
      }
  
      SerializeMember(m_shadowCharacterSlot);
      SerializeMember(m_hasShadowCharacter);
  
      SerializeMember(m_prevEntLocation.t);
      SerializeMember(m_prevEntLocation.q);
  
      SerializeMember(m_actualEntMovement.t);
      SerializeMember(m_actualEntMovement.q);
  
      SerializeMember(m_actualEntSpeed);
      SerializeMember(m_actualEntSpeedHorizontal);
      if (isReading)
      {
          m_actualEntMovementDirHorizontal = Vec2(m_actualEntMovement.t).GetNormalizedSafe(Vec2_Zero);
          m_actualEntVelocityHorizontal = m_actualEntMovementDirHorizontal * m_actualEntSpeedHorizontal;
      }
      SerializeMember(m_actualEntAccelerationHorizontal);
  
      SerializeMember(m_requestedEntityMovement.t);
      SerializeMember(m_requestedEntityMovement.q);
  
      if (m_pMannequinAGState)
      {
          m_pMannequinAGState->Serialize(ser);
      }
  
      if (isReading)
      {
          ResetInertiaCache();
      }
  
      SerializeMember(m_currentStance);
  
      SerializeMember(m_disallowLookIKFlags);
      SerializeMemberType(bool, m_allowAimIk);
  
      RefreshAnimTarget();
      bool bTemp = m_groundAlignmentParams.IsFlag(eGA_Enable);
      ser.Value("m_enableGroundAlignment", bTemp);
      m_groundAlignmentParams.SetFlag(eGA_Enable, bTemp);
  
      string cml("m_colliderModeLayer");
      for (int layer = 0; layer < eColliderModeLayer_COUNT; layer++)
      {
          uint32 tempVal = m_colliderModeLayers[layer];
          ser.Value(cml + g_szColliderModeLayerString[layer], tempVal);
          m_colliderModeLayers[layer] = EColliderMode(tempVal);
      }
  
      char mcm[32] = "m_movementControlMethod";
      static const int basicStringLength = 23;
      assert(strlen(mcm) == basicStringLength);
      for (int slot = 0; slot < eMCMSlot_COUNT; ++slot)
      {
          mcm[basicStringLength] = 'H';
          azitoa(slot, &mcm[basicStringLength + 1], AZ_ARRAY_SIZE(mcm) - basicStringLength, 10);
          SerializeNamedType(uint8, mcm, EMovementControlMethod, m_movementControlMethod[eMCMComponent_Horizontal][slot]);
  
          mcm[basicStringLength] = 'V';
          azitoa(slot, &mcm[basicStringLength + 1], AZ_ARRAY_SIZE(mcm) - basicStringLength, 10);
          SerializeNamedType(uint8, mcm, EMovementControlMethod, m_movementControlMethod[eMCMComponent_Vertical][slot]);
      }
      ser.Value("m_elapsedTimeMCM_Horizontal", m_elapsedTimeMCM[eMCMComponent_Horizontal]);
      ser.Value("m_elapsedTimeMCM_Vertical", m_elapsedTimeMCM[eMCMComponent_Vertical]);
  
      ser.EndGroup(); //AnimatedCharacter
  }
  
  void CAnimatedCharacter::PostSerialize()
  {
      if (m_hasShadowCharacter)
      {
          InitShadowCharacter();
      }
  }
  
  void CAnimatedCharacter::Update(SEntityUpdateContext& ctx, int slot)
  {
      FUNCTION_PROFILER(GetISystem(), PROFILE_ACTION);
  
      //assert(!m_simplifyMovement); // If we have simplified movement, the this GameObject extension should not be updated here.
  
      assert(m_entLocation.IsValid());
      //assert(m_colliderModeLayers[eColliderModeLayer_ForceSleep] == eColliderMode_Undefined);
  
      if (m_simplifyMovement)
      {
          GetCurrentEntityLocation();
      }
  
      float EntRotZ = RAD2DEG(m_entLocation.q.GetRotZ());
  
      assert(m_entLocation.IsValid());
  
      SetAnimationPostProcessParameters();
  
      assert(m_entLocation.IsValid());
  
      /*
      This code which was around here is highly suspect; I suggest we fix 'standing on moving platforms' in a better way
  
      if (GetMCMV() == eMCM_SmoothedEntity)
      {
      static float elevationBlendDuration = 0.1f;
      float elevationBlend = clamp_tpl((float)m_curFrameTime / elevationBlendDuration, 0.0f, 1.0f);
  
      // Blend out vertical lag when not moving (e.g. standing still on a vertically moving platform).
      float velocityFractionH = clamp_tpl(m_actualEntSpeedHorizontal / 0.1f, 0.0f, 1.0f);
      elevationBlend = LERP(1.0f, elevationBlend, velocityFractionH);
  
      // Blend out vertical lag when not moving (e.g. standing still on a vertically moving platform).
      float prevFrameTimeInv = ((float)m_prevFrameTime > 0.0f) ? (1.0f / (float)m_prevFrameTime) : 0.0f;
      float actualEntVelocityZ = m_actualEntMovement.t.z * prevFrameTimeInv;
      float velocityFractionZ = clamp_tpl(actualEntVelocityZ / 1.0f, 0.0f, 1.0f);
      elevationBlend = LERP(elevationBlend, 1.0f, velocityFractionZ);
  
      m_animLocation.q = animLocationClamped.q;
      m_animLocation.t.x = animLocationClamped.t.x;
      m_animLocation.t.y = animLocationClamped.t.y;
      m_animLocation.t.z = LERP(m_animLocation.t.z, animLocationClamped.t.z, elevationBlend);
      }
      */
  
      assert(m_entLocation.IsValid());
  
      /*
      CRYANIMATION2
  
      Broke procedural leaning. The animrenderlocation used to contain the procedural leaning factor:
  
      if (EnableProceduralLeaning()
      && ((m_pAnimTarget == NULL) || (!m_pAnimTarget->activated))
      && ((GetMCMH() == eMCM_DecoupledCatchUp) || CAnimationGraphCVars::Get().m_nonDecoupledLeaning)) // This was added to primarily prevent deviation while parachuting.
      {
      QuatT proceduralLeaning = CalculateProceduralLeaning();
      animRenderLocation = animRenderLocation * proceduralLeaning;
      }
      */
  
  
      VALIDATE_CHARACTER_PTRS
  
  
  
          DebugRenderCurLocations();
  
  #ifdef _DEBUG
      DebugGraphQT(m_entLocation, "eDH_EntLocationPosX", "eDH_EntLocationPosY", "eDH_EntLocationOriZ");
  
      //DebugDisplayNewLocationsAndMovements(wantedEntLocationClamped, wantedEntMovement, wantedAnimLocationClamped, wantedAnimMovement, m_curFrameTime);
  #endif
  }
  
  void CAnimatedCharacter::ForceRefreshPhysicalColliderMode()
  {
      m_forcedRefreshColliderMode = true;
  }
  
  
  void CAnimatedCharacter::RequestPhysicalColliderMode(EColliderMode mode, EColliderModeLayer layer, const char* tag /* = NULL */)
  {
      bool update = (m_colliderModeLayers[layer] != mode);
      if (update || m_forcedRefreshColliderMode)
      {
          m_colliderModeLayersTag[layer] = tag;
          m_colliderModeLayers[layer] = mode;
          UpdatePhysicalColliderMode();
      }
  }
  
  void CAnimatedCharacter::HandleEvent(const SGameObjectEvent& event)
  {
      switch (event.event)
      {
      case eGFE_QueueBlendFromRagdoll:
          SetBlendFromRagdollizeParams(event);
          break;
      case eGFE_QueueRagdollCreation:
          SetRagdollizeParams(event);
          break;
      case eGFE_BecomeLocalPlayer:
      {
          m_isClient = true;
          break;
      }
      case eGFE_OnCollision:
      {
  #if ENABLE_CRY_PHYSICS
          const EventPhysCollision* pCollision = static_cast<const EventPhysCollision*>(event.ptr);
  
          // Ignore bullets and insignificant particles, etc.
          // TODO: This early-out condition should ideally be done on a higher level,
          // to avoid even touching this memory for all bullets and stuff.
          if (pCollision->pEntity[0]->GetType() == PE_PARTICLE)
          {
              break;
          }
  
          if (m_curFrameID > m_collisionFrameID)
          {
              m_collisionNormalCount = 0;
              m_collisionNormal[0].zero();
              m_collisionNormal[1].zero();
              m_collisionNormal[2].zero();
              m_collisionNormal[3].zero();
          }
  
          if ((m_curFrameID < m_collisionFrameID) || (m_collisionNormalCount >= 4) || (m_curFrameID <= 10))
          {
              break;
          }
  
          // Both entities in a collision recieve the same direction of the normal.
          // We need to flip the normal if this is the second entity.
          IPhysicalEntity* pPhysEnt = GetEntity()->GetPhysics();
          if (pPhysEnt == pCollision->pEntity[0])
          {
              m_collisionNormal[m_collisionNormalCount] = pCollision->n;
          }
          else if (pPhysEnt == pCollision->pEntity[1])
          {
              m_collisionNormal[m_collisionNormalCount] = -pCollision->n;
          }
  
          // We only care about the horizontal part, so we remove the vertical component for simplicity.
          m_collisionNormal[m_collisionNormalCount].z = 0.0f;
          if (!m_collisionNormal[m_collisionNormalCount].IsZero())
          {
              m_collisionNormal[m_collisionNormalCount].Normalize();
  
              if (s_debugDrawCollisionEvents)
              {
                  CPersistentDebug* pPD = CCryAction::GetCryAction()->GetPersistentDebug();
                  if (pPD != nullptr)
                  {
                      pPD->Begin(UNIQUE("AnimatedCharacter.HandleEvent.CollisionNormal"), false);
                      pPD->AddSphere(pCollision->pt, 0.02f, ColorF(1, 0.75f, 0.0f, 1), 0.1f);
                      pPD->AddLine(pCollision->pt, pCollision->pt + m_collisionNormal[m_collisionNormalCount] * 0.5f, ColorF(1, 0.75f, 0.0f, 1), 0.1f);
                  }
              }
  
              m_collisionFrameID = m_curFrameID;
              m_collisionNormalCount++;
          }
  #endif // ENABLE_CRY_PHYSICS
      }
      break;
  
      case eGFE_ResetAnimationGraphs:
          if (m_pMannequinAGState)
          {
              m_pMannequinAGState->Reset();
          }
          break;
      case eGFE_EnablePhysics:
          RequestPhysicalColliderMode(eColliderMode_Undefined, eColliderModeLayer_ForceSleep, "eGFE_EnablePhysics");
          break;
      case eGFE_DisablePhysics:
          RequestPhysicalColliderMode(eColliderMode_Disabled, eColliderModeLayer_ForceSleep, "eGFE_DisablePhysics");
          break;
      }
      // AnimationControlled/GameControlled: DEPRECATED in favor of MovementControlMethod controlled by AnimGraph.
  }
  
  void CAnimatedCharacter::ResetInertiaCache()
  {
  #if ENABLE_CRY_PHYSICS
      // Synch our cached inertia values with the living entity values
      pe_player_dynamics dynParams;
      IPhysicalEntity* pPhysEnt = GetEntity()->GetPhysics();
      if (pPhysEnt && pPhysEnt->GetParams(&dynParams))
      {
          m_fPrevInertia = dynParams.kInertia;
          m_fPrevInertiaAccel = dynParams.kInertiaAccel;
          m_fPrevTimeImpulseRecover = dynParams.timeImpulseRecover;
      }
  #endif // ENABLE_CRY_PHYSICS
  }
  
  void CAnimatedCharacter::ResetState()
  {
      if (m_pMannequinAGState)
      {
          m_pMannequinAGState->Reset();
      }
  
      if (m_pActionController)
      {
          m_pActionController->Reset();
      }
      ResetVars();
      ResetInertiaCache();
  }
  
  void CAnimatedCharacter::ResetVars()
  {
      IEntity* pEntity = GetEntity();
      assert(pEntity);
  
      m_params.Reset();
  
      m_facialAlertness = 0;
  
      m_currentStance = -1;
      m_requestedStance = -1;
      m_stanceQuery = 0;
  
      m_disallowLookIKFlags = 0;
      m_allowAimIk = true;
  
      // Why -1, why not 0?
      m_curFrameID = -1;
      m_lastResetFrameId = gEnv->pRenderer->GetFrameID();
      m_updateGrabbedInputFrameID = -1;
      m_moveRequestFrameID = -1;
      m_lastSerializeReadFrameID = 0;
      m_lastPostProcessUpdateFrameID = 0;
      m_lastAnimProcFrameID = 0;
  
      m_shadowCharacterSlot = -1;
      m_hasShadowCharacter = false;
  
      m_bSimpleMovementSetOnce = false;
  
      m_curWeaponRaisedPose = eWeaponRaisedPose_None;
  
      m_moveRequest.type = eCMT_None;
      m_moveRequest.velocity.zero();
      m_moveRequest.rotation.SetIdentity();
      m_moveRequest.prediction.Reset();
      m_moveRequest.jumping = false;
      m_moveRequest.allowStrafe = false;
      m_moveRequest.proceduralLeaning = false;
  
      m_inGrabbedState = false;
  
      m_groundAlignmentParams.InitVars();
  
      // Init IK Disable Distance to the CVar value if specified.
      const float ikDisableDistance = CAnimationGraphCVars::Get().m_distanceForceNoIk;
      m_groundAlignmentParams.ikDisableDistanceSqr = (float)fsel(-ikDisableDistance, m_groundAlignmentParams.ikDisableDistanceSqr, sqr(ikDisableDistance));
  
      m_isPlayer = false;
      m_isClient = false;
      if (pEntity)
      {
          IActorSystem* pActorSystem = CCryAction::GetCryAction()->GetIActorSystem();
          assert(pActorSystem != NULL);
          IActor* pActor = pActorSystem->GetActor(pEntity->GetId());
  
          //No longer asserting, as the animated character is no longer just used on actors
          if (pActor != NULL)
          {
              m_isPlayer = pActor->IsPlayer();
              m_isClient = pActor->IsClient();
  
              // Turn on by default for 3rd person in singleplayer.
              m_groundAlignmentParams.SetFlag(eGA_PoseAlignerUseRootOffset, pActor->IsThirdPerson() && !gEnv->bMultiplayer);
          }
      }
  
      m_curFrameStartTime.SetValue(0);
  
      m_curFrameTime = 0.0f;
      m_prevFrameTime = 0.0f;
      m_curFrameTimeOriginal = 0.0f;
  
      if (pEntity)
      {
          m_entLocation.t = pEntity->GetWorldPos();
          m_entLocation.q = pEntity->GetWorldRotation();
  
          m_prevEntLocation = m_entLocation;
      }
      else
      {
          m_entLocation.SetIdentity();
          m_prevEntLocation.SetIdentity();
      }
  
      m_expectedEntMovement.zero();
      m_actualEntMovement.SetIdentity();
      m_entTeleportMovement.SetIdentity();
  
      for (int i = 0; i < NumAxxSamples; i++)
      {
          m_reqLocalEntAxx[i].zero();
          m_reqEntVelo[i].zero();
          m_reqEntTime[i].SetValue(0);
      }
      m_reqLocalEntAxxNextIndex = 0;
      m_smoothedActualEntVelo.zero();
      m_smoothedAmountAxx = 0.0f;
      m_avgLocalEntAxx.zero();
  
      m_requestedEntMoveDirLH4 = 0;
      m_actualEntMoveDirLH4 = 0;
  
      for (int slot = 0; slot < eMCMSlot_COUNT; ++slot)
      {
          m_movementControlMethodTags[slot] = "ResetVars";
          m_movementControlMethod[eMCMComponent_Horizontal][slot] = eMCM_Entity;
          m_movementControlMethod[eMCMComponent_Vertical][slot] = eMCM_Entity;
      }
      for (int slot = eMCMSlotStack_Begin; slot < eMCMSlotStack_End; ++slot)
      {
          m_movementControlMethod[eMCMComponent_Horizontal][slot] = eMCM_Undefined;
          m_movementControlMethod[eMCMComponent_Vertical][slot] = eMCM_Undefined;
      }
      m_currentMovementControlMethodTags[eMCMComponent_Horizontal] = m_movementControlMethodTags[eMCMSlot_Cur];
      m_currentMovementControlMethodTags[eMCMComponent_Vertical] = m_movementControlMethodTags[eMCMSlot_Cur];
      m_elapsedTimeMCM[eMCMComponent_Horizontal] = 0.0f;
      m_elapsedTimeMCM[eMCMComponent_Vertical] = 0.0f;
  
      for (int layer = 0; layer < eColliderModeLayer_COUNT; layer++)
      {
          m_colliderModeLayersTag[layer] = "ResetVars";
          m_colliderModeLayers[layer] = eColliderMode_Undefined;
      }
      m_colliderMode = eColliderMode_Undefined;
  
      m_simplifiedAGSpeedInputsRequested = false;
      m_simplifiedAGSpeedInputsActual = false;
  
      m_requestedEntityMovement.SetIdentity();
      m_requestedEntityMovementType = RequestedEntMovementType_Undefined;
      m_requestedIJump = 0;
      m_bDisablePhysicalGravity = false;
  
      m_simplifyMovement = false;
      m_forceDisableSlidingContactEvents = false;
      m_noMovementTimer = 0.0f;
  
      m_actualEntSpeed = 0.0f;
      m_actualEntSpeedHorizontal = 0.0f;
      m_actualEntMovementDirHorizontal.zero();
      m_actualEntVelocityHorizontal.zero();
      m_actualEntAccelerationHorizontal.zero();
      m_actualEntTangentialAcceleration = 0.0f;
  
      m_pAnimTarget = NULL;
      m_pCharacter = NULL;
      m_pSkeletonAnim = NULL;
      m_pSkeletonPose = NULL;
      m_pShadowCharacter = NULL;
      m_pShadowSkeletonAnim = NULL;
      m_pShadowSkeletonPose = NULL;
  
      m_wasInAir = false;
      m_fallMaxHeight = 0.0f;
      m_landBobTime = 0.0f;
      m_totalLandBob = 0.0f;
  
      m_noMovementOverrideExternal = false;
  
      m_fJumpSmooth = 1.0f;
      m_fJumpSmoothRate = 1.0f;
      m_fGroundSlopeMoveDirSmooth = 0.0f;
      m_fGroundSlopeMoveDirRate = 0.0f;
      m_fGroundSlope = 0.0f;
      m_fGroundSlopeSmooth = 0.0f;
      m_fGroundSlopeRate = 0.0f;
      m_fRootHeightSmooth = 0.0f;
      m_fRootHeightRate = 0.0f;
  
      m_forcedRefreshColliderMode = false;
      m_bPendingRagdoll = false;
      m_ragdollParams = SRagdollizeParams();
  
      m_prevAnimPhaseHash = 0;
      m_prevAnimEntOffsetHash = 0.0f;
      m_prevMoveVeloHash = 0.0f;
      m_prevMoveJump = 0;
  
      m_moveOverride_useAnimXY = false;
      m_moveOverride_useAnimZ = false;
      m_moveOverride_useAnimRot = false;
  
      m_collisionFrameID = -1;
      m_collisionNormalCount = 0;
      m_collisionNormal[0].zero();
      m_collisionNormal[1].zero();
      m_collisionNormal[2].zero();
      m_collisionNormal[3].zero();
  
  #if ENABLE_CRY_PHYSICS
      if (m_pFeetColliderPE)
      {
          gEnv->pPhysicalWorld->DestroyPhysicalEntity(m_pFeetColliderPE);
          m_pFeetColliderPE = NULL;
      }
  #endif // ENABLE_CRY_PHYSICS
  
      DisableRigidCollider();
  
      if (m_debugHistoryManager)
      {
          m_debugHistoryManager->Clear();
      }
  
      if (pEntity)
      {
          // Disable physics as default when reviving/resetting characters.
          // Only a few frames after reset will non-disabled collider be allowed in UpdatePhysicalColliderMode().
  #if ENABLE_CRY_PHYSICS
          IPhysicalEntity* pPhysEnt = pEntity->GetPhysics();
          if (pPhysEnt)
          {
              pe_player_dynamics pd;
              pe_params_part pp;
              pd.bActive = 0;
              pp.flagsAND = ~(m_characterCollisionFlags);
              pPhysEnt->SetParams(&pd);
              pPhysEnt->SetParams(&pp);
          }
  #endif // ENABLE_CRY_PHYSICS
      }
  
      DestroyExtraSolidCollider();
  
      m_hasForcedMovement = false;
      m_forcedMovementRelative.SetIdentity();
      m_hasForcedOverrideRotation = false;
      m_forcedOverrideRotationWorld.SetIdentity();
  
      if (m_proxiesInitialized)
      {
          m_pComponentPrepareCharForUpdate->ClearQueuedRotation();
      }
  }
  
  void CAnimatedCharacter::SetOutput(const char* output, const char* value)
  {
  }
  
  void CAnimatedCharacter::QueryComplete(TAnimationGraphQueryID queryID, bool succeeded)
  {
      if (queryID == m_stanceQuery)
      {
          if (succeeded)
          {
              m_currentStance = m_requestedStance;
          }
          else
          {
              CryLog("CAnimatedCharacter::QueryComplete: failed setting stance %d on %s", m_requestedStance, GetEntity()->GetName());
          }
          m_requestedStance = -1;
          m_stanceQuery = 0;
      }
  }
  
  void CAnimatedCharacter::AddMovement(const SCharacterMoveRequest& request)
  {
      if (request.type != eCMT_None)
      {
          assert(request.rotation.IsValid());
          assert(request.velocity.IsValid());
  
          CheckNANVec(Vec3(request.velocity), GetEntity());
  
          // we should have processed a move request before adding a new one
          m_moveRequest = request;
          m_moveRequestFrameID = gEnv->pRenderer->GetFrameID();
  
          assert(m_moveRequest.rotation.IsValid());
          assert(m_moveRequest.velocity.IsValid());
      }
      else
      {
          m_moveRequest.type = eCMT_None;
          m_moveRequest.velocity.zero();
          m_moveRequest.rotation.SetIdentity();
          m_moveRequest.prediction.Reset();
          m_moveRequest.jumping = false;
          m_moveRequest.allowStrafe = false;
          m_moveRequest.proceduralLeaning = false;
      }
  }
  
  //////////////////////////////////////////////////////////////////////////
  void CAnimatedCharacter::ValidateCharacterPtrs()
  {
      ICharacterInstance* pCharacter = GetEntity()->GetCharacter(0);
      ICharacterInstance* pShadowCharacter = m_hasShadowCharacter ? GetEntity()->GetCharacter(m_shadowCharacterSlot) : NULL;
  
      const bool characterChanged = (pCharacter != m_pCharacter) || (m_pShadowCharacter != pShadowCharacter);
      CRY_ASSERT_TRACE(!characterChanged, ("CharacterPtrs out of date in %s. Ensure that updateCharacterPtrs is called on the animatedCharacter whenever new models are loaded", GetEntity()->GetName()));
  }
  
  //////////////////////////////////////////////////////////////////////////
  void CAnimatedCharacter::UpdateCharacterPtrs()
  {
      // TODO: OPT: These three will not change often (if ever), so they can be cached over many frames.
      // TODO: Though, make sure that they are refreshed if/when they actually DO change.
      ICharacterInstance* pCharacter = GetEntity()->GetCharacter(0);
      ICharacterInstance* pShadowCharacter = m_hasShadowCharacter ? GetEntity()->GetCharacter(m_shadowCharacterSlot) : NULL;
  
      const bool characterChanged = (pCharacter != m_pCharacter) || (m_pShadowCharacter != pShadowCharacter);
  
      m_pCharacter = pCharacter;
      m_pShadowCharacter = pShadowCharacter;
  
      if (characterChanged)
      {
          m_pSkeletonAnim = (m_pCharacter != NULL) ? m_pCharacter->GetISkeletonAnim() : NULL;
          m_pSkeletonPose = (m_pCharacter != NULL) ? m_pCharacter->GetISkeletonPose() : NULL;
  
          m_pShadowSkeletonAnim = (m_pShadowCharacter != NULL) ? m_pShadowCharacter->GetISkeletonAnim() : NULL;
          m_pShadowSkeletonPose = (m_pShadowCharacter != NULL) ? m_pShadowCharacter->GetISkeletonPose() : NULL;
  
          DisableEntitySystemCharacterUpdate();
          UpdateSkeletonSettings();
      }
  
      if (m_pActionController)
      {
          IActor* pActor = CCryAction::GetCryAction()->GetIActorSystem()->GetActor(GetEntityId());
          const bool isFirstPerson = pActor && (pActor->IsThirdPerson() == false);
  
          if (characterChanged || (isFirstPerson != m_lastACFirstPerson))
          {
              m_lastACFirstPerson = isFirstPerson;
  
              const int scopeContextSound = m_pActionController->GetContext().controllerDef.m_scopeContexts.Find("Audio");
              const int scopeContext1P = m_pActionController->GetContext().controllerDef.m_scopeContexts.Find("Char1P");
              const int scopeContext3P = m_pActionController->GetContext().controllerDef.m_scopeContexts.Find("Char3P");
  
              if (scopeContextSound >= 0 && m_pSoundDatabase)
              {
                  m_pActionController->SetScopeContext(scopeContextSound, *GetEntity(), NULL, m_pSoundDatabase);
              }
  
              if (isFirstPerson)
              {
                  if ((scopeContext1P >= 0) && m_pAnimDatabase1P)
                  {
                      if (m_pCharacter)
                      {
                          m_pActionController->SetScopeContext(scopeContext1P, *GetEntity(), m_pCharacter, m_pAnimDatabase1P);
                      }
                      else
                      {
                          m_pActionController->ClearScopeContext(scopeContext1P);
                      }
                  }
                  if ((scopeContext3P >= 0) && m_pAnimDatabase3P)
                  {
                      if (m_pShadowCharacter)
                      {
                          m_pActionController->SetScopeContext(scopeContext3P, *GetEntity(), m_pShadowCharacter, m_pAnimDatabase3P);
                      }
                      else
                      {
                          m_pActionController->ClearScopeContext(scopeContext3P);
                      }
                  }
              }
              else
              {
                  if (scopeContext1P >= 0)
                  {
                      m_pActionController->ClearScopeContext(scopeContext1P);
                  }
                  if ((scopeContext3P >= 0) && m_pAnimDatabase3P)
                  {
                      if (m_pCharacter)
                      {
                          m_pActionController->SetScopeContext(scopeContext3P, *GetEntity(), m_pCharacter, m_pAnimDatabase3P);
                      }
                      else
                      {
                          m_pActionController->ClearScopeContext(scopeContext3P);
                      }
                  }
              }
  
              for (TAnimCharListeners::Notifier notifier(m_listeners); notifier.IsValid(); notifier.Next())
              {
                  notifier->OnCharacterChange();
              }
          }
      }
  }
  
  //////////////////////////////////////////////////////////////////////////
  void CAnimatedCharacter::ProcessEvent(SEntityEvent& event)
  {
      FUNCTION_PROFILER(gEnv->pSystem, PROFILE_ACTION);
  
      switch (event.event)
      {
      case ENTITY_EVENT_PRE_SERIALIZE:
      {
          if (m_pActionController)
          {
              m_pActionController->Reset();
          }
      }
      break;
      case ENTITY_EVENT_ANIM_EVENT:
      {
          VALIDATE_CHARACTER_PTRS
  
          if (m_pActionController)
          {
              const AnimEventInstance* pAnimEvent = reinterpret_cast<const AnimEventInstance*>(event.nParam[0]);
              ICharacterInstance* pCharacter = reinterpret_cast<ICharacterInstance*>(event.nParam[1]);
              if (pAnimEvent && pCharacter)
              {
                  m_pActionController->OnAnimationEvent(pCharacter, *pAnimEvent);
              }
          }
      }
      break;
      case ENTITY_EVENT_XFORM:
      {
          int flags = (int)event.nParam[0];
  
          if (!(flags & (ENTITY_XFORM_USER | ENTITY_XFORM_PHYSICS_STEP)))
          {
              IEntity* pEntity = GetEntity();
              if (pEntity != NULL)
              {
                  QuatT entLocationTeleported = m_entLocation;     // maybe don't use this local variable, but instead just m_entLocation, and maybe call UpdateCurEntLocation() here as well, just in case.
  
                  // TODO: Optimize by not doing the merge of full QuatT's twice (once for each component).
                  if (flags & ENTITY_XFORM_ROT /*&& flags & (ENTITY_XFORM_TRACKVIEW|ENTITY_XFORM_EDITOR)*/)
                  {
                      entLocationTeleported.q = pEntity->GetWorldRotation();
                  }
                  if (flags & ENTITY_XFORM_POS)
                  {
                      entLocationTeleported.t = pEntity->GetWorldPos();
  
                      //if (pEntity->GetParent() == NULL && m_entLocation.t != entLocationTeleported.t)
                      //{
                      //  // forcing MCM's to eMCM_Entity only when teleported if not inside vehicle
                      //  // (inside vehicles entity can only move by teleporting)
                      //  EMovementControlMethod mcmh = GetMCMH();
                      //  EMovementControlMethod mcmv = GetMCMV();
                      //  bool forceEntity = false;
                      //  if (mcmh == eMCM_Animation || mcmh == eMCM_AnimationHCollision)
                      //  {
                      //      forceEntity = true;
                      //      mcmh = eMCM_Entity;
                      //  }
                      //  if (mcmv == eMCM_Animation)
                      //  {
                      //      forceEntity = true;
                      //      mcmv = eMCM_Entity;
                      //  }
                      //  if (forceEntity)
                      //      SetMovementControlMethods(mcmh, mcmv);
                      //}
                  }
  
                  if (!m_inGrabbedState)
                  {
                      // This is only for debugging, not used for anything.
                      m_entTeleportMovement = ApplyWorldOffset(m_entTeleportMovement, GetWorldOffset(m_entLocation, entLocationTeleported));
  
                      m_expectedEntMovement.zero();
                      m_entLocation = entLocationTeleported;
                  }
                  else
                  {
                      // [Benito] Note:
                      // When the player is grabbing an AI, the update of the character instance has to be delayed to this point
                      // The player instance will update, and the AI, being attached to the player's hand will get updated its final position
                      // at this point.
                      // Because this happens during SynchAllAnimations at the end of the frame, SetAnimationPostProcessParameters has true as 3rd parameter
                      // which means, it will immediatelly call FinishAnimations in the character (it's not ideal, but there is no other way to get the correct update order)
  
                      VALIDATE_CHARACTER_PTRS
  
                          m_entLocation = entLocationTeleported;
                      if (StartAnimationProcessing(m_entLocation))
                      {
                          SetAnimationPostProcessParameters(m_entLocation, true);
                      }
                  }
  
                  DestroyExtraSolidCollider();
  
                  m_pComponentPrepareCharForUpdate->ClearQueuedRotation();
              }
          }
      }
      break;
      case ENTITY_EVENT_SCRIPT_REQUEST_COLLIDERMODE:
      {
          VALIDATE_CHARACTER_PTRS
  
          EColliderMode mode = (EColliderMode)event.nParam[0];
          RequestPhysicalColliderMode(mode, eColliderModeLayer_Script);
      }
      break;
      case ENTITY_EVENT_DONE:
      {
          // Delete the ActionController before everything is deleted.
          DeleteActionController();
      }
      break;
      case ENTITY_EVENT_RETURNING_TO_POOL:
      {
          // Delete the ActionController before everything is reused.
          DeleteActionController();
      }
      break;
      }
  }
  
  
  float CAnimatedCharacter::FilterView(SViewParams& viewParams) const
  {
      ICharacterInstance* pCharacter = GetEntity()->GetCharacter(0);
      float animationControlledView = 0.0f;
  
      if (animationControlledView > 0.001f)
      {
          viewParams.viewID = 1;
          viewParams.nearplane = 0.1f;
  
          ISkeletonPose* pISkeletonPose = pCharacter->GetISkeletonPose();
          IDefaultSkeleton& rIDefaultSkeleton = pCharacter->GetIDefaultSkeleton();
  
          //FIXME:keep IDs and such
  
          //view position, get the character position from the eyes and blend it with the game desired position
          int id_right = rIDefaultSkeleton.GetJointIDByName(PoseAlignerBones::Right::Eye);
          int id_left = rIDefaultSkeleton.GetJointIDByName(PoseAlignerBones::Left::Eye);
          if (id_right > -1 && id_left > -1)
          {
              Vec3 characterViewPos(pISkeletonPose->GetAbsJointByID(id_right).t);
              characterViewPos += pISkeletonPose->GetAbsJointByID(id_left).t;
              characterViewPos *= 0.5f;
  
              characterViewPos = GetEntity()->GetSlotWorldTM(0) * characterViewPos;
  
              viewParams.position = animationControlledView * characterViewPos + (1.0f - animationControlledView) * viewParams.position;
          }
  
          //and then, same with view rotation
          int id_head = rIDefaultSkeleton.GetJointIDByName(PoseAlignerBones::Head);
          if (id_head > -1)
          {
              //  Quat characterViewQuat(Quat(GetEntity()->GetSlotWorldTM(0)) * Quat(pSkeleton->GetAbsJMatrixByID(id_head)) * Quat::CreateRotationY(gf_PI*0.5f));
              Quat characterViewQuat(Quat(GetEntity()->GetSlotWorldTM(0)) * pISkeletonPose->GetAbsJointByID(id_head).q * Quat::CreateRotationY(gf_PI * 0.5f));
  
              viewParams.rotation = Quat::CreateSlerp(viewParams.rotation, characterViewQuat, animationControlledView);
          }
      }
  
      return animationControlledView;
  }
  
  void CAnimatedCharacter::SetParams(const SAnimatedCharacterParams& params)
  {
      m_params = params;
  }
  
  void CAnimatedCharacter::RequestStance(int stanceID, const char* name)
  {
      m_stanceQuery = 0;
      m_requestedStance = -1;
      m_currentStance = stanceID;
  }
  
  int CAnimatedCharacter::GetCurrentStance()
  {
      return m_currentStance;
  }
  
  bool CAnimatedCharacter::InStanceTransition()
  {
      return m_requestedStance >= 0;
  }
  
  void CAnimatedCharacter::DestroyedState(IAnimationGraphState*)
  {
      m_pMannequinAGState = NULL;
  }
  
  
  uint32 CAnimatedCharacter::MakeFace(const char* pExpressionName, bool usePreviewChannel, float lifeTime)
  {
      uint32 channelId(~0);
      return channelId;
  }
  
  void CAnimatedCharacter::AllowLookIk(bool allow, int layer /* = -1 */)
  {
      unsigned int oneBasedLayerIndex = ((layer >= 0) && (layer < eAnimationGraphLayer_COUNT)) ? layer + 1 : 0;
  
      if (allow)
      {
          m_disallowLookIKFlags &= ~(1 << oneBasedLayerIndex);
      }
      else
      {
          m_disallowLookIKFlags |= (1 << oneBasedLayerIndex);
      }
  }
  
  void CAnimatedCharacter::AllowAimIk(bool allow)
  {
      m_allowAimIk = allow;
  }
  
  void CAnimatedCharacter::TriggerRecoil(float duration, float kinematicImpact, float kickIn /*=0.8f*/, EAnimatedCharacterArms arms /*=eACA_BothArms*/)
  {
      if (IActor* pActor = CCryAction::GetCryAction()->GetIActorSystem()->GetActor(GetEntityId()))
      {
          //--- Ensure that our cached ptrs are up to date as this can be called from outside the update loop
          VALIDATE_CHARACTER_PTRS
  
          ISkeletonPose* pSkeletonPose = pActor->IsThirdPerson() ? m_pSkeletonPose : m_pShadowSkeletonPose; // in 1p apply recoil on shadow instead of the main skeletonpose
  
          if (pSkeletonPose != NULL)
          {
              pSkeletonPose->ApplyRecoilAnimation(duration, kinematicImpact, kickIn, static_cast<uint32>(arms));
          }
      }
  }
  
  void CAnimatedCharacter::SetWeaponRaisedPose(EWeaponRaisedPose pose)
  {
      if (pose == m_curWeaponRaisedPose)
      {
          return;
      }
  
      ICharacterInstance* pCharacter = GetEntity()->GetCharacter(0);
      if (pCharacter == NULL)
      {
          return;
      }
  
      ISkeletonAnim* pSkeletonAnim = pCharacter->GetISkeletonAnim();
      if (pSkeletonAnim == NULL)
      {
          return;
      }
  
      m_curWeaponRaisedPose = pose;
  
      if ((pose == eWeaponRaisedPose_None) || (pose == eWeaponRaisedPose_Fists))
      {
          pSkeletonAnim->StopAnimationInLayer(2, 0.5f);  // Stop weapon raising animation in Layer 2.
          return;
      }
  
      const char* anim = NULL;
      switch (pose)
      {
      case eWeaponRaisedPose_Pistol:
          anim = "combat_idleAimBlockPoses_pistol_01";
          break;
      case eWeaponRaisedPose_PistolLft:
          anim = "combat_idleAimBlockPoses_dualpistol_left_01";
          break;
      case eWeaponRaisedPose_PistolRgt:
          anim = "combat_idleAimBlockPoses_dualpistol_right_01";
          break;
      case eWeaponRaisedPose_PistolBoth:
          anim = "combat_idleAimBlockPoses_dualpistol_01";
          break;
      case eWeaponRaisedPose_Rifle:
          anim = "combat_idleAimBlockPoses_rifle_01";
          break;
      case eWeaponRaisedPose_Rocket:
          anim = "combat_idleAimBlockPoses_rocket_01";
          break;
      case eWeaponRaisedPose_MG:
          anim = "combat_idleAimBlockPoses_mg_01";
          break;
      }
  
      if (anim == NULL)
      {
          m_curWeaponRaisedPose = eWeaponRaisedPose_None;
          return;
      }
  
      // Start the weapon raising in Layer 2. This will automatically deactivate aim-poses.
      CryCharAnimationParams Params0(0);
      Params0.m_nLayerID = 2;
      Params0.m_fTransTime = 0.5f;
      Params0.m_nFlags |= CA_LOOP_ANIMATION;
      pSkeletonAnim->StartAnimation(anim, Params0);
  }
  
  SGroundAlignmentParams& CAnimatedCharacter::GetGroundAlignmentParams()
  {
      return m_groundAlignmentParams;
  }
  
  void CAnimatedCharacter::GetMemoryUsage(ICrySizer* s) const
  {
      s->Add(*this);
      {
          SIZER_COMPONENT_NAME(s, "MannequinAGState");
          s->AddObject(m_pMannequinAGState);
      }
  
      {
          SIZER_COMPONENT_NAME(s, "DebugHistory");
          s->AddObject(m_debugHistoryManager);
      }
  }
  
  void CAnimatedCharacter::DeleteActionController()
  {
      SAFE_RELEASE(m_pActionController);
      SAFE_DELETE(m_pAnimContext);
  }
  
  void CAnimatedCharacter::SetActionController(const char* filename)
  {
      IMannequin& mannequinSys = gEnv->pGame->GetIGameFramework()->GetMannequinInterface();
      const SControllerDef* contDef = mannequinSys.GetAnimationDatabaseManager().LoadControllerDef(filename);
  
      DeleteActionController();
  
      if (contDef)
      {
          m_pAnimContext = new SAnimationContext(*contDef);
          m_pActionController = mannequinSys.CreateActionController(GetEntity(), *m_pAnimContext);
      }
  }
  
  void CAnimatedCharacter::SetShadowCharacterSlot(int id)
  {
      m_shadowCharacterSlot = id;
      m_hasShadowCharacter = true;
  
      InitShadowCharacter();
  }
  
  void CAnimatedCharacter::InitShadowCharacter()
  {
      //--- Ensure that the shadow skel is set to animDriven motion, don't wait until the occassional ticked update
      IEntity* pEntity = GetEntity();
      ICharacterInstance* pCharacterInstanceShadow = m_hasShadowCharacter ? pEntity->GetCharacter(m_shadowCharacterSlot) : NULL;
      ISkeletonAnim* pShadowSkeletonAnim = pCharacterInstanceShadow ? pCharacterInstanceShadow->GetISkeletonAnim() : NULL;
      if (pShadowSkeletonAnim)
      {
          pShadowSkeletonAnim->SetAnimationDrivenMotion(1);
      }
  }
  
  void CAnimatedCharacter::SetAnimationPlayerProxy(CAnimationPlayerProxy* proxy, int layer)
  {
      m_pAnimationPlayerProxies[layer] = proxy;
  }
  
  CAnimationPlayerProxy* CAnimatedCharacter::GetAnimationPlayerProxy(int layer)
  {
      CRY_ASSERT(layer < eAnimationGraphLayer_COUNT);
      return m_pAnimationPlayerProxies[layer];
  }
  
  void CAnimatedCharacter::DisableEntitySystemCharacterUpdate()
  {
      if (m_pCharacter)
      {
          // Turn off auto updating on this character,
          // AnimatedCharacter will be forcing Pre and Post update manually.
          m_pCharacter->SetFlags(m_pCharacter->GetFlags() & (~CS_FLAG_UPDATE));
  
          if (m_pShadowCharacter)
          {
              m_pShadowCharacter->SetFlags(m_pShadowCharacter->GetFlags() & (~CS_FLAG_UPDATE));
          }
      }
  }
  
  void CAnimatedCharacter::EnableLandBob(const SLandBobParams& landBobParams)
  {
      CRY_ASSERT(landBobParams.IsValid());
  
      m_landBobParams = landBobParams;
  }
  
  void CAnimatedCharacter::DisableLandBob()
  {
      m_landBobParams.Invalidate();
  }
  
  void CAnimatedCharacter::UseAnimationMovementForEntity(bool xyMove, bool zMove, bool rotation)
  {
      m_moveOverride_useAnimXY = xyMove;
      m_moveOverride_useAnimZ = zMove;
      m_moveOverride_useAnimRot = rotation;
  }
  
  void CAnimatedCharacter::SetInGrabbedState(bool bEnable)
  {
      m_noMovementOverrideExternal = bEnable;
      m_inGrabbedState = bEnable;
  }
  
  void CAnimatedCharacter::SetBlendFromRagdollizeParams(const SGameObjectEvent& event)
  {
      CRY_ASSERT(event.event == eGFE_QueueBlendFromRagdoll);
  
      m_blendFromRagollizeParams.m_bPendingBlend = event.paramAsBool;
  }
  
  void CAnimatedCharacter::SetRagdollizeParams(const SGameObjectEvent& event)
  {
      CRY_ASSERT(event.event == eGFE_QueueRagdollCreation);
  
      m_ragdollParams = *static_cast<const SRagdollizeParams*> (event.ptr);
  
      m_bPendingRagdoll = true;
  }
  
  void CAnimatedCharacter::KickOffRagdoll()
  {
  #if ENABLE_CRY_PHYSICS
      if (m_bPendingRagdoll)
      {
          m_groundAlignmentParams.SetFlag(eGA_Enable, false);
  
          SEntityPhysicalizeParams pp;
  
          pp.type = PE_ARTICULATED;
          pp.nSlot = 0;
          pp.bCopyJointVelocities = true;
  
          pp.mass = m_ragdollParams.mass;
  
          //never ragdollize without mass [Anton]
          pp.mass = (float)fsel(-pp.mass, 80.0f, pp.mass);
  
          pp.fStiffnessScale = m_ragdollParams.stiffness;
  
          pe_player_dimensions playerDim;
          pe_player_dynamics playerDyn;
  
          playerDyn.gravity.z = 15.0f;
          playerDyn.kInertia = 5.5f;
  
          pp.pPlayerDimensions = &playerDim;
          pp.pPlayerDynamics = &playerDyn;
  
          IPhysicalEntity* pPhysicalEntity = GetEntity()->GetPhysics();
          if (!pPhysicalEntity || pPhysicalEntity->GetType() != PE_LIVING)
          {
              pp.nLod = 1;
          }
  
          // Joints velocities are copied by default for now
          pp.bCopyJointVelocities = !gEnv->pSystem->IsSerializingFile();
          pp.nFlagsOR = pef_log_poststep;
          GetEntity()->Physicalize(pp);
  
          SGameObjectEvent triggeredRagdoll(eGFE_RagdollPhysicalized, eGOEF_ToExtensions);
          triggeredRagdoll.ptr = &m_ragdollParams;
          GetGameObject()->SendEvent(triggeredRagdoll);
      }
  #endif // ENABLE_CRY_PHYSICS
      m_bPendingRagdoll = false;
  
      if (m_blendFromRagollizeParams.m_bPendingBlend)
      {
          m_groundAlignmentParams.SetFlag(eGA_Enable, true);
  
          SGameObjectEvent event(eGFE_DisableBlendRagdoll, eGOEF_ToExtensions);
          GetGameObject()->SendEvent(event);
  
          /*      ICharacterInstance *pCharacter=GetEntity()->GetCharacter(0);
                  if (pCharacter && pCharacter->GetISkeletonAnim())
                  {
                      IPhysicalEntity *pPhysicalEntity=0;
                      Matrix34 delta(IDENTITY);
  
                      pCharacter->GetISkeletonPose()->StandUp( Matrix34(m_entLocation), false, pPhysicalEntity, delta);
  
                      if (pPhysicalEntity)
                      {
                          IComponentPhysicsPtr pPhysicsComponent = GetEntity()->GetComponent<IComponentPhysics>();
                          if (pPhysicsComponent)
                          {
                              GetEntity()->SetWorldTM(delta);
                              m_entLocation = QuatT(delta);
                              pPhysicsComponent->AssignPhysicalEntity(pPhysicalEntity);
  
                              GetGameObject()->SetAspectProfile(eEA_Physics, eAP_Alive);
                          }
                      }
                  }*/
      }
      m_blendFromRagollizeParams.m_bPendingBlend = false;
  }
  
  bool CAnimatedCharacter::StartAnimationProcessing(const QuatT& entityLocation) const
  {
      const int currentFrameId = gEnv->pRenderer->GetFrameID();
  
      if ((m_pCharacter != NULL) && (m_lastAnimationUpdateFrameId != currentFrameId))
      {
          // calculate the approximate distance from camera
          CCamera* pCamera = &GetISystem()->GetViewCamera();
          const float fDistance = ((pCamera ? pCamera->GetPosition() : entityLocation.t) - entityLocation.t).GetLength();
          const float fZoomFactor = 0.001f + 0.999f * (RAD2DEG((pCamera ? pCamera->GetFov() : 60.0f)) / 60.f);
  
          SAnimationProcessParams params;
          params.locationAnimation = entityLocation;
          params.bOnRender = 0;
          params.zoomAdjustedDistanceFromCamera = fDistance * fZoomFactor;
          params.locationAnimation = QuatTS(entityLocation.q, entityLocation.t, m_pCharacter->GetUniformScale());
  
          if (m_pShadowCharacter)
          {
              m_pShadowCharacter->StartAnimationProcessing(params);
          }
  
          m_pCharacter->StartAnimationProcessing(params);
  
          m_lastAnimationUpdateFrameId = currentFrameId;
  
          return true;
      }
  
      return false;
  }
  
  void CAnimatedCharacter::SetAnimationPostProcessParameters(const QuatT& entityLocation, const bool finishImmediate) const
  {
      if (m_pCharacter != NULL)
      {
          const CCamera& viewCamera = GetISystem()->GetViewCamera();
          const float scale = GetEntity()->GetWorldTM().GetColumn(0).GetLength();
          const float fDistance = (viewCamera.GetPosition() - entityLocation.t).GetLength();
          const float fZoomFactor = 0.001f + 0.999f * (RAD2DEG((viewCamera.GetFov())) / 60.f);
  
          m_pCharacter->SetAttachmentLocation_DEPRECATED(QuatTS(entityLocation.q, entityLocation.t, scale));
          if (m_pShadowCharacter)
          {
              m_pShadowCharacter->SetAttachmentLocation_DEPRECATED(QuatTS(entityLocation.q, entityLocation.t, scale));
          }
  
          if (finishImmediate)
          {
              m_pCharacter->FinishAnimationComputations();
  
              //This path won't trigger, but for consistency
              if (m_pShadowCharacter)
              {
                  m_pShadowCharacter->FinishAnimationComputations();
              }
          }
      }
  }
  
  void CAnimatedCharacter::StartAnimationProcessing() const
  {
      m_lastAnimProcFrameID = gEnv->pRenderer->GetFrameID();
  
      if (UseNormalAnimationProcessing())
      {
          StartAnimationProcessing(m_entLocation);
      }
  }
  
  void CAnimatedCharacter::SetAnimationPostProcessParameters() const
  {
      if (UseNormalAnimationProcessing())
      {
          SetAnimationPostProcessParameters(m_entLocation);
      }
  }
  
  void CAnimatedCharacter::PrepareAndStartAnimProc()
  {
      if (m_curFrameTime <= 0.0f)
      {
          return;
      }
  
      UpdateCharacterPtrs();
  
      KickOffRagdoll();
  
      UpdateGroundAlignment();
  
      StartAnimationProcessing();
  
      UpdatePhysicalColliderMode();
  
      UpdatePhysicsInertia();
  }
  
  void CAnimatedCharacter::ForceMovement(const QuatT& relativeMovement)
  {
      if (!m_hasForcedMovement)
      {
          m_forcedMovementRelative = relativeMovement;
      }
      else
      {
          m_forcedMovementRelative = ApplyWorldOffset(m_forcedMovementRelative, relativeMovement);
      }
      m_hasForcedMovement = true;
  }
  
  void CAnimatedCharacter::ForceOverrideRotation(const Quat& qWorldRotation)
  {
      m_forcedOverrideRotationWorld = qWorldRotation;
      m_hasForcedOverrideRotation = true;
  }
  
  void CAnimatedCharacter::UpdateGroundAlignment()
  {
      //use ground alignment only when character is close to the camera
      if (m_pSkeletonPose)
      {
          bool bNeedUpdate = true;
  
          if (m_simplifyMovement)
          {
              bNeedUpdate = false;
          }
          else if (!m_groundAlignmentParams.IsFlag(eGA_Enable))
          {
              bNeedUpdate = false;
          }
          else
          {
              //check if player is close enough
              CCamera& camera = gEnv->pSystem->GetViewCamera();
              const float fDistanceSq =   (camera.GetPosition() - m_entLocation.t).GetLengthSquared();
  
              // check if the character is using an animAction
              // because these should allow groundAlignment even in animation driven mode
              const int currentStance = GetCurrentStance();
  
              if (fDistanceSq > m_groundAlignmentParams.ikDisableDistanceSqr)
              {
                  bNeedUpdate = false;
              }
              else if (GetEntity()->GetParent() != NULL)
              {
                  bNeedUpdate = false;
              }
              else if ((currentStance == STANCE_SWIM) ||
                       (currentStance == STANCE_ZEROG) ||
                       (currentStance == STANCE_PRONE))
              {
                  bNeedUpdate = false;
              }
              else if (NoMovementOverride() && !m_groundAlignmentParams.IsFlag(eGA_AllowWithNoCollision))
              {
                  bNeedUpdate = false;
              }
              else if ((m_colliderMode == eColliderMode_Disabled) && !m_groundAlignmentParams.IsFlag(eGA_AllowWithNoCollision))
              {
                  bNeedUpdate = false;
              }
              else if (GetMCMV() == eMCM_Animation)
              {
                  bNeedUpdate = false;
              }
  #if ENABLE_CRY_PHYSICS
              else if (!m_groundAlignmentParams.IsFlag(eGA_AllowWhenHasGroundCollider))
              {
                  if (IPhysicalEntity* piPhysics = GetEntity()->GetPhysics())
                  {
                      // Can't get access to whether the actor has a ground collider here,
                      // so querying physics directly. This is really a bug :(
                      pe_status_living peLiv;
                      piPhysics->GetStatus(&peLiv);
                      if (peLiv.pGroundCollider)
                      {
                          bNeedUpdate = false;
                      }
                  }
              }
  #endif // ENABLE_CRY_PHYSICS
          }
  
          if (bNeedUpdate)
          {
              PostProcessingUpdate();
          }
      }
  }
  
  void CAnimatedCharacter::PerformSimpleMovement()
  {
      return;
      //this function doesn't make any sense here. We ALWAYS update entities in CryAnimation
      CryFatalError("no need to update entities here");
      /*  if (m_simplifyMovement && m_pCharacter)
          {
              //if a character is not visible on screen, we still have to update the world position of the attached entity
              QuatT EntLocation;
              EntLocation.q=GetEntity()->GetWorldRotation();
              EntLocation.t=GetEntity()->GetWorldPos();
              m_pCharacter->UpdateAttachedObjectsFast(EntLocation,0.0f);
          }*/
  }
  
  void CAnimatedCharacter::GenerateMovementRequest()
  {
      // 21/09/2012: Workaround for cases in which ResetVars() is called after PrepareAnimatedCharacterForUpdate() but before GenerateMovementRequest()
      // This could turn into a proper 'cache' of useful variables like curFrameTime, velocity, ... which gets properly invalidated
      // whenever ResetVars() is called.
      IF_UNLIKELY (m_curFrameTime == 0.0f)
      {
          UpdateTime();
      }
  
      UpdateCharacterPtrs();
  
      UpdateSimpleMovementConditions();
  
      RefreshAnimTarget();
  
      PreAnimationUpdate();
  
      // Update actioncontroller after the graph if we push fragments
      // (fragments started by the graph should start as soon as possible)
      if (m_pActionController)
      {
          m_pActionController->Update((float) m_curFrameTime);
      }
  
      CalculateParamsForCurrentMotions();
  
      UpdateMCMs();
  
      CalculateAndRequestPhysicalEntityMovement();
  }
  
  void CAnimatedCharacter::PrepareAnimatedCharacterForUpdate()
  {
  #ifdef DEBUGHISTORY
      SetupDebugHistories();
  #endif
  
  #ifdef _DEBUG
      RunTests();
  #endif
  
      UpdateTime();
      GetCurrentEntityLocation();
      RefreshAnimTarget();
  }
  
  namespace animatedcharacter
  {
      void Preload(struct IScriptTable* pEntityScript)
      {
          // Cache Mannequin related files
          bool hasActionController = false;
          {
              IMannequin& mannequinSystem = gEnv->pGame->GetIGameFramework()->GetMannequinInterface();
              IAnimationDatabaseManager& animationDatabaseManager = mannequinSystem.GetAnimationDatabaseManager();
  
              const char* szAnimationDatabase1p = 0;
              if (pEntityScript->GetValue("AnimDatabase1P", szAnimationDatabase1p) &&
                  szAnimationDatabase1p && szAnimationDatabase1p[0])
              {
                  animationDatabaseManager.Load(szAnimationDatabase1p);
              }
  
              const char* szAnimationDatabase3p = 0;
              if (pEntityScript->GetValue("AnimDatabase3P", szAnimationDatabase3p) &&
                  szAnimationDatabase3p && szAnimationDatabase3p[0])
              {
                  animationDatabaseManager.Load(szAnimationDatabase3p);
              }
  
              const char* szSoundDatabase = 0;
              if (pEntityScript->GetValue("SoundDatabase", szSoundDatabase) &&
                  szSoundDatabase && szSoundDatabase[0])
              {
                  animationDatabaseManager.Load(szSoundDatabase);
              }
  
              const char* szControllerDef = 0;
              if (pEntityScript->GetValue("ActionController", szControllerDef) &&
                  szControllerDef && szControllerDef[0])
              {
                  const SControllerDef* pControllerDef = animationDatabaseManager.LoadControllerDef(szControllerDef);
                  hasActionController = (pControllerDef != NULL);
              }
          }
      }
  } // namespace animatedcharacter
  