BVB Source Codes

CRYENGINE Show Vehicle.cpp Source code

Return Download CRYENGINE: download Vehicle.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. /*************************************************************************
  4.    -------------------------------------------------------------------------
  5.    $Id$
  6.    $DateTime$
  7.    Description: Implements vehicle functionality
  8.  
  9.    -------------------------------------------------------------------------
  10.    History:
  11.    - 05:10:2004: Created by Mathieu Pinard
  12.  
  13. *************************************************************************/
  14. #include "StdAfx.h"
  15.  
  16. #include <IViewSystem.h>
  17. #include <IItemSystem.h>
  18. #include <IVehicleSystem.h>
  19. #include <CryPhysics/IPhysics.h>
  20. #include <CryAnimation/ICryAnimation.h>
  21. #include <IActorSystem.h>
  22. #include <CryNetwork/ISerialize.h>
  23. #include <CryAISystem/IAgent.h>
  24.  
  25. #include "IGameRulesSystem.h"
  26.  
  27. #include "VehicleSystem.h"
  28. #include "ScriptBind_Vehicle.h"
  29. #include "ScriptBind_VehicleSeat.h"
  30. #include "VehicleCVars.h"
  31. #include "VehicleDamagesGroup.h"
  32. #include "Vehicle.h"
  33. #include "VehicleAnimation.h"
  34. #include "VehicleComponent.h"
  35. #include "VehicleHelper.h"
  36. #include "VehicleSeat.h"
  37. #include "VehicleSeatGroup.h"
  38. #include "VehicleSeatActionWeapons.h"
  39. #include "VehicleSeatActionRotateTurret.h"
  40.  
  41. #include "VehiclePartAnimated.h"
  42. #include "VehiclePartAnimatedJoint.h"
  43. #include "VehiclePartSubPartWheel.h"
  44. #include "VehiclePartTread.h"
  45. #include "VehicleUtils.h"
  46.  
  47. #include "CryAction.h"
  48. #include "Serialization/XMLScriptLoader.h"
  49. #include "PersistantDebug.h"
  50. #include <CryAISystem/IAIObject.h>
  51.  
  52. #include "CryActionCVars.h"
  53.  
  54. #define ENGINESLOT_MINSPEED 0.05f
  55.  
  56. // Default distance ratio for vehicles.
  57. #define DEFAULT_VEHICLE_VIEW_DIST_RATIO (50)
  58.  
  59. int CVehicle::s_repairHitTypeId = 0;
  60. int CVehicle::s_disableCollisionsHitTypeId = 0;
  61. int CVehicle::s_collisionHitTypeId = 0;
  62. int CVehicle::s_normalHitTypeId = 0;
  63. int CVehicle::s_fireHitTypeId = 0;
  64. int CVehicle::s_punishHitTypeId = 0;
  65. int CVehicle::s_vehicleDestructionTypeId = 0;
  66.  
  67. const static string s_vehicleImplXmlDir = "Scripts/Entities/Vehicles/Implementations/Xml/";
  68.  
  69. namespace Veh
  70. {
  71. void RegisterEvents(IGameObjectExtension& goExt, IGameObject& gameObject)
  72. {
  73.         const int eventToRegister[] =
  74.         {
  75.                 eGFE_OnPostStep,
  76.                 eGFE_OnCollision,
  77.                 eGFE_OnStateChange,
  78.                 eGFE_OnBecomeVisible,
  79.                 eGFE_PreShatter,
  80.                 eGFE_StoodOnChange
  81.         };
  82.  
  83.         gameObject.UnRegisterExtForEvents(&goExt, NULL, 0);
  84.         gameObject.RegisterExtForEvents(&goExt, eventToRegister, sizeof(eventToRegister) / sizeof(int));
  85. }
  86. }
  87.  
  88. //------------------------------------------------------------------------
  89. CVehicle::CVehicle() :
  90.         m_mass(0.0f),
  91.         m_wheelCount(0),
  92.         m_pMovement(NULL),
  93.         m_ownerId(0),
  94.         m_customEngineSlot(false),
  95.         m_bRetainGravity(false),
  96.         m_usesVehicleActionToEnter(false),
  97.         m_isDestroyed(false),
  98.         m_initialposition(0.0f),
  99.         m_lastWeaponId(0),
  100.         m_pIEntityAudioComponent(),
  101.         //m_abandonedSoundId(INVALID_SOUNDID),
  102.         m_bNeedsUpdate(true),
  103.         m_lastFrameId(0),
  104.         m_pInventory(NULL),
  105.         m_collisionDisabledTime(0.0f),
  106.         m_indestructible(false),
  107.         m_pVehicleSystem(NULL),
  108.         m_damageMax(0.f),
  109.         m_pPaintMaterial(NULL),
  110.         m_pDestroyedMaterial(NULL),
  111.         m_eventListeners(3),
  112.         m_unmannedflippedThresholdDot(0.1f),
  113.         m_ParentId(0),
  114.         m_bCanBeAbandoned(true),
  115.         m_isDestroyable(true),
  116.         m_hasAuthority(false),
  117.         m_smoothedPing(0.0f),
  118.         m_clientSmoothedPosition(IDENTITY),
  119.         m_clientPositionError(IDENTITY)
  120. {
  121.         m_gravity.zero();
  122.         m_physUpdateTime = 0.f;
  123.  
  124. #if ENABLE_VEHICLE_DEBUG
  125.         m_debugIndex = 0;
  126. #endif
  127. }
  128.  
  129. //------------------------------------------------------------------------
  130. unsigned int CVehicle::GetPartChildrenCount(IVehiclePart* pParentPart)
  131. {
  132.         TVehiclePartVector::iterator partIte = m_parts.begin();
  133.         TVehiclePartVector::iterator partEnd = m_parts.end();
  134.  
  135.         unsigned int counter = 0;
  136.  
  137.         for (; partIte != partEnd; ++partIte)
  138.         {
  139.                 IVehiclePart* pPart = partIte->second;
  140.  
  141.                 if (pPart && pPart->GetParent() == pParentPart)
  142.                         counter++;
  143.         }
  144.  
  145.         return counter;
  146. }
  147.  
  148. //------------------------------------------------------------------------
  149. CVehicle::~CVehicle()
  150. {
  151.         CVehicleSystem* pVehicleSystem = (CVehicleSystem*)m_pVehicleSystem;
  152.         if (pVehicleSystem->GetCurrentClientVehicle() == this)
  153.         {
  154.                 // If another thread is currently doing things with the vehicle wait until it has finished
  155.                 CryAutoCriticalSection lock(pVehicleSystem->GetCurrentVehicleLock());
  156.                 pVehicleSystem->ClearCurrentClientVehicle();
  157.         }
  158.  
  159.         for (TVehicleSeatVector::iterator it = m_seats.begin(), end = m_seats.end(); it != end; ++it)
  160.         {
  161.                 if (it->second->GetPassenger())
  162.                         it->second->Exit(false, true);
  163.         }
  164.  
  165.         SVehicleEventParams pa;
  166.         BroadcastVehicleEvent(eVE_PreVehicleDeletion, pa);
  167.  
  168.         KillTimers();
  169.  
  170.         for (TVehicleSoundEventId id = 0; id < m_soundEvents.size(); ++id)
  171.                 StopSound(id);
  172.  
  173.         ReleaseDamages();
  174.  
  175.         SVehicleEventParams eventParams;
  176.         BroadcastVehicleEvent(eVE_VehicleDeleted, eventParams);
  177.  
  178.         if (SpawnAndDeleteEntities(true))
  179.         {
  180.                 // delete AI anchors
  181.                 IEntityClass* pAnchorClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass("AIAnchor");
  182.  
  183.                 int nChildren = GetEntity()->GetChildCount();
  184.                 for (int i = nChildren - 1; i >= 0; --i)
  185.                 {
  186.                         IEntity* pEnt = GetEntity()->GetChild(i);
  187.  
  188.                         if (pEnt && pEnt->GetClass() == pAnchorClass)
  189.                         {
  190.                                 gEnv->pEntitySystem->RemoveEntity(pEnt->GetId(), true);
  191.                         }
  192.                 }
  193.         }
  194.  
  195.         TVehicleActionVector::iterator actionIte = m_actions.begin();
  196.         TVehicleActionVector::iterator actionEnd = m_actions.end();
  197.         for (; actionIte != actionEnd; ++actionIte)
  198.         {
  199.                 SVehicleActionInfo& actionInfo = *actionIte;
  200.                 actionInfo.pAction->Release();
  201.         }
  202.  
  203.         for (TVehicleSeatVector::iterator ite = m_seats.begin(); ite != m_seats.end(); ++ite)
  204.         {
  205.                 ite->second->Release();
  206.         }
  207.  
  208.         for (TVehicleHelperMap::iterator it = m_helpers.begin(); it != m_helpers.end(); ++it)
  209.         {
  210.                 SAFE_RELEASE(it->second);
  211.         }
  212.         stl::free_container(m_helpers);
  213.  
  214.         std::for_each(m_components.begin(), m_components.end(), stl::container_object_deleter());
  215.  
  216.         TVehiclePartVector::iterator partIte;
  217.         TVehiclePartVector::iterator partEnd;
  218.  
  219.         bool isEmpty;
  220.  
  221.         do
  222.         {
  223.                 partIte = m_parts.begin();
  224.                 partEnd = m_parts.end();
  225.  
  226.                 isEmpty = true;
  227.  
  228.                 for (; partIte != partEnd; ++partIte)
  229.                 {
  230.                         IVehiclePart* pPart = partIte->second;
  231.                         if (pPart)
  232.                         {
  233.                                 if (GetPartChildrenCount(pPart) == 0)
  234.                                 {
  235.                                         pPart->Release();
  236.                                         partIte->second = NULL;
  237.                                 }
  238.                                 else
  239.                                 {
  240.                                         isEmpty = false;
  241.                                 }
  242.                         }
  243.                 }
  244.         }
  245.         while (m_parts.size() > 0 && isEmpty != true);
  246.  
  247.         m_parts.clear();
  248.  
  249.         if (m_pMovement)
  250.         {
  251.                 GetGameObject()->EnablePhysicsEvent(false, eEPE_OnPostStepImmediate | eEPE_OnPostStepLogged);
  252.                 SAFE_RELEASE(m_pMovement);
  253.         }
  254.  
  255.         if (m_pInventory)
  256.         {
  257.                 if (gEnv->bServer)
  258.                         m_pInventory->Destroy();
  259.  
  260.                 GetGameObject()->ReleaseExtension("Inventory");
  261.         }
  262.  
  263.         CCryAction::GetCryAction()->GetIVehicleSystem()->RemoveVehicle(GetEntityId());
  264.  
  265.         GetGameObject()->EnablePhysicsEvent(false, eEPE_OnCollisionLogged | eEPE_OnStateChangeLogged);
  266.         //GetGameObject()->DisablePostUpdates(this);
  267.  
  268.         for (TVehicleAnimationsVector::iterator it = m_animations.begin(); it != m_animations.end(); ++it)
  269.         {
  270.                 it->second->Release();
  271.         }
  272. }
  273.  
  274. //------------------------------------------------------------------------
  275. bool CVehicle::SpawnAndDeleteEntities(bool clientBasedOnly)
  276. {
  277.         if (!clientBasedOnly)
  278.                 return !(GetISystem()->IsSerializingFile() || IsDemoPlayback());
  279.         return !(GetISystem()->IsSerializingFile());
  280. }
  281.  
  282. //------------------------------------------------------------------------
  283. void CVehicle::LoadParts(const CVehicleParams& table, IVehiclePart* pParent, SPartInitInfo& initInfo)
  284. {
  285.         int c = table.getChildCount();
  286.         int i = 0;
  287.         m_parts.reserve(m_parts.capacity() + c);
  288.  
  289.         for (; i < c; i++)
  290.         {
  291.                 CVehicleParams partTable = table.getChild(i);
  292.                 if (IVehiclePart* pPart = AddPart(partTable, pParent, initInfo))
  293.                 {
  294.                         if (CVehicleParams childPartsTable = partTable.findChild("Parts"))
  295.                                 LoadParts(childPartsTable, pPart, initInfo);
  296.                 }
  297.         }
  298. }
  299.  
  300. namespace
  301. {
  302. //------------------------------------------------------------------------
  303. XmlNodeRef LoadXmlForClass(const char* className, const string& xmlDir)
  304. {
  305.         // try to load file with same filename as class name
  306.         string xmlFile = xmlDir + className + ".xml";
  307.  
  308.         IGameRules* pGameRules = CCryAction::GetCryAction()->GetIGameRulesSystem()->GetCurrentGameRules();
  309.  
  310.         XmlNodeRef xmlData = (pGameRules ? pGameRules->FindPrecachedXmlFile(xmlFile.c_str()) : (XmlNodeRef) 0);
  311.         if (0 == xmlData)
  312.         {
  313.                 // xml file didn't exist in precache (or precache doesn't exist!), so just load it as normal
  314.                 xmlData = gEnv->pSystem->LoadXmlFromFile(xmlFile.c_str());
  315.         }
  316.  
  317.         if (0 == xmlData)
  318.         {
  319.                 // if not found, search xml dir for files with name="<class>" attribute
  320.                 _finddata_t fd;
  321.                 intptr_t handle;
  322.                 int res;
  323.  
  324.                 if ((handle = gEnv->pCryPak->FindFirst(xmlDir + "*.xml", &fd)) != -1)
  325.                 {
  326.                         do
  327.                         {
  328.                                 if (XmlNodeRef root = GetISystem()->LoadXmlFromFile(xmlDir + string(fd.name)))
  329.                                 {
  330.                                         const char* name = root->getAttr("name");
  331.                                         if (0 == strcmp(name, className))
  332.                                         {
  333.                                                 xmlData = root;
  334.                                                 break;
  335.                                         }
  336.                                 }
  337.                                 res = gEnv->pCryPak->FindNext(handle, &fd);
  338.                         }
  339.                         while (res >= 0);
  340.  
  341.                         gEnv->pCryPak->FindClose(handle);
  342.                 }
  343.         }
  344.  
  345.         return xmlData;
  346. }
  347. }
  348.  
  349. //------------------------------------------------------------------------
  350. void CVehicle::SerializeSpawnInfo(TSerialize ser)
  351. {
  352.         CRY_ASSERT(ser.IsReading());
  353.         ser.Value("modifications", m_modifications);
  354.         ser.Value("paint", m_paintName);
  355.         ser.Value("parentId", m_ParentId, 'eid');
  356. }
  357.  
  358. namespace CVehicleGetSpawnInfo
  359. {
  360. struct SInfo : public ISerializableInfo
  361. {
  362.         string   modifications;
  363.         string   paint;
  364.         EntityId parentId;
  365.         void SerializeWith(TSerialize ser)
  366.         {
  367.                 ser.Value("modifications", modifications);
  368.                 ser.Value("paint", paint);
  369.                 ser.Value("parentId", parentId, 'eid');
  370.         }
  371. };
  372. }
  373. //------------------------------------------------------------------------
  374. ISerializableInfoPtr CVehicle::GetSpawnInfo()
  375. {
  376.         CVehicleGetSpawnInfo::SInfo* p = new CVehicleGetSpawnInfo::SInfo;
  377.         p->modifications = m_modifications;
  378.         p->paint = m_paintName;
  379.         p->parentId = m_ParentId;
  380.         return p;
  381. }
  382.  
  383. //------------------------------------------------------------------------
  384. bool CVehicle::Init(IGameObject* pGameObject)
  385. {
  386.         CryLog("Init vehicle: %s", pGameObject->GetEntity()->GetEntityTextDescription().c_str());
  387.         INDENT_LOG_DURING_SCOPE();
  388.  
  389.         SetGameObject(pGameObject);
  390.  
  391.         IEntity* pEntity = GetEntity();
  392.         CRY_ASSERT(pEntity == pGameObject->GetEntity());
  393.  
  394.         if (s_disableCollisionsHitTypeId == 0 || s_repairHitTypeId == 0 || s_collisionHitTypeId == 0
  395.             || s_normalHitTypeId == 0 || s_fireHitTypeId == 0 || s_punishHitTypeId == 0)
  396.         {
  397.                 IGameRules* pGR = CCryAction::GetCryAction()->GetIGameRulesSystem()->GetCurrentGameRules();
  398.                 if (pGR)
  399.                 {
  400.                         s_repairHitTypeId = pGR->GetHitTypeId("repair");
  401.                         s_disableCollisionsHitTypeId = pGR->GetHitTypeId("disableCollisions");
  402.                         s_collisionHitTypeId = pGR->GetHitTypeId("collision");
  403.                         s_normalHitTypeId = pGR->GetHitTypeId("normal");
  404.                         s_fireHitTypeId = pGR->GetHitTypeId("fire");
  405.                         s_punishHitTypeId = pGR->GetHitTypeId("punish");
  406.                         s_vehicleDestructionTypeId = pGR->GetHitTypeId("vehicleDestruction");
  407.  
  408.                         assert(s_repairHitTypeId && s_disableCollisionsHitTypeId && s_collisionHitTypeId
  409.                                 && s_normalHitTypeId && s_fireHitTypeId && s_punishHitTypeId);
  410.                 }
  411.                 CRY_ASSERT_MESSAGE(pGR, "No valid game rules set!");
  412.         }
  413.  
  414.         if (gEnv->bMultiplayer && (CCryActionCVars::Get().g_multiplayerEnableVehicles == 0))
  415.         {
  416.                 static IEntityClass* pMPGunshipClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass("MP_PerkAlienGunship");
  417.  
  418.                 if (pMPGunshipClass != pEntity->GetClass())
  419.                 {
  420.                         GameWarning("!Vehicles disabled in multiplayer, not spawning entity '%s'", pEntity->GetName());
  421.                         return false;
  422.                 }
  423.         }
  424.  
  425.         m_pIEntityAudioComponent = pEntity->GetOrCreateComponent<IEntityAudioComponent>();
  426.         CRY_ASSERT(m_pIEntityAudioComponent && "no sound proxy on entity");
  427.  
  428.         m_pVehicleSystem = CCryAction::GetCryAction()->GetIVehicleSystem();
  429.         m_engineSlotBySpeed = true;
  430.  
  431.         m_parts.clear();
  432.         m_seats.clear();
  433.  
  434.         CCryAction::GetCryAction()->GetIVehicleSystem()->AddVehicle(GetEntityId(), this);
  435.         CCryAction::GetCryAction()->GetVehicleScriptBind()->AttachTo(this);
  436.  
  437.         m_pInventory = static_cast<IInventory*>(GetGameObject()->AcquireExtension("Inventory"));
  438.  
  439.         InitRespawn();
  440.  
  441.         const char* className = pEntity->GetClass()->GetName();
  442.  
  443.         // load the xml data into the vehicle lua table
  444.         XmlNodeRef vehicleXmlData = LoadXmlForClass(className, s_vehicleImplXmlDir);
  445.  
  446.         if (!vehicleXmlData)
  447.         {
  448.                 GameWarning("<%s>: failed loading xml file (directory %s), aborting initialization", pEntity->GetName(), s_vehicleImplXmlDir.c_str());
  449.                 return false;
  450.         }
  451.  
  452.         // if modification is used, merge its elements with main tree
  453.         if (m_modifications.empty())
  454.         {
  455.                 IScriptTable* pScriptTable = pEntity->GetScriptTable();
  456.                 if (pScriptTable)
  457.                 {
  458.                         SmartScriptTable pProps;
  459.                         if (pScriptTable->GetValue("Properties", pProps))
  460.                         {
  461.                                 const char* modification = 0;
  462.                                 if (pProps->GetValue("Modification", modification))
  463.                                 {
  464.                                         //Trim out all whitespace (as the modification name is used for sending over the network, shared params and more)
  465.                                         stack_string mods(modification);
  466.                                         mods = mods.replace(" ", "");
  467.                                         m_modifications = mods.c_str();
  468.                                 }
  469.                         }
  470.                 }
  471.         }
  472.  
  473.         if (m_paintName.empty())
  474.         {
  475.                 IScriptTable* pScriptTable = pEntity->GetScriptTable();
  476.                 if (pScriptTable)
  477.                 {
  478.                         SmartScriptTable pProps;
  479.                         if (pScriptTable->GetValue("Properties", pProps))
  480.                         {
  481.                                 const char* paint = 0;
  482.                                 if (pProps->GetValue("Paint", paint))
  483.                                         m_paintName = paint;
  484.                         }
  485.                 }
  486.         }
  487.  
  488.         // this merges modification data and must be done before further processing
  489.         //InitModification(xmlData, m_modification.c_str());
  490.         CVehicleModificationParams vehicleModificationParams(vehicleXmlData, m_modifications.c_str());
  491.         CVehicleParams vehicleParams(vehicleXmlData, vehicleModificationParams);
  492.  
  493.         vehicleParams.getAttr("isDestroyable", m_isDestroyable);
  494.  
  495.         // read physics properties
  496.  
  497.         if (CVehicleParams physicsTable = vehicleParams.findChild("Physics"))
  498.         {
  499.                 if (CVehicleParams buoyancyTable = physicsTable.findChild("Buoyancy"))
  500.                 {
  501.                         buoyancyTable.getAttr("waterDamping", m_buoyancyParams.waterDamping);
  502.                         buoyancyTable.getAttr("waterDensity", m_buoyancyParams.waterDensity);
  503.                         buoyancyTable.getAttr("waterResistance", m_buoyancyParams.waterResistance);
  504.                 }
  505.  
  506.                 physicsTable.getAttr("damping", m_simParams.damping);
  507.                 physicsTable.getAttr("dampingFreefall", m_simParams.dampingFreefall);
  508.                 physicsTable.getAttr("gravityFreefall", m_simParams.gravityFreefall);
  509.                 physicsTable.getAttr("retainGravity", m_bRetainGravity);
  510.  
  511.                 if (CVehicleParams simulationTable = physicsTable.findChild("Simulation"))
  512.                 {
  513.                         simulationTable.getAttr("maxTimeStep", m_simParams.maxTimeStep);
  514.                         simulationTable.getAttr("minEnergy", m_simParams.minEnergy);
  515.                         simulationTable.getAttr("maxLoggedCollisions", m_simParams.maxLoggedCollisions);
  516.  
  517.                         if (VehicleCVars().v_vehicle_quality == 1)
  518.                                 m_simParams.maxTimeStep = max(m_simParams.maxTimeStep, 0.04f);
  519.                 }
  520.  
  521.                 bool pushable = false;
  522.                 physicsTable.getAttr("pushable", pushable);
  523.                 if (!pushable)
  524.                         m_paramsFlags.flagsAND = ~pef_pushable_by_players;
  525.         }
  526.  
  527.         // load parts
  528.         SPartInitInfo partInitInfo;
  529.  
  530.         if (CVehicleParams partsTable = vehicleParams.findChild("Parts"))
  531.                 LoadParts(partsTable, NULL, partInitInfo);
  532.         else
  533.                 CryLog("%s: No Parts table found!", pEntity->GetName());
  534.  
  535.         for (TVehiclePartVector::iterator ite = m_parts.begin(); ite != m_parts.end(); ++ite)
  536.         {
  537.                 IVehiclePart* pPart = ite->second;
  538.                 pPart->ChangeState(IVehiclePart::eVGS_Default);
  539.         }
  540.  
  541.         InitHelpers(vehicleParams);
  542.  
  543.         // Init the mannequin data
  544.         CVehicleParams mannequinTable = vehicleParams.findChild("Mannequin");
  545.         if (mannequinTable && CVehicleCVars::Get().v_enableMannequin)
  546.         {
  547.                 m_vehicleAnimation.Initialise(*this, mannequinTable);
  548.         }
  549.  
  550.         // load the components (after the parts)
  551.         if (CVehicleParams componentsTable = vehicleParams.findChild("Components"))
  552.         {
  553.                 int componentCount = componentsTable.getChildCount();
  554.                 m_components.reserve(componentCount);
  555.  
  556.                 int i = 0;
  557.                 for (; i < componentCount; i++)
  558.                 {
  559.                         if (CVehicleParams componentTable = componentsTable.getChild(i))
  560.                         {
  561.                                 AddComponent(componentTable);
  562.                         }
  563.                 }
  564.  
  565.                 // register parts at their components
  566.                 for (std::vector<SPartComponentPair>::const_iterator it = partInitInfo.partComponentMap.begin(), end = partInitInfo.partComponentMap.end(); it != end; ++it)
  567.                 {
  568.                         CVehicleComponent* pVehicleComponent = static_cast<CVehicleComponent*>(GetComponent(it->component.c_str()));
  569.                         if (pVehicleComponent)
  570.                                 pVehicleComponent->AddPart(it->pPart);
  571.                 }
  572.         }
  573.  
  574.         InitParticles(vehicleParams); // must be after part init because it needs to find the helpers!
  575.  
  576.         // Init Animations
  577.         if (CVehicleParams animationsTable = vehicleParams.findChild("Animations"))
  578.         {
  579.                 int i = 0;
  580.                 int c = animationsTable.getChildCount();
  581.                 m_animations.reserve(c);
  582.  
  583.                 for (; i < c; i++)
  584.                 {
  585.                         if (CVehicleParams animTable = animationsTable.getChild(i))
  586.                         {
  587.                                 IVehicleAnimation* pVehicleAnimation = new CVehicleAnimation;
  588.  
  589.                                 if (animTable.haveAttr("name") && pVehicleAnimation->Init(this, animTable))
  590.                                         m_animations.push_back(TVehicleStringAnimationPair(animTable.getAttr("name"), pVehicleAnimation));
  591.                                 else
  592.                                         delete pVehicleAnimation;
  593.                         }
  594.                 }
  595.         }
  596.  
  597.         // Init the movement
  598.         if (CVehicleParams movementsTable = vehicleParams.findChild("MovementParams"))
  599.         {
  600.                 int i = 0;
  601.                 int c = movementsTable.getChildCount();
  602.  
  603.                 for (; i < c; i++)
  604.                 {
  605.                         if (CVehicleParams moveTable = movementsTable.getChild(i))
  606.                         {
  607.                                 if (!SetMovement(moveTable.getTag(), moveTable))
  608.                                         return false;
  609.                         }
  610.                 }
  611.         }
  612.  
  613.         // load the seats, if any
  614.         if (CVehicleParams seatsTable = vehicleParams.findChild("Seats"))
  615.         {
  616.                 int c = seatsTable.getChildCount();
  617.                 m_seats.reserve(c);
  618.  
  619.                 int i = 0;
  620.                 for (; i < c; i++)
  621.                 {
  622.                         if (CVehicleParams seatRef = seatsTable.getChild(i))
  623.                         {
  624.                                 CVehicleSeat* pVehicleSeat = new CVehicleSeat;
  625.                                 CRY_ASSERT(pVehicleSeat != NULL);
  626.  
  627.                                 if (seatRef.haveAttr("name") && pVehicleSeat)
  628.                                 {
  629.                                         if (pVehicleSeat->Init(this, m_seats.size() + 1, seatRef))
  630.                                         {
  631.                                                 m_seats.push_back(TVehicleSeatPair(seatRef.getAttr("name"), pVehicleSeat));
  632.                                         }
  633.                                         else
  634.                                         {
  635.                                                 SAFE_DELETE(pVehicleSeat);
  636.                                         }
  637.                                 }
  638.                         }
  639.                 }
  640.  
  641.                 m_transitionInfo.resize(c);
  642.  
  643.                 i = 0;
  644.                 for (; i < c; i++)
  645.                 {
  646.                         if (CVehicleParams seatRef = seatsTable.getChild(i))
  647.                         {
  648.                                 if (IVehicleSeat* pVehicleSeat = GetSeatById(i + 1))
  649.                                 {
  650.                                         STransitionInfo& info = m_transitionInfo[i];
  651.  
  652.                                         if (CVehicleParams transitionTable = seatRef.findChild("Transitions"))
  653.                                         {
  654.                                                 if (CVehicleParams waitTable = transitionTable.findChild("WaitFor"))
  655.                                                 {
  656.                                                         unsigned int waitCount = waitTable.getChildCount();
  657.                                                         info.waitFor.reserve(waitCount);
  658.  
  659.                                                         // if "Transitions" table is specified, read the seats from there.
  660.                                                         for (int w = 1, nWait = waitCount; w <= nWait; ++w)
  661.                                                         {
  662.                                                                 CVehicleParams waitRef = waitTable.getChild(w);
  663.  
  664.                                                                 TVehicleSeatId waitForId = GetSeatId(waitRef.getAttr("value"));
  665.                                                                 if (waitForId != InvalidVehicleSeatId)
  666.                                                                         info.waitFor.push_back(waitForId);
  667.                                                         }
  668.                                                 }
  669.                                         }
  670.                                         else
  671.                                         {
  672.                                                 // else add all seats that use the same exit helper as the current one
  673.                                                 for (TVehicleSeatVector::const_iterator it = m_seats.begin(), end = m_seats.end(); it != end; ++it)
  674.                                                 {
  675.                                                         if (it->second == pVehicleSeat)
  676.                                                                 continue;
  677.  
  678.                                                         if (IVehicleHelper* pHelper = it->second->GetExitHelper())
  679.                                                         {
  680.                                                                 if (pHelper == static_cast<CVehicleSeat*>(pVehicleSeat)->GetExitHelper())
  681.                                                                         info.waitFor.push_back(it->second->GetSeatId());
  682.                                                         }
  683.                                                 }
  684.                                         }
  685.                                 }
  686.                         }
  687.                 }
  688.         }
  689.  
  690.         if (CVehicleParams seatGroupsTable = vehicleParams.findChild("SeatGroups"))
  691.         {
  692.                 int c = seatGroupsTable.getChildCount();
  693.                 int i = 0;
  694.  
  695.                 m_seatGroups.reserve(c);
  696.  
  697.                 for (; i < c; i++)
  698.                 {
  699.                         if (CVehicleParams seatGroupTable = vehicleParams.getChild(i))
  700.                         {
  701.                                 CVehicleSeatGroup* pVehicleSeatGroup = new CVehicleSeatGroup;
  702.  
  703.                                 if (pVehicleSeatGroup->Init(this, seatGroupTable))
  704.                                         m_seatGroups.push_back(pVehicleSeatGroup);
  705.                                 else
  706.                                         delete pVehicleSeatGroup;
  707.                         }
  708.                 }
  709.         }
  710.  
  711.         if (CVehicleParams inventoryTable = vehicleParams.findChild("Inventory"))
  712.         {
  713.                 if (CVehicleParams ammosTable = inventoryTable.findChild("AmmoTypes"))
  714.                 {
  715.                         int i = 0;
  716.                         int c = ammosTable.getChildCount();
  717.  
  718.                         for (; i < c; i++)
  719.                         {
  720.                                 if (CVehicleParams ammoTable = ammosTable.getChild(i))
  721.                                 {
  722.                                         string type;
  723.                                         int capacity = 0;
  724.  
  725.                                         if ((type = ammoTable.getAttr("type")) && ammoTable.getAttr("capacity", capacity))
  726.                                         {
  727.                                                 IEntityClass* pClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(type);
  728.  
  729.                                                 if (pClass)
  730.                                                         SetAmmoCapacity(pClass, capacity);
  731.                                                 else
  732.                                                         GameWarning("Could not find entity class for ammo type '%s' when initializing vehicle '%s' of class '%s'", type.c_str(), pEntity->GetName(), className);
  733.                                         }
  734.                                 }
  735.                         }
  736.                 }
  737.         }
  738.        
  739.         InitPaint(vehicleParams);
  740.         InitActions(vehicleParams);
  741.  
  742.         m_actionMap = vehicleParams.getAttr("actionMap");
  743.  
  744.         pEntity->AddFlags(ENTITY_FLAG_CASTSHADOW | ENTITY_FLAG_CUSTOM_VIEWDIST_RATIO | ENTITY_FLAG_TRIGGER_AREAS);
  745.         //////////////////////////////////////////////////////////////////////////
  746.         {
  747.                 int viewDistRatio = DEFAULT_VEHICLE_VIEW_DIST_RATIO;
  748.                 vehicleParams.getAttr("viewDistRatio", viewDistRatio);
  749.                 pEntity->SetViewDistRatio(viewDistRatio);
  750.         }
  751.         //////////////////////////////////////////////////////////////////////////
  752.  
  753.         InitDamages(this, vehicleParams);
  754.  
  755. #if ENABLE_VEHICLE_DEBUG
  756.         if (VehicleCVars().v_debugdraw == eVDB_Parts)
  757.         {
  758.                 for (TVehiclePartVector::iterator it = m_parts.begin(); it != m_parts.end(); ++it)
  759.                 {
  760.                         if (CVehiclePartAnimated* pPart = CAST_VEHICLEOBJECT(CVehiclePartAnimated, it->second))
  761.                                 pPart->Dump();
  762.                 }
  763.         }
  764. #endif
  765.  
  766.         // calculate total damage
  767.         m_damageMax = 0.0f;
  768.         m_majorComponentDamageMax = 0.0f;
  769.         for (TVehicleComponentVector::iterator ite = m_components.begin(); ite != m_components.end(); ++ite)
  770.         {
  771.                 m_damageMax += (*ite)->GetMaxDamage();
  772.                 if ((*ite)->IsMajorComponent())
  773.                         m_majorComponentDamageMax += (*ite)->GetMaxDamage();
  774.         }
  775.  
  776.         // each component should also record the percentage it contributes to the total vehicle health
  777.         if (m_majorComponentDamageMax > 0)
  778.         {
  779.                 for (TVehicleComponentVector::iterator ite = m_components.begin(); ite != m_components.end(); ++ite)
  780.                 {
  781.                         if ((*ite)->IsMajorComponent())
  782.                         {
  783.                                 float proportion = (*ite)->GetMaxDamage() / m_majorComponentDamageMax;
  784.                                 (*ite)->SetProportionOfVehicleHealth(proportion);
  785.                         }
  786.                 }
  787.         }
  788.  
  789.         // attach seat scriptbinds
  790.         // this is done during OnSpawn when spawning initially, or here in case only the extension is created
  791.         for (TVehicleSeatVector::iterator it = m_seats.begin(); it != m_seats.end(); ++it)
  792.                 CCryAction::GetCryAction()->GetVehicleSeatScriptBind()->AttachTo(this, GetSeatId(it->second));
  793.  
  794.         if (0 == (pEntity->GetFlags() & (ENTITY_FLAG_CLIENT_ONLY | ENTITY_FLAG_SERVER_ONLY)))
  795.         {
  796.                 if (!GetGameObject()->BindToNetwork())
  797.                 {
  798.                         GameWarning("<%s> BindToNetwork failed", pEntity->GetName());
  799.                         return false;
  800.                 }
  801.         }
  802.  
  803.         if (VehicleCVars().v_serverControlled)
  804.         {
  805.                 pGameObject->EnableDelegatableAspect(eEA_Physics, false);
  806.         }
  807.  
  808.         return true;
  809. }
  810.  
  811. //------------------------------------------------------------------------
  812. void CVehicle::OnSpawnComplete()
  813. {
  814.         for (TVehicleSeatVector::iterator it = m_seats.begin(), end = m_seats.end(); it != end; ++it)
  815.         {
  816.                 it->second->OnSpawnComplete();
  817.         }
  818. }
  819.  
  820. //------------------------------------------------------------------------
  821. void CVehicle::InitPaint(const CVehicleParams& xmlContent)
  822. {
  823.         // check and apply "paint"
  824.         if (IScriptTable* pScriptTable = GetEntity()->GetScriptTable())
  825.         {
  826.                 if (CVehicleParams paintsTable = xmlContent.findChild("Paints"))
  827.                 {
  828.                         int i = 0;
  829.                         int c = paintsTable.getChildCount();
  830.  
  831.                         for (; i < c; i++)
  832.                         {
  833.                                 if (CVehicleParams paintRef = paintsTable.getChild(i))
  834.                                 {
  835.                                         const char* paintName = paintRef.getAttr("name");
  836.                                         if (!stricmp(paintName, m_paintName.c_str()))
  837.                                         {
  838.                                                 const char* paintMaterial = paintRef.getAttr("material");
  839.                                                 if (paintMaterial && paintMaterial[0])
  840.                                                 {
  841.                                                         m_pPaintMaterial = gEnv->p3DEngine->GetMaterialManager()->LoadMaterial(paintMaterial, false);
  842.                                                         if (m_pPaintMaterial)
  843.                                                                 GetEntity()->SetMaterial(m_pPaintMaterial);
  844.                                                         else
  845.                                                                 CryLog("[CVehicle::Paint] <%s> Material %s for Paint %s not found", GetEntity()->GetName(), paintMaterial, m_paintName.c_str());
  846.                                                 }
  847.  
  848.                                                 const char* destroyedMaterialName = paintRef.getAttr("materialDestroyed");
  849.                                                 if (destroyedMaterialName && destroyedMaterialName[0])
  850.                                                 {
  851.                                                         m_pDestroyedMaterial = gEnv->p3DEngine->GetMaterialManager()->LoadMaterial(destroyedMaterialName, false);
  852.                                                 }
  853.  
  854.                                                 break;
  855.                                         }
  856.                                 }
  857.                         }
  858.                 }
  859.         }
  860. }
  861.  
  862. //------------------------------------------------------------------------
  863. bool CVehicle::InitActions(const CVehicleParams& vehicleTable)
  864. {
  865.         CVehicleParams actionsTable = vehicleTable.findChild("Actions");
  866.         if (!actionsTable)
  867.                 return false;
  868.  
  869.         int c = actionsTable.getChildCount();
  870.         m_actions.reserve(c);
  871.  
  872.         for (int i = 0; i < c; i++)
  873.         {
  874.                 if (CVehicleParams actionRef = actionsTable.getChild(i))
  875.                 {
  876.                         if (actionRef.haveAttr("class"))
  877.                         {
  878.                                 string className = actionRef.getAttr("class");
  879.                                 if (IVehicleAction* pAction = m_pVehicleSystem->CreateVehicleAction(className))
  880.                                 {
  881.                                         if (pAction->Init(this, actionRef))
  882.                                         {
  883.                                                 m_actions.resize(m_actions.size() + 1);
  884.                                                 SVehicleActionInfo& actionInfo = m_actions.back();
  885.  
  886.                                                 actionInfo.pAction = pAction;
  887.  
  888.                                                 if (className == "Enter")
  889.                                                         m_usesVehicleActionToEnter = true;
  890.  
  891.                                                 actionInfo.useWhenFlipped = (className == "Flip") ? 1 : 0;
  892.  
  893.                                                 if (CVehicleParams activationsTable = actionRef.findChild("Activations"))
  894.                                                 {
  895.                                                         int numActivations = activationsTable.getChildCount();
  896.                                                         actionInfo.activations.resize(numActivations);
  897.  
  898.                                                         for (int n = 0; n < numActivations; n++)
  899.                                                         {
  900.                                                                 if (CVehicleParams activationRef = activationsTable.getChild(n))
  901.                                                                 {
  902.                                                                         SActivationInfo& activationInfo = actionInfo.activations[n];
  903.  
  904.                                                                         string type = activationRef.getAttr("type");
  905.                                                                         if (!type.empty())
  906.                                                                         {
  907.                                                                                 if (type == "OnUsed")
  908.                                                                                         activationInfo.m_type = SActivationInfo::eAT_OnUsed;
  909.                                                                                 else if (type == "OnGroundCollision")
  910.                                                                                         activationInfo.m_type = SActivationInfo::eAT_OnGroundCollision;
  911.                                                                         }
  912.  
  913.                                                                         string param1 = activationRef.getAttr("param1");
  914.                                                                         if (!param1.empty())
  915.                                                                         {
  916.                                                                                 if (param1 == "part")
  917.                                                                                         activationInfo.m_param1 = SActivationInfo::eAP1_Part;
  918.                                                                                 else if (param1 == "component")
  919.                                                                                         activationInfo.m_param1 = SActivationInfo::eAP1_Component;
  920.                                                                         }
  921.  
  922.                                                                         activationInfo.m_param2 = activationRef.getAttr("param2");
  923.  
  924.                                                                         if (!activationRef.getAttr("distance", activationInfo.m_distance))
  925.                                                                                 activationInfo.m_distance = 1.5f;
  926.                                                                 }
  927.                                                         }
  928.                                                 }
  929.                                         }
  930.                                         else
  931.                                         {
  932.                                                 // Failed to initialise this action (probably bad data...) so just free it
  933.                                                 pAction->Release();
  934.                                                 CryLog("Vehicle %s has an action defined (probably an 'Enter' action) that refers to a seat that doesn't exist.", vehicleTable.getAttr("name"));
  935.                                         }
  936.                                 }
  937.                         }
  938.                 }
  939.         }
  940.  
  941.         return true;
  942. }
  943.  
  944. //------------------------------------------------------------------------
  945. void CVehicle::PostInit(IGameObject* pGameObject)
  946. {
  947.         Veh::RegisterEvents(*this, *pGameObject);
  948.  
  949.         if (GetMovement())
  950.                 GetMovement()->PostInit();
  951.  
  952.         for (TVehiclePartVector::iterator ite = m_parts.begin(); ite != m_parts.end(); ++ite)
  953.         {
  954.                 IVehiclePart* part = ite->second;
  955.                 part->PostInit();
  956.         }
  957.  
  958.         pGameObject->EnablePhysicsEvent(true, eEPE_OnCollisionLogged | eEPE_OnStateChangeLogged);
  959.         //pGameObject->EnablePostUpdates(this);
  960.  
  961.         // not needed anymore - was required previously to make sure vehicle is not disabled when player drives
  962.         //  for (int i=0; i<MAX_UPDATE_SLOTS_PER_EXTENSION; ++i)
  963.         //    pGameObject->SetUpdateSlotEnableCondition(this, i, eUEC_WithoutAI);
  964.  
  965.         if (!gEnv->bServer)
  966.         {
  967.                 pGameObject->SetUpdateSlotEnableCondition(this, eVUS_Always, eUEC_VisibleOrInRangeIgnoreAI);
  968.                 pGameObject->SetUpdateSlotEnableCondition(this, eVUS_EnginePowered, eUEC_VisibleOrInRangeIgnoreAI);
  969.                 pGameObject->SetUpdateSlotEnableCondition(this, eVUS_PassengerIn, eUEC_VisibleOrInRangeIgnoreAI);
  970.         }
  971.  
  972.         pGameObject->SetUpdateSlotEnableCondition(this, eVUS_Visible, eUEC_Visible);
  973.         pGameObject->EnableUpdateSlot(this, eVUS_Visible);
  974.  
  975.         pGameObject->SetMovementController(GetMovementController());
  976.  
  977.         m_initialposition = GetEntity()->GetWorldPos();
  978.  
  979.         for (TVehicleSeatVector::iterator it = m_seats.begin(), end = m_seats.end(); it != end; ++it)
  980.         {
  981.                 it->second->PostInit(this);
  982.         }
  983.  
  984.         if (!CCryAction::GetCryAction()->IsEditing())
  985.                 NeedsUpdate();
  986. #if ENABLE_VEHICLE_DEBUG
  987.         else if (IsDebugDrawing())
  988.                 NeedsUpdate();
  989. #endif
  990.  
  991.         //  if (gEnv->bServer)
  992.         //    SendWeaponSetup(eRMI_ToRemoteClients);
  993.  
  994. #if ENABLE_VEHICLE_DEBUG
  995.         DumpParts();
  996.  
  997.         if (VehicleCVars().v_debug_mem > 0)
  998.         {
  999.                 ICrySizer* pSizer = gEnv->pSystem->CreateSizer();
  1000.                 GetMemoryUsage(pSizer);
  1001.                 int vehicleSize = pSizer->GetTotalSize();
  1002.                 CryLog("Vehicle initialized: <%s> takes %" PRISIZE_T " bytes.", GetEntity()->GetName(), pSizer->GetTotalSize());
  1003.  
  1004.                 pSizer->Release();
  1005.         }
  1006. #endif
  1007.  
  1008. }
  1009.  
  1010. //------------------------------------------------------------------------
  1011. void CVehicle::PostInitClient(int channelId)
  1012. {
  1013.         SendWeaponSetup(eRMI_ToClientChannel, channelId);
  1014. };
  1015.  
  1016. //------------------------------------------------------------------------
  1017. bool CVehicle::ReloadExtension(IGameObject* pGameObject, const SEntitySpawnParams& params)
  1018. {
  1019.         ResetGameObject();
  1020.  
  1021.         Veh::RegisterEvents(*this, *pGameObject);
  1022.  
  1023.         CRY_ASSERT_MESSAGE(false, "CVehicle::ReloadExtension not implemented");
  1024.  
  1025.         return false;
  1026. }
  1027.  
  1028. #if ENABLE_VEHICLE_DEBUG
  1029. //------------------------------------------------------------------------
  1030. void CVehicle::DumpParts() const
  1031. {
  1032.         if (VehicleCVars().v_debugdraw == eVDB_PhysParts || VehicleCVars().v_debugdraw == eVDB_PhysPartsExt)
  1033.         {
  1034.                 CryLog("============ %s =============", GetEntity()->GetName());
  1035.  
  1036.                 IPhysicalEntity* pPhysics = GetEntity()->GetPhysics();
  1037.                 pe_status_nparts nparts;
  1038.                 int numParts = pPhysics->GetStatus(&nparts);
  1039.                 CryLog("%i physical parts", numParts);
  1040.                 CryLog("------------------");
  1041.  
  1042.                 if (VehicleCVars().v_debugdraw == eVDB_PhysParts)
  1043.                 {
  1044.                         for (TVehiclePartVector::const_iterator ite = m_parts.begin(); ite != m_parts.end(); ++ite)
  1045.                         {
  1046.                                 IVehiclePart* part = ite->second;
  1047.                                 int status = -1;
  1048.                                 pe_params_part params;
  1049.  
  1050.                                 if (part->GetPhysId() != -1)
  1051.                                 {
  1052.                                         params.partid = part->GetPhysId();
  1053.                                         status = pPhysics->GetParams(&params);
  1054.                                 }
  1055.  
  1056.                                 CryLog("Part <%-25s>: slot %2i, physId %8i, status %i", part->GetName(), part->GetSlot(), part->GetPhysId(), status);
  1057.                         }
  1058.                 }
  1059.                 else
  1060.                 {
  1061.                         ICharacterInstance* pCharInstance = GetEntity()->GetCharacter(0);
  1062.                         ISkeletonPose* pSkeletonPose = pCharInstance ? pCharInstance->GetISkeletonPose() : 0;
  1063.                         IDefaultSkeleton& rIDefaultSkeleton = pCharInstance->GetIDefaultSkeleton();
  1064.  
  1065.                         for (int part = 0; part < numParts; ++part)
  1066.                         {
  1067.                                 pe_status_pos status;
  1068.                                 Matrix34 tm;
  1069.                                 status.ipart = part;
  1070.                                 status.pMtx3x4 = &tm;
  1071.                                 if (pPhysics->GetStatus(&status))
  1072.                                 {
  1073.                                         Vec3& min = status.BBox[0];
  1074.                                         Vec3& max = status.BBox[1];
  1075.                                         CryLog("Part [%i]: partId %i, min: (%.2f, %.2f, %.2f), max: (%.2f, %.2f, %.2f)", part, status.partid, min.x, min.y, min.z, max.x, max.y, max.z);
  1076.  
  1077.                                         {
  1078.                                                 // quadratic, but well, we're debugging
  1079.                                                 uint32 numJoints = rIDefaultSkeleton.GetJointCount();
  1080.                                                 for (uint32 i = 0; i < numJoints; ++i)
  1081.                                                 {
  1082.                                                         if (pSkeletonPose->GetPhysIdOnJoint(i) == status.partid)
  1083.                                                                 CryLog("partId %i matches Joint <%s>", status.partid, rIDefaultSkeleton.GetJointNameByID(i));
  1084.                                                 }
  1085.                                         }
  1086.  
  1087.                                         tm = GetEntity()->GetWorldTM().GetInverted() * tm;
  1088.                                         VehicleUtils::LogMatrix("", tm);
  1089.                                 }
  1090.                         }
  1091.                 }
  1092.         }
  1093. }
  1094. #endif
  1095.  
  1096. //------------------------------------------------------------------------
  1097. void CVehicle::SetAmmoCapacity(IEntityClass* pAmmoType, int capacity)
  1098. {
  1099.         if (m_pInventory)
  1100.                 m_pInventory->SetAmmoCapacity(pAmmoType, capacity);
  1101. }
  1102.  
  1103. //------------------------------------------------------------------------
  1104. void CVehicle::SetAmmoCount(IEntityClass* pAmmoType, int amount)
  1105. {
  1106.         if (m_pInventory)
  1107.         {
  1108.                 int oldAmount = m_pInventory->GetAmmoCount(pAmmoType);
  1109.                 m_pInventory->SetAmmoCount(pAmmoType, amount);
  1110.  
  1111.                 // if we didn't have any of this ammo before, and we do now, and we have a weapon inuse which uses this ammo type,
  1112.                 // then trigger a reload
  1113.                 if (oldAmount == 0 && amount != 0 && gEnv->IsClient())
  1114.                 {
  1115.                         if (IItemSystem* pItemSystem = gEnv->pGameFramework->GetIItemSystem())
  1116.                         {
  1117.                                 int weaponCount = GetWeaponCount();
  1118.                                 for (int i = 0; i < weaponCount; ++i)
  1119.                                 {
  1120.                                         IItem* pItem = pItemSystem->GetItem(GetWeaponId(i));
  1121.                                         if (pItem && pItem->GetOwnerId() == gEnv->pGameFramework->GetClientActorId())
  1122.                                         {
  1123.                                                 if (IWeapon* pWeapon = pItem->GetIWeapon())
  1124.                                                 {
  1125.                                                         if (IFireMode* pfm = pWeapon->GetFireMode(pWeapon->GetCurrentFireMode()))
  1126.                                                         {
  1127.                                                                 if (pfm->GetAmmoType() == pAmmoType)
  1128.                                                                 {
  1129.                                                                         pWeapon->Reload(false);
  1130.                                                                         float time = 0;
  1131.                                                                         float rate = pfm->GetFireRate();
  1132.                                                                         if (rate > 0.0f)
  1133.                                                                                 time = 60.0f / rate;
  1134.                                                                         pfm->SetNextShotTime(time);
  1135.                                                                         break;
  1136.                                                                 }
  1137.                                                         }
  1138.                                                 }
  1139.                                         }
  1140.                                 }
  1141.                         }
  1142.                 }
  1143.         }
  1144.  
  1145.         if (gEnv->bServer)
  1146.                 GetGameObject()->InvokeRMI(ClSetAmmo(), AmmoParams(pAmmoType->GetName(), amount), eRMI_ToRemoteClients);
  1147. }
  1148.  
  1149. //------------------------------------------------------------------------
  1150. int CVehicle::GetAmmoCount(IEntityClass* pAmmoType) const
  1151. {
  1152.         if (m_pInventory)
  1153.                 return m_pInventory->GetAmmoCount(pAmmoType);
  1154.  
  1155.         return 0;
  1156. }
  1157.  
  1158. //------------------------------------------------------------------------
  1159. SVehicleWeapon* CVehicle::GetVehicleWeaponAllSeats(EntityId weaponId) const
  1160. {
  1161.         SVehicleWeapon* pVehicleWeapon(NULL);
  1162.  
  1163.         TVehicleSeatVector::const_iterator iter = m_seats.begin();
  1164.         TVehicleSeatVector::const_iterator end = m_seats.end();
  1165.         while (iter != end)
  1166.         {
  1167.                 const TVehicleSeatActionVector& seatActions = iter->second->GetSeatActions();
  1168.  
  1169.                 TVehicleSeatActionVector::const_iterator seatActionsIter = seatActions.begin();
  1170.                 TVehicleSeatActionVector::const_iterator seatActionsEnd = seatActions.end();
  1171.                 while (seatActionsIter != seatActionsEnd)
  1172.                 {
  1173.                         if (CVehicleSeatActionWeapons* weapAction = CAST_VEHICLEOBJECT(CVehicleSeatActionWeapons, seatActionsIter->pSeatAction))
  1174.                         {
  1175.                                 if (pVehicleWeapon = weapAction->GetVehicleWeapon(weaponId))
  1176.                                 {
  1177.                                         return pVehicleWeapon;
  1178.                                 }
  1179.                         }
  1180.  
  1181.                         ++seatActionsIter;
  1182.                 }
  1183.  
  1184.                 ++iter;
  1185.         }
  1186.  
  1187.         return NULL;
  1188. }
  1189.  
  1190. //------------------------------------------------------------------------
  1191. void CVehicle::SendWeaponSetup(int where, int channelId)
  1192. {
  1193.         SetupWeaponsParams params;
  1194.         for (TVehicleSeatVector::iterator it = m_seats.begin(); it != m_seats.end(); ++it)
  1195.         {
  1196.                 SetupWeaponsParams::SeatWeaponParams seatparams;
  1197.                 const CVehicleSeat* pSeat = it->second;
  1198.  
  1199.                 const TVehicleSeatActionVector& seatActions = pSeat->GetSeatActions();
  1200.                 for (TVehicleSeatActionVector::const_iterator ait = seatActions.begin(), aitEnd = seatActions.end(); ait != aitEnd; ++ait)
  1201.                 {
  1202.                         IVehicleSeatAction* pSeatAction = ait->pSeatAction;
  1203.                         if (CVehicleSeatActionWeapons* weapAction = CAST_VEHICLEOBJECT(CVehicleSeatActionWeapons, pSeatAction))
  1204.                         {
  1205.                                 SetupWeaponsParams::SeatWeaponParams::SeatActionWeaponParams actionParams;
  1206.  
  1207.                                 int n = weapAction->GetWeaponCount();
  1208.                                 for (int w = 0; w < n; w++)
  1209.                                         actionParams.weapons.push_back(weapAction->GetWeaponEntityId(w));
  1210.  
  1211.                                 seatparams.seatactions.push_back(actionParams);
  1212.                         }
  1213.                 }
  1214.  
  1215.                 params.seats.push_back(seatparams);
  1216.         }
  1217.  
  1218.         GetGameObject()->InvokeRMI(ClSetupWeapons(), params, where, channelId);
  1219. }
  1220.  
  1221. //------------------------------------------------------------------------
  1222. TVehicleSoundEventId CVehicle::AddSoundEvent(SVehicleSoundInfo& info)
  1223. {
  1224.         m_soundEvents.push_back(info);
  1225.  
  1226.         return TVehicleSoundEventId(m_soundEvents.size() - 1);
  1227. }
  1228.  
  1229. //------------------------------------------------------------------------
  1230. void CVehicle::ProcessEvent(SEntityEvent& entityEvent)
  1231. {
  1232.         switch (entityEvent.event)
  1233.         {
  1234.         case ENTITY_EVENT_RESET:
  1235.                 Reset(entityEvent.nParam[0] == 1 ? true : false);
  1236.                 break;
  1237.  
  1238.         case ENTITY_EVENT_DONE:
  1239.                 {
  1240.                         // Passengers should exit now.
  1241.                         for (TVehicleSeatVector::iterator it = m_seats.begin(), end = m_seats.end(); it != end; ++it)
  1242.                         {
  1243.                                 if (it->second->GetPassenger())
  1244.                                         it->second->Exit(false, true);
  1245.                         }
  1246.  
  1247.                         DeleteActionController();
  1248.                 }
  1249.                 break;
  1250.  
  1251.         case ENTITY_EVENT_TIMER:
  1252.                 OnTimer((int)entityEvent.nParam[0]);
  1253.                 break;
  1254.  
  1255.         case ENTITY_EVENT_MATERIAL_LAYER:
  1256.                 OnMaterialLayerChanged(entityEvent);
  1257.                 break;
  1258.  
  1259.         case ENTITY_EVENT_HIDE:
  1260.         case ENTITY_EVENT_UNHIDE:
  1261.                 {
  1262.                         SVehicleEventParams eventParams;
  1263.  
  1264.                         eventParams.iParam = entityEvent.event == ENTITY_EVENT_HIDE;
  1265.  
  1266.                         BroadcastVehicleEvent(eVE_Hide, eventParams);
  1267.                 }
  1268.                 break;
  1269.         case ENTITY_EVENT_ANIM_EVENT:
  1270.                 {
  1271.                         if (IActionController* pActionController = GetAnimationComponent().GetActionController())
  1272.                         {
  1273.                                 const AnimEventInstance* pAnimEvent = reinterpret_cast<const AnimEventInstance*>(entityEvent.nParam[0]);
  1274.                                 ICharacterInstance* pCharacter = reinterpret_cast<ICharacterInstance*>(entityEvent.nParam[1]);
  1275.                                 if (pAnimEvent && pCharacter)
  1276.                                 {
  1277.                                         pActionController->OnAnimationEvent(pCharacter, *pAnimEvent);
  1278.                                 }
  1279.                         }
  1280.                 }
  1281.                 break;
  1282.         case ENTITY_EVENT_PREPHYSICSUPDATE:
  1283.                 {
  1284.                         for (TVehicleSeatVector::iterator ite = m_seats.begin(); ite != m_seats.end(); ++ite)
  1285.                         {
  1286.                                 ite->second->PrePhysUpdate(gEnv->pTimer->GetFrameTime());
  1287.                         }
  1288.                 }
  1289.                 break;
  1290.         }
  1291.  
  1292.         if (m_pMovement)
  1293.                 m_pMovement->ProcessEvent(entityEvent);
  1294. }
  1295.  
  1296. uint64 CVehicle::GetEventMask() const
  1297. {
  1298.         return
  1299.                 BIT64(ENTITY_EVENT_RESET) |
  1300.                 BIT64(ENTITY_EVENT_DONE) |
  1301.                 BIT64(ENTITY_EVENT_TIMER) |
  1302.                 BIT64(ENTITY_EVENT_MATERIAL_LAYER) |
  1303.                 BIT64(ENTITY_EVENT_HIDE) |
  1304.                 BIT64(ENTITY_EVENT_UNHIDE) |
  1305.                 BIT64(ENTITY_EVENT_ANIM_EVENT) |
  1306.                 BIT64(ENTITY_EVENT_PREPHYSICSUPDATE);
  1307. }
  1308.  
  1309. //------------------------------------------------------------------------
  1310. void CVehicle::DeleteActionController()
  1311. {
  1312.         GetAnimationComponent().DeleteActionController();
  1313.         for (TVehicleSeatVector::iterator ite = m_seats.begin(), end = m_seats.end(); ite != end; ++ite)
  1314.         {
  1315.                 CVehicleSeat* seat = ite->second;
  1316.                 seat->OnVehicleActionControllerDeleted();
  1317.         }
  1318. }
  1319.  
  1320. //------------------------------------------------------------------------
  1321. void CVehicle::OnMaterialLayerChanged(const SEntityEvent& event)
  1322. {
  1323.         // only handle frozen layer for now.
  1324.         bool frozen = event.nParam[0] & MTL_LAYER_FROZEN;
  1325.         bool prev = event.nParam[1] & MTL_LAYER_FROZEN;
  1326.         if (frozen != prev)
  1327.         {
  1328.                 int n = GetEntity()->GetChildCount();
  1329.                 for (int i = 0; i < n; ++i)
  1330.                 {
  1331.                         IEntity* pChild = GetEntity()->GetChild(i);
  1332.                         IEntityRender* pIEntityRender = pChild->GetRenderInterface();
  1333.                        
  1334.                         {
  1335.                                 if (IActor* pActor = CCryAction::GetCryAction()->GetIActorSystem()->GetActor(pChild->GetId()))
  1336.                                         if (pActor->IsPlayer()) // don't freeze players inside vehicles
  1337.                                                 continue;
  1338.  
  1339.                                 //uint8 mask = pIEntityRender->GetMaterialLayersMask();
  1340.                                 //pIEntityRender->SetMaterialLayersMask(frozen ? mask | MTL_LAYER_FROZEN : mask & ~MTL_LAYER_FROZEN);
  1341.                         }
  1342.                 }
  1343.         }
  1344. }
  1345.  
  1346. //------------------------------------------------------------------------
  1347. int CVehicle::SetTimer(int timerId, int ms, IVehicleObject* pObject)
  1348. {
  1349.         if (timerId == -1)
  1350.         {
  1351.                 if (!m_timers.empty())
  1352.                 {
  1353.                         TVehicleTimerMap::const_reverse_iterator last = m_timers.rbegin();
  1354.                         timerId = last->first + 1;
  1355.                 }
  1356.                 else
  1357.                         timerId = eVT_Last;
  1358.         }
  1359.         else
  1360.                 KillTimer(timerId);
  1361.  
  1362.         if (m_timers.insert(std::make_pair(timerId, pObject)).second)
  1363.         {
  1364.                 GetEntity()->SetTimer(timerId, ms);
  1365.                 //CryLog("vehicle <%s> setting timer %i, %i ms", GetEntity()->GetName(), timerId, ms);
  1366.  
  1367.                 return timerId;
  1368.         }
  1369.  
  1370.         return -1;
  1371. }
  1372.  
  1373. //------------------------------------------------------------------------
  1374. int CVehicle::KillTimer(int timerId)
  1375. {
  1376.         if (timerId != -1)
  1377.         {
  1378.                 GetEntity()->KillTimer(timerId);
  1379.                 m_timers.erase(timerId);
  1380.         }
  1381.  
  1382.         return -1;
  1383. }
  1384.  
  1385. //------------------------------------------------------------------------
  1386. void CVehicle::KillTimers()
  1387. {
  1388.         KillAbandonedTimer();
  1389.  
  1390.         GetEntity()->KillTimer(-1);
  1391.         m_timers.clear();
  1392. }
  1393.  
  1394. //------------------------------------------------------------------------
  1395. void CVehicle::OnTimer(int timerId)
  1396. {
  1397.         TVehicleTimerMap::iterator it = m_timers.find(timerId);
  1398.         if (it != m_timers.end())
  1399.         {
  1400.                 IVehicleObject* pObject = it->second;
  1401.                 m_timers.erase(it);
  1402.  
  1403.                 if (pObject)
  1404.                 {
  1405.                         SVehicleEventParams params;
  1406.                         params.iParam = timerId;
  1407.                         pObject->OnVehicleEvent(eVE_Timer, params);
  1408.                 }
  1409.         }
  1410.  
  1411.         switch (timerId)
  1412.         {
  1413.         case eVT_Abandoned:
  1414.                 Destroy();
  1415.                 break;
  1416.         case eVT_AbandonedSound:
  1417.                 EnableAbandonedWarnSound(true);
  1418.                 break;
  1419.         case eVT_Flipped:
  1420.                 ProcessFlipped();
  1421.                 break;
  1422.         }
  1423. }
  1424.  
  1425. void CVehicle::Reset(bool enterGame)
  1426. {
  1427.         KillTimers();
  1428.  
  1429.         m_vehicleAnimation.Reset();
  1430.  
  1431.         m_ownerId = 0;
  1432.  
  1433.         // disable engine slot in case it was enabled by speed threshold
  1434.         if (m_customEngineSlot)
  1435.         {
  1436.                 GetGameObject()->DisableUpdateSlot(this, eVUS_EnginePowered);
  1437.                 m_customEngineSlot = false;
  1438.         }
  1439.  
  1440.         ResetDamages();
  1441.  
  1442.         for (TVehiclePartVector::iterator ite = m_parts.begin(); ite != m_parts.end(); ++ite)
  1443.         {
  1444.                 IVehiclePart* part = ite->second;
  1445.                 part->Reset();
  1446.         }
  1447.  
  1448.         for (TVehicleSeatVector::iterator ite = m_seats.begin(); ite != m_seats.end(); ++ite)
  1449.         {
  1450.                 CVehicleSeat* pSeat = ite->second;
  1451.                 pSeat->Reset();
  1452.         }
  1453.  
  1454.         for (TVehicleComponentVector::iterator ite = m_components.begin(); ite != m_components.end(); ++ite)
  1455.         {
  1456.                 CVehicleComponent* pComponent = *ite;
  1457.                 pComponent->Reset();
  1458.         }
  1459.  
  1460.         for (TVehicleAnimationsVector::iterator ite = m_animations.begin(); ite != m_animations.end(); ++ite)
  1461.         {
  1462.                 IVehicleAnimation* pAnimation = ite->second;
  1463.                 pAnimation->Reset();
  1464.         }
  1465.  
  1466.         for (TVehicleActionVector::iterator ite = m_actions.begin(); ite != m_actions.end(); ++ite)
  1467.         {
  1468.                 SVehicleActionInfo& actionInfo = *ite;
  1469.                 actionInfo.pAction->Reset();
  1470.         }
  1471.  
  1472.         for (TVehicleSoundEventId id = 0; id < m_soundEvents.size(); ++id)
  1473.                 StopSound(id);
  1474.  
  1475.         m_isDestroyed = false;
  1476.         m_status.Reset();
  1477.  
  1478.         m_initialposition = GetEntity()->GetWorldPos();
  1479.  
  1480.         DoRequestedPhysicalization();
  1481.  
  1482.         if (enterGame)
  1483.         {
  1484.                 // activate when going to game, to adjust vehicle to terrain etc.
  1485.                 // will be deactivated some frames later
  1486.                 NeedsUpdate(eVUF_AwakePhysics);
  1487.  
  1488.                 // Temp Code, testing only
  1489.                 AudioControlId engineAudioTriggerId;
  1490.                 if (gEnv->pAudioSystem->GetAudioTriggerId("ENGINE_ON", engineAudioTriggerId))
  1491.                 {
  1492.                         m_pIEntityAudioComponent->ExecuteTrigger(engineAudioTriggerId);
  1493.                 }
  1494.         }
  1495.         else
  1496.         {
  1497.                 m_bNeedsUpdate = false;
  1498.  
  1499.                 for (int i = 0; i < eVUS_Last; ++i)
  1500.                 {
  1501.                         while (GetGameObject()->GetUpdateSlotEnables(this, i) > 0)
  1502.                                 GetGameObject()->DisableUpdateSlot(this, i);
  1503.                 }
  1504.  
  1505.                 // Temp Code, testing only
  1506.                 AudioControlId engineAudioTriggerId;
  1507.                 if (gEnv->pAudioSystem->GetAudioTriggerId("ENGINE_OFF", engineAudioTriggerId))
  1508.                 {
  1509.                         m_pIEntityAudioComponent->ExecuteTrigger(engineAudioTriggerId);
  1510.                 }
  1511.         }
  1512.  
  1513.         m_collisionDisabledTime = 0.0f;
  1514.         m_physUpdateTime = 0.f;
  1515.         m_indestructible = false;
  1516.  
  1517.         m_predictionHistory.clear();
  1518. #if ENABLE_VEHICLE_DEBUG
  1519.         m_debugClientPredictData.clear();
  1520. #endif
  1521. }
  1522.  
  1523. //------------------------------------------------------------------------
  1524. void CVehicle::RequestPhysicalization(IVehiclePart* pPart, bool request)
  1525. {
  1526.         if (request)
  1527.                 m_physicalizeParts.insert(pPart);
  1528.         else
  1529.                 stl::find_and_erase(m_physicalizeParts, pPart);
  1530. }
  1531.  
  1532. //------------------------------------------------------------------------
  1533. void CVehicle::DoRequestedPhysicalization()
  1534. {
  1535.         if (!m_physicalizeParts.empty())
  1536.         {
  1537.                 TVehiclePartSet parts(m_physicalizeParts);
  1538.                 for (TVehiclePartSet::iterator it = parts.begin(), end = parts.end(); it != end; ++it)
  1539.                 {
  1540.                         (*it)->Physicalize();
  1541.                 }
  1542.  
  1543.                 m_physicalizeParts.clear();
  1544.         }
  1545. }
  1546.  
  1547. //------------------------------------------------------------------------
  1548. void CVehicle::Update(SEntityUpdateContext& ctx, int slot)
  1549. {
  1550.         FUNCTION_PROFILER(GetISystem(), PROFILE_ACTION);
  1551.  
  1552. #if ENABLE_VEHICLE_DEBUG
  1553.         gEnv->pAuxGeomRenderer->SetRenderFlags(e_Def3DPublicRenderflags);
  1554. #endif
  1555.  
  1556.         const float frameTime = ctx.fFrameTime;
  1557.         if (ctx.nFrameID != m_lastFrameId)
  1558.         {
  1559.                 m_bNeedsUpdate = false;
  1560.                 m_lastFrameId = ctx.nFrameID;
  1561.         }
  1562.  
  1563.         switch (slot)
  1564.         {
  1565.         case eVUS_Always:
  1566.                 {
  1567. #if ENABLE_VEHICLE_DEBUG
  1568.                         m_debugIndex = 0;
  1569. #endif
  1570.  
  1571.                         if (!GetEntity()->GetPhysics())
  1572.                                 return;
  1573.  
  1574.                         UpdateStatus(frameTime);
  1575.                         UpdateDamages(frameTime);
  1576.  
  1577.                         for (TVehicleObjectUpdateInfoList::iterator ite = m_objectsToUpdate.begin(), end = m_objectsToUpdate.end(); ite != end; ++ite)
  1578.                         {
  1579.                                 SObjectUpdateInfo& updateInfo = *ite;
  1580.                                 if (updateInfo.updatePolicy == eVOU_AlwaysUpdate)
  1581.                                         updateInfo.pObject->Update(frameTime);
  1582.                         }
  1583.  
  1584.                         if (m_collisionDisabledTime > 0.0f)
  1585.                                 m_collisionDisabledTime -= frameTime;
  1586.  
  1587.                         m_vehicleAnimation.Update(frameTime);
  1588.  
  1589.                         if (m_hasAuthority && !gEnv->bServer && VehicleCVars().v_serverControlled && VehicleCVars().v_clientPredict)
  1590.                         {
  1591.                                 const INetChannel* pNetChannel = gEnv->pGameFramework->GetClientChannel();
  1592.                                 if (pNetChannel)
  1593.                                 {
  1594.                                         m_smoothedPing = pNetChannel->GetPing(true);
  1595.                                 }
  1596.                         }
  1597.                 }
  1598.                 break;
  1599.  
  1600.         case eVUS_EnginePowered:
  1601.                 {
  1602.                         if (m_pMovement)
  1603.                         {
  1604.                                 NeedsUpdate();
  1605.                                 m_pMovement->Update(frameTime);
  1606.                         }
  1607.  
  1608.                         break;
  1609.                 }
  1610.         case eVUS_AIControlled:
  1611.                 {
  1612.                         NeedsUpdate();
  1613.  
  1614.                         for (TVehicleSeatVector::iterator ite = m_seats.begin(), end = m_seats.end(); ite != end; ++ite)
  1615.                         {
  1616.                                 CVehicleSeat* seat = ite->second;
  1617.  
  1618.                                 if (CVehicleSeatActionWeapons* weapons = seat->GetSeatActionWeapons())
  1619.                                 {
  1620.                                         seat->Update(frameTime);
  1621.                                 }
  1622.                         }
  1623.                 }
  1624.                 break;
  1625.  
  1626.         case eVUS_PassengerIn:
  1627.                 {
  1628.                         NeedsUpdate();
  1629.  
  1630.                         for (TVehicleSeatVector::iterator ite = m_seats.begin(), end = m_seats.end(); ite != end; ++ite)
  1631.                         {
  1632.                                 CVehicleSeat* seat = ite->second;
  1633.                                 seat->Update(frameTime);
  1634.                         }
  1635.  
  1636.                         for (TVehicleObjectUpdateInfoList::iterator ite = m_objectsToUpdate.begin(), end = m_objectsToUpdate.end(); ite != end; ++ite)
  1637.                         {
  1638.                                 SObjectUpdateInfo& updateInfo = *ite;
  1639.                                 if (updateInfo.updatePolicy == eVOU_PassengerUpdate)
  1640.                                         updateInfo.pObject->Update(frameTime);
  1641.                         }
  1642.  
  1643.                         break;
  1644.                 }
  1645.  
  1646.         case eVUS_Visible:
  1647.                 {
  1648.                         for (TVehicleObjectUpdateInfoList::iterator ite = m_objectsToUpdate.begin(), end = m_objectsToUpdate.end(); ite != end; ++ite)
  1649.                         {
  1650.                                 SObjectUpdateInfo& updateInfo = *ite;
  1651.                                 if (updateInfo.updatePolicy == eVOU_Visible)
  1652.                                         updateInfo.pObject->Update(frameTime);
  1653.                         }
  1654.  
  1655. #if ENABLE_VEHICLE_DEBUG
  1656.                         DebugDraw(frameTime);
  1657. #endif
  1658.                 }
  1659.         }
  1660.  
  1661.         CheckDisableUpdate(slot);
  1662.  
  1663.         m_physUpdateTime = 0.f;
  1664. }
  1665.  
  1666. void CVehicle::UpdatePassenger(float frameTime, EntityId playerId)
  1667. {
  1668.         for (uint32 updatePolicy = 0; updatePolicy <= eVUS_Last; ++updatePolicy)
  1669.         {
  1670.                 for (TVehicleObjectUpdateInfoList::iterator ite = m_objectsToUpdate.begin(), end = m_objectsToUpdate.end(); ite != end; ++ite)
  1671.                 {
  1672.                         SObjectUpdateInfo& updateInfo = *ite;
  1673.                         if (updateInfo.updatePolicy == updatePolicy)
  1674.                         {
  1675.                                 updateInfo.pObject->UpdateFromPassenger(frameTime, playerId);
  1676.                         }
  1677.                 }
  1678.         }
  1679. }
  1680.  
  1681. //------------------------------------------------------------------------
  1682. void CVehicle::PostUpdate(float frameTime)
  1683. {
  1684.         //DebugDraw(frameTime);
  1685.  
  1686.         // Force update of passenger transform matrices.
  1687.  
  1688.         IEntitySystem* pEntitySystem = gEnv->pEntitySystem;
  1689.  
  1690.         for (TVehicleSeatVector::const_iterator iSeat = m_seats.begin(), iEndSeat = m_seats.end(); iSeat != iEndSeat; ++iSeat)
  1691.         {
  1692.                 const CVehicleSeat* pVehicleSeat = iSeat->second;
  1693.                 if (!pVehicleSeat->IsRemoteControlled())
  1694.                 {
  1695.                         if (IEntity* pPassengerEntity = pEntitySystem->GetEntity(pVehicleSeat->GetPassenger()))
  1696.                         {
  1697.                                 pPassengerEntity->InvalidateTM(ENTITY_XFORM_FROM_PARENT);
  1698.                         }
  1699.                 }
  1700.         }
  1701. }
  1702.  
  1703. //------------------------------------------------------------------------
  1704. void CVehicle::NeedsUpdate(int flags, bool bThreadSafe /*=false*/)
  1705. {
  1706.         m_bNeedsUpdate = true;
  1707.  
  1708.         if (0 == GetGameObject()->GetUpdateSlotEnables(this, eVUS_Always))
  1709.         {
  1710.                 // enable, if necessary
  1711.                 GetGameObject()->EnableUpdateSlot(this, eVUS_Always);
  1712.         }
  1713.  
  1714.         if (flags & eVUF_AwakePhysics)
  1715.         {
  1716.                 if (IPhysicalEntity* pPE = GetEntity()->GetPhysics())
  1717.                 {
  1718.                         pe_action_awake awakeParams;
  1719.                         awakeParams.bAwake = 1;
  1720.                         // keep vehicle awake for a bit to keep it from sleeping when it is going from positive to negative acceleration
  1721.                         awakeParams.minAwakeTime = 2.0f;
  1722.                         pPE->Action(&awakeParams, (int)bThreadSafe);
  1723.                 }
  1724.         }
  1725. }
  1726.  
  1727. //------------------------------------------------------------------------
  1728. void CVehicle::CheckDisableUpdate(int slot)
  1729. {
  1730.         if (m_bNeedsUpdate)
  1731.                 return;
  1732.  
  1733.         if (0 == CVehicleCVars::Get().v_autoDisable)
  1734.                 return;
  1735.  
  1736. #if ENABLE_VEHICLE_DEBUG
  1737.         if (IsDebugDrawing())
  1738.                 return;
  1739. #endif
  1740.  
  1741.         // check after last updated slot if we can be disabled
  1742.         for (int i = eVUS_Visible - 1; i >= 0; --i)
  1743.         {
  1744.                 if (GetGameObject()->GetUpdateSlotEnables(this, i))
  1745.                 {
  1746.                         if (slot >= i)
  1747.                         {
  1748.                                 if (IPhysicalEntity* pPhysics = GetEntity()->GetPhysics())
  1749.                                 {
  1750.                                         pe_status_pos status;
  1751.                                         if (pPhysics->GetStatus(&status) && status.iSimClass > 1)
  1752.                                                 break;
  1753.                                 }
  1754.  
  1755.                                 GetGameObject()->DisableUpdateSlot(this, eVUS_Always);
  1756.                         }
  1757.                         break;
  1758.                 }
  1759.         }
  1760. }
  1761.  
  1762. //------------------------------------------------------------------------
  1763. void CVehicle::OnPhysStateChange(EventPhysStateChange* pEvent)
  1764. {
  1765.         if (pEvent->iSimClass[0] < 2 && pEvent->iSimClass[1] > 1)
  1766.         {
  1767.                 // awakened
  1768.                 NeedsUpdate();
  1769.  
  1770.                 SVehicleEventParams params;
  1771.                 BroadcastVehicleEvent(eVE_Awake, params);
  1772.         }
  1773.         else if (pEvent->iSimClass[0] > 1 && pEvent->iSimClass[1] < 2)
  1774.         {
  1775.                 // falling asleep
  1776.  
  1777.                 // do one update pass on visibility-based objects
  1778.                 for (TVehicleObjectUpdateInfoList::iterator ite = m_objectsToUpdate.begin(); ite != m_objectsToUpdate.end(); ++ite)
  1779.                 {
  1780.                         SObjectUpdateInfo& updateInfo = *ite;
  1781.                         if (updateInfo.updatePolicy == eVOU_Visible)
  1782.                                 updateInfo.pObject->Update(0.f);
  1783.                 }
  1784.  
  1785.                 SVehicleEventParams params;
  1786.                 BroadcastVehicleEvent(eVE_Sleep, params);
  1787.         }
  1788. }
  1789.  
  1790. #if ENABLE_VEHICLE_DEBUG
  1791. //------------------------------------------------------------------------
  1792. void CVehicle::DebugDraw(const float frameTime)
  1793. {
  1794.         if (IsDebugDrawing())
  1795.                 NeedsUpdate();
  1796.  
  1797.         if (GetEntity()->GetWorldPos().GetSquaredDistance(gEnv->pSystem->GetViewCamera().GetPosition()) > sqr(100.f))
  1798.                 return;
  1799.  
  1800.         CVehicleCVars& cvars = CVehicleCVars::Get();
  1801.  
  1802.         if (cvars.v_draw_components)
  1803.         {
  1804.                 for (TVehicleComponentVector::const_iterator ite = m_components.begin(); ite != m_components.end(); ++ite)
  1805.                 {
  1806.                         CVehicleComponent* pComponent = *ite;
  1807.                         pComponent->DebugDraw();
  1808.                 }
  1809.         }
  1810.  
  1811.         if (cvars.v_debugdraw == eVDB_Parts)
  1812.         {
  1813.                 static float drawColor[4] = { 1, 1, 1, 1 };
  1814.  
  1815.                 for (TVehiclePartVector::iterator ite = m_parts.begin(); ite != m_parts.end(); ++ite)
  1816.                 {
  1817.                         IRenderAuxText::DrawLabelExF(ite->second->GetWorldTM().GetTranslation(), 1.0f, drawColor, true, true, "<%s>", ite->first.c_str());
  1818.  
  1819.                         /*IRenderAuxGeom* pGeom = gEnv->pRenderer->GetIRenderAuxGeom();
  1820.                            AABB bounds = AABB::CreateTransformedAABB(ite->second->GetWorldTM(), ite->second->GetLocalBounds());
  1821.                            ColorB col(0,255,0,255);
  1822.                            pGeom->DrawAABB(bounds, false, col, eBBD_Extremes_Color_Encoded);*/
  1823.                 }
  1824.         }
  1825.         else if (cvars.v_debugdraw == eVDB_PhysPartsExt)
  1826.         {
  1827.                 for (TVehiclePartVector::iterator iPart = m_parts.begin(), iEnd = m_parts.end(); iPart != iEnd; ++iPart)
  1828.                 {
  1829.                         if (IVehiclePart* pPart = iPart->second)
  1830.                         {
  1831.                                 const Matrix34& partWorldTM = pPart->GetWorldTM();
  1832.  
  1833.                                 {
  1834.                                         const float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
  1835.  
  1836.                                         IRenderAuxText::DrawLabelExF(partWorldTM.GetTranslation(), 1.0f, color, true, true, "<%s>", iPart->first.c_str());
  1837.                                 }
  1838.  
  1839.                                 if (IRenderAuxGeom* pRenderAuxGeom = gEnv->pRenderer->GetIRenderAuxGeom())
  1840.                                 {
  1841.                                         pRenderAuxGeom->DrawAABB(pPart->GetLocalBounds(), GetEntity()->GetWorldTM(), false, ColorB(255, 255, 255, 255), eBBD_Extremes_Color_Encoded);
  1842.  
  1843.                                         const Vec3 partWorldTranslation = partWorldTM.GetTranslation();
  1844.  
  1845.                                         pRenderAuxGeom->DrawLine(partWorldTranslation, ColorB(255, 0, 0, 255), partWorldTranslation + partWorldTM.GetColumn0(), ColorB(255, 0, 0, 255), 1.0f);
  1846.                                         pRenderAuxGeom->DrawLine(partWorldTranslation, ColorB(0, 255, 0, 255), partWorldTranslation + partWorldTM.GetColumn1(), ColorB(0, 255, 0, 255), 1.0f);
  1847.                                         pRenderAuxGeom->DrawLine(partWorldTranslation, ColorB(0, 0, 255, 255), partWorldTranslation + partWorldTM.GetColumn2(), ColorB(0, 0, 255, 255), 1.0f);
  1848.                                 }
  1849.                         }
  1850.                 }
  1851.         }
  1852.         else if (cvars.v_debugdraw == eVDB_Damage)
  1853.         {
  1854.                 const float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
  1855.                 float damageRatio = GetDamageRatio();
  1856.                 string damageStr;
  1857.                 damageStr.Format("Health: %.2f/%.2f Damage Ratio: %.2f", m_damageMax * (1.f - damageRatio), m_damageMax, damageRatio);
  1858.                 IRenderAuxText::DrawLabelEx(GetEntity()->GetWorldPos() + Vec3(0.f, 0.f, 1.f), 1.5f, color, true, true, damageStr.c_str());
  1859.         }
  1860.         else if (cvars.v_debugdraw == eVDB_ClientPredict)
  1861.         {
  1862.                 DebugDrawClientPredict();
  1863.         }
  1864.  
  1865.         if (cvars.v_draw_helpers)
  1866.         {
  1867.                 static float drawColor[4] = { 1, 0, 0, 1 };
  1868.  
  1869.                 CPersistantDebug* pDB = CCryAction::GetCryAction()->GetPersistantDebug();
  1870.                 CryFixedStringT<32> dbgName;
  1871.                 dbgName.Format("VehicleHelpers_%s", GetEntity()->GetName());
  1872.                 pDB->Begin(dbgName.c_str(), true);
  1873.                 for (TVehicleHelperMap::const_iterator ite = m_helpers.begin(); ite != m_helpers.end(); ++ite)
  1874.                 {
  1875.                         Matrix34 tm;
  1876.                         ite->second->GetWorldTM(tm);
  1877.                         IRenderAuxText::DrawLabelExF(tm.GetTranslation(), 1.0f, drawColor, true, true, "<%s>", ite->first.c_str());
  1878.                         pDB->AddDirection(tm.GetTranslation(), 0.25f, tm.GetColumn(1), ColorF(1, 1, 0, 1), 0.05f);
  1879.                 }
  1880.         }
  1881.  
  1882.         if (cvars.v_draw_seats)
  1883.         {
  1884.                 float seatColor[] = { 0.5, 1, 1, 1 };
  1885.                 //    float enterColor[] = {0.5,1,1,0.5};
  1886.                 for (TVehicleSeatVector::const_iterator it = m_seats.begin(), end = m_seats.end(); it != end; ++it)
  1887.                 {
  1888.                         Vec3 pos(0);
  1889.                         if (IVehicleHelper* pHelper = it->second->GetSitHelper())
  1890.                                 pos = pHelper->GetVehicleSpaceTranslation();
  1891.  
  1892.                         IRenderAuxText::DrawLabelExF(GetEntity()->GetWorldTM() * pos, 1.1f, seatColor, true, true, "[%s]", it->second->GetName().c_str());
  1893.  
  1894.                         if (IVehicleHelper* pHelper = it->second->GetEnterHelper())
  1895.                                 IRenderAuxText::DrawLabelExF(pHelper->GetWorldSpaceTranslation(), 1.0f, seatColor, true, true, "[%s enter]", it->second->GetName().c_str());
  1896.                 }
  1897.         }
  1898.  
  1899.         if (cvars.v_debugdraw == eVDB_Sounds && IsPlayerPassenger())
  1900.         {
  1901.                 static float color[] = { 1, 1, 1, 1 };
  1902.  
  1903.                 for (TVehicleSoundEventId i = 0; i < m_soundEvents.size(); ++i)
  1904.                 {
  1905.                         if (SVehicleSoundInfo* info = GetSoundInfo(i))
  1906.                         {
  1907.                                 REINST("update speed RTPC");
  1908.                                 /*if (ISound* pSound = m_pIEntityAudioComponent->GetSound(info->soundId))
  1909.                                    {
  1910.                                    float speed = 0.f;
  1911.                                    if (pSound->GetParam("speed", &speed, false))
  1912.                                    {
  1913.                                     IRenderAuxText::Draw2dLabel(50.f, (float)(100+15*GetDebugIndex()), 1.25f, color, false, "%s: speed %.2f", info->name.c_str(), speed);
  1914.                                    }
  1915.                                    }*/
  1916.                         }
  1917.                 }
  1918.         }
  1919. }
  1920.  
  1921. //------------------------------------------------------------------------
  1922. void CVehicle::DebugDrawClientPredict()
  1923. {
  1924.         if (IRenderAuxGeom* pRenderAuxGeom = gEnv->pRenderer->GetIRenderAuxGeom())
  1925.         {
  1926.                 CryAutoCriticalSection lk(m_debugDrawLock);
  1927.  
  1928.                 Vec3 scale(1.0f, 1.0f, 1.0f);
  1929.                 AABB bbox;
  1930.                 GetEntity()->GetLocalBounds(bbox);
  1931.                 bbox.max.z -= 1.5f;
  1932.                 AABB bbox2 = bbox;
  1933.                 bbox2.min.x += 0.2f;
  1934.                 bbox2.max.x -= 0.2f;
  1935.                 TDebugClientPredictData::iterator itInterp;
  1936.                 float y = 50.0f;
  1937.                 for (itInterp = m_debugClientPredictData.begin(); itInterp != m_debugClientPredictData.end(); ++itInterp)
  1938.                 {
  1939.                         Matrix34 matrix1 = Matrix34::Create(scale, itInterp->recordedPos.q, itInterp->recordedPos.t);
  1940.                         Matrix34 matrix2 = Matrix34::Create(scale, itInterp->correctedPos.q, itInterp->correctedPos.t);
  1941.                         pRenderAuxGeom->DrawAABB(bbox, matrix1, false, Col_Green, eBBD_Faceted);
  1942.                         pRenderAuxGeom->DrawAABB(bbox2, matrix2, false, Col_Red, eBBD_Faceted);
  1943.                         Vec3 pos1 = itInterp->recordedPos.t;
  1944.                         Vec3 pos2 = itInterp->correctedPos.t;
  1945.                         pos1.z += 3.0f;
  1946.                         pos2.z += 3.0f;
  1947.                         pRenderAuxGeom->DrawLine(pos1, Col_Green, pos1 + itInterp->recordedVel * 0.2f, Col_Green, 2.0f);
  1948.                         pRenderAuxGeom->DrawLine(pos2, Col_Red, pos2 + itInterp->correctedVel * 0.2f, Col_Red, 2.0f);
  1949.                 }
  1950.         }
  1951. }
  1952.  
  1953. //------------------------------------------------------------------------
  1954. bool CVehicle::IsDebugDrawing()
  1955. {
  1956.         CVehicleCVars& cvars = CVehicleCVars::Get();
  1957.  
  1958.         return (cvars.v_draw_components || cvars.v_draw_helpers || cvars.v_debugdraw);
  1959. }
  1960. #endif
  1961.  
  1962. //------------------------------------------------------------------------
  1963. void CVehicle::UpdateView(SViewParams& viewParams, EntityId playerId)
  1964. {
  1965. #if ENABLE_VEHICLE_DEBUG
  1966.         const CVehicleCVars& vars = VehicleCVars();
  1967.         if (vars.v_debugViewDetach == 1) return;
  1968.  
  1969.         if (vars.v_debugViewDetach == 2)
  1970.         {
  1971.                 IEntity* pEntity = GetEntity();
  1972.                 Vec3 entityPos = pEntity->GetPos();
  1973.                 Vec3 dir = (entityPos - viewParams.position);
  1974.                 float radius = dir.GetLength();
  1975.                 if (radius > 0.01f)
  1976.                 {
  1977.                         dir = dir * (1.f / radius);
  1978.                         viewParams.rotation = Quat::CreateRotationVDir(dir);
  1979.                 }
  1980.                 return;
  1981.         }
  1982.         else if (vars.v_debugViewAbove)
  1983.         {
  1984.                 IEntity* pEntity = GetEntity();
  1985.                 viewParams.position = pEntity->GetPos();
  1986.                 viewParams.position.z += vars.v_debugViewAboveH;
  1987.                 viewParams.rotation = Quat(0.7071067811865475f, -0.7071067811865475f, 0.f, 0.f);
  1988.                 return;
  1989.         }
  1990. #endif
  1991.  
  1992.         for (TVehicleSeatVector::iterator ite = m_seats.begin(), end = m_seats.end(); ite != end; ++ite)
  1993.         {
  1994.                 CVehicleSeat* seat = ite->second;
  1995.                 if (seat->GetPassenger() == playerId && seat->GetCurrentTransition() != CVehicleSeat::eVT_RemoteUsage)
  1996.                 {
  1997.                         seat->UpdateView(viewParams);
  1998.                         if (m_pMovement)
  1999.                         {
  2000.                                 m_pMovement->PostUpdateView(viewParams, playerId);
  2001.                         }
  2002.                         return;
  2003.                 }
  2004.         }
  2005. }
  2006.  
  2007. //------------------------------------------------------------------------
  2008. void CVehicle::HandleEvent(const SGameObjectEvent& event)
  2009. {
  2010.         if (event.event == eGFE_OnPostStep)
  2011.         {
  2012.                 OnPhysPostStep((EventPhys*)event.ptr, (event.flags & eGOEF_LoggedPhysicsEvent) != 0);
  2013.         }
  2014.         else if (event.event == eGFE_OnCollision)
  2015.         {
  2016.                 EventPhysCollision* pCollision = static_cast<EventPhysCollision*>(event.ptr);
  2017.                 OnCollision(pCollision);
  2018.         }
  2019.         else if (event.event == eGFE_OnStateChange)
  2020.         {
  2021.                 EventPhysStateChange* pStateChange = static_cast<EventPhysStateChange*>(event.ptr);
  2022.                 OnPhysStateChange(pStateChange);
  2023.         }
  2024.         else if (event.event == eGFE_OnBecomeVisible)
  2025.         {
  2026.                 if (m_pMovement)
  2027.                 {
  2028.                         SVehicleMovementEventParams params;
  2029.                         m_pMovement->OnEvent(IVehicleMovement::eVME_BecomeVisible, params);
  2030.                 }
  2031.         }
  2032.         else if (event.event == eGFE_PreShatter)
  2033.         {
  2034.                 // evacuate all the passengers
  2035.                 for (TVehicleSeatVector::iterator it = m_seats.begin(), end = m_seats.end(); it != end; ++it)
  2036.                 {
  2037.                         if (it->second->GetPassenger())
  2038.                                 it->second->Exit(false, true);
  2039.                 }
  2040.  
  2041.                 OnDestroyed();
  2042.                 SetDestroyedStatus(true);
  2043.         }
  2044.         else if (event.event == eGFE_StoodOnChange)
  2045.         {
  2046.                 if (m_pMovement)
  2047.                 {
  2048.                         SVehicleMovementEventParams params;
  2049.                         params.sParam = (const char*)event.ptr;
  2050.                         params.bValue = event.paramAsBool;
  2051.                         m_pMovement->OnEvent(IVehicleMovement::eVME_StoodOnChange, params);
  2052.                 }
  2053.         }
  2054. }
  2055.  
  2056. //------------------------------------------------------------------------
  2057. void CVehicle::UpdateStatus(const float deltaTime)
  2058. {
  2059.         FUNCTION_PROFILER(GetISystem(), PROFILE_ACTION);
  2060.  
  2061.         int frameId = gEnv->nMainFrameID;
  2062.         if (!(frameId > m_status.frameId))
  2063.                 return;
  2064.  
  2065.         m_status.frameId = frameId;
  2066.         IPhysicalEntity* pPhysics = GetEntity()->GetPhysics();
  2067.  
  2068.         m_status.altitude = 0.0f;
  2069.  
  2070.         m_status.passengerCount = 0;
  2071.  
  2072.         if (!IsDestroyed())
  2073.         {
  2074.                 for (TVehicleSeatVector::iterator ite = m_seats.begin(), end = m_seats.end(); ite != end; ++ite)
  2075.                 {
  2076.                         CVehicleSeat* seat = ite->second;
  2077.                         if (seat && seat->GetPassenger() && seat->GetCurrentTransition() != CVehicleSeat::eVT_RemoteUsage)
  2078.                         {
  2079.                                 ++m_status.passengerCount;
  2080.                         }
  2081.                 }
  2082.         }
  2083.         else
  2084.         {
  2085.                 m_status.health = 0.f;
  2086.         }
  2087.  
  2088.         if (m_bRetainGravity)
  2089.         {
  2090.                 pe_simulation_params simParams;
  2091.                 simParams.gravity = m_gravity;
  2092.                 GetEntity()->GetPhysics()->SetParams(&simParams);
  2093.         }
  2094.  
  2095.         pe_status_dynamics dyn;
  2096.         if (!IsDestroyed() && pPhysics->GetStatus(&dyn))
  2097.         {
  2098.                 float speed = dyn.v.len();
  2099.  
  2100.                 if (m_pMovement && TriggerEngineSlotBySpeed())
  2101.                 {
  2102.                         // we enable/disable EnginePowered slot when speed crosses
  2103.                         // this threshold, so the engine/movement update can also be
  2104.                         // executed when engine itself is off
  2105.  
  2106.                         float minSpeed = ENGINESLOT_MINSPEED;
  2107.  
  2108.                         // todo: add a small timer here
  2109.                         if (speed > minSpeed && !m_customEngineSlot)
  2110.                         {
  2111.                                 GetGameObject()->EnableUpdateSlot(this, IVehicle::eVUS_EnginePowered);
  2112.                                 m_customEngineSlot = true;
  2113.                         }
  2114.                         else if (speed <= minSpeed && m_customEngineSlot)
  2115.                         {
  2116.                                 GetGameObject()->DisableUpdateSlot(this, IVehicle::eVUS_EnginePowered);
  2117.                                 m_customEngineSlot = false;
  2118.  
  2119.                                 SVehicleMovementEventParams params;
  2120.                                 params.bValue = false;
  2121.                                 m_pMovement->OnEvent(IVehicleMovement::eVME_ToggleEngineUpdate, params);
  2122.                         }
  2123.                 }
  2124.  
  2125.                 float preSubmerged = m_status.submergedRatio;
  2126.  
  2127.                 m_status.speed = speed;
  2128.                 m_status.vel = dyn.v;
  2129.                 m_status.submergedRatio = dyn.submergedFraction;
  2130.  
  2131.                 pe_status_collisions collisions;
  2132.                 collisions.pHistory = 0;
  2133.                 collisions.len = 0;
  2134.                 collisions.age = 1.f;
  2135.  
  2136.                 m_status.contacts = pPhysics->GetStatus(&collisions);
  2137.  
  2138.                 const SVehicleDamageParams& damageParams = m_pVehicle->GetDamageParams();
  2139.                 float max = damageParams.submergedRatioMax - 0.001f;
  2140.                 if (m_status.submergedRatio >= max && preSubmerged < max)
  2141.                         OnSubmerged(m_status.submergedRatio);
  2142.         }
  2143.  
  2144.         // check flipped over status
  2145.         CheckFlippedStatus(deltaTime);
  2146. }
  2147.  
  2148. #if ENABLE_VEHICLE_DEBUG
  2149. //------------------------------------------------------------------------
  2150. void CVehicle::TestClientPrediction(const float deltaTime)
  2151. {
  2152.         // This function is used to test rewinding of physics and replaying inputs, the code is similar to that of
  2153.         // the client prediction and can be used to help debugging problems with it.
  2154.         int predictSamples = VehicleCVars().v_testClientPredict;
  2155.         if (predictSamples > 0 && m_hasAuthority && gEnv->bServer)
  2156.         {
  2157.                 IPhysicalEntity* pPhysics = GetEntity()->GetPhysics();
  2158.                 if (pPhysics)
  2159.                 {
  2160.                         if (m_pMovement)
  2161.                         {
  2162.                                 pe_status_pos currentPos;
  2163.                                 pe_status_dynamics currentDynamics;
  2164.                                 pPhysics->GetStatus(&currentPos);
  2165.                                 pPhysics->GetStatus(&currentDynamics);
  2166.  
  2167.                                 // Record inputs
  2168.                                 SVehiclePredictionHistory sample;
  2169.                                 sample.m_actions = m_pMovement->GetMovementActions();
  2170.                                 sample.m_state = m_pMovement->GetVehicleNetState();
  2171.                                 sample.m_pos = currentPos.pos;
  2172.                                 sample.m_rot = currentPos.q;
  2173.                                 sample.m_velocity = currentDynamics.v;
  2174.                                 sample.m_angVelocity = currentDynamics.w;
  2175.                                 sample.m_deltaTime = deltaTime;
  2176.  
  2177.                                 if (m_predictionHistory.size() >= predictSamples)
  2178.                                 {
  2179.                                         pe_params_flags savedFlags;
  2180.                                         pPhysics->GetParams(&savedFlags);
  2181.                                         pe_params_flags setFlags;
  2182.                                         setFlags.flagsAND = ~(pef_log_state_changes | pef_log_collisions | pef_log_env_changes | pef_log_poststep);
  2183.                                         pPhysics->SetParams(&setFlags, 1);
  2184.  
  2185.                                         // Set the vehicle back "predictSamples" number of frames
  2186.                                         pe_params_pos newPosParams;
  2187.                                         newPosParams.bRecalcBounds = 16 | 32 | 64;
  2188.                                         newPosParams.pos = m_predictionHistory[0].m_pos;
  2189.                                         newPosParams.q = m_predictionHistory[0].m_rot;
  2190.                                         pPhysics->SetParams(&newPosParams, 1);
  2191.  
  2192.                                         pe_action_set_velocity velocity;
  2193.                                         velocity.v = m_predictionHistory[0].m_velocity;
  2194.                                         velocity.w = m_predictionHistory[0].m_angVelocity;
  2195.                                         pPhysics->Action(&velocity, 1);
  2196.  
  2197.                                         // Fast-forward the physics applying all the inputs we recorded
  2198.                                         CryAutoCriticalSection debuglk(m_debugDrawLock);
  2199.                                         ReplayPredictionHistory(0.0f);
  2200.  
  2201.                                         // The final position should now be the same as what we started with as long as everything
  2202.                                         // worked as expected
  2203.  
  2204.                                         // Restore inputs back to what they were before we messed with them
  2205.                                         m_pMovement->RequestActions(sample.m_actions);
  2206.                                         m_predictionHistory.clear();
  2207.  
  2208.                                         pPhysics->SetParams(&savedFlags, 1);
  2209.                                 }
  2210.                                 else
  2211.                                 {
  2212.                                         m_predictionHistory.push_back(sample);
  2213.                                 }
  2214.                         }
  2215.                 }
  2216.         }
  2217. }
  2218. #endif
  2219.  
  2220. //------------------------------------------------------------------------
  2221. // NOTE: This function must be thread-safe.
  2222. void CVehicle::OnPrePhysicsTimeStep(float deltaTime)
  2223. {
  2224.         UpdateNetwork(deltaTime);
  2225. #if ENABLE_VEHICLE_DEBUG
  2226.         TestClientPrediction(deltaTime);
  2227. #endif
  2228. }
  2229.  
  2230. //------------------------------------------------------------------------
  2231. // NOTE: This function must be thread-safe.
  2232. void CVehicle::UpdateNetwork(const float deltaTime)
  2233. {
  2234.         // Client sends vehicle control inputs to the server via the IMovementController interface.
  2235.         // The server responds to those inputs and drives the vehicle as if it was a local player controlling it.
  2236.         // The server then sends the positions of the vehicle to the client which processes them trying to maintain
  2237.         // smooth movement while also keeping in sync with the server position. This function deals will processing
  2238.         // the positions from the server.
  2239.         if (m_hasAuthority && !gEnv->bServer && VehicleCVars().v_serverControlled)
  2240.         {
  2241.                 IPhysicalEntity* pPhysics = GetEntity()->GetPhysics();
  2242.                 if (pPhysics && m_pMovement)
  2243.                 {
  2244.                         CryAutoCriticalSection netlk(*m_pMovement->GetNetworkLock());
  2245. #if ENABLE_VEHICLE_DEBUG
  2246.                         CryAutoCriticalSection debuglk(m_debugDrawLock);
  2247. #endif
  2248.  
  2249.                         pe_status_pos statusPos;
  2250.                         pe_status_dynamics statusDynamics;
  2251.                         pPhysics->GetStatus(&statusPos);
  2252.                         pPhysics->GetStatus(&statusDynamics);
  2253.  
  2254.                         // Record inputs
  2255.                         SVehiclePredictionHistory sample;
  2256.                         sample.m_actions = m_pMovement->GetMovementActions();
  2257.                         sample.m_state = m_pMovement->GetVehicleNetState();
  2258.                         sample.m_pos = statusPos.pos;
  2259.                         sample.m_rot = statusPos.q;
  2260.                         sample.m_velocity = statusDynamics.v;
  2261.                         sample.m_angVelocity = statusDynamics.w;
  2262.                         sample.m_deltaTime = deltaTime;
  2263.  
  2264.                         // Set the vehicle back in time to where the server says it is
  2265.                         pe_status_netpos netPos;
  2266.                         if (pPhysics->GetStatus(&netPos))
  2267.                         {
  2268.                                 float remainderTime = 0.0f;
  2269.                                 bool needsCorrection = true;
  2270.                                 if (VehicleCVars().v_clientPredict)
  2271.                                 {
  2272.                                         // Determine the difference between what the client predicted and what the server says
  2273.                                         float predictTime = min(m_smoothedPing + netPos.timeOffset + VehicleCVars().v_clientPredictAdditionalTime, VehicleCVars().v_clientPredictMaxTime);
  2274.                                         float accumulatedTime = 0.0f;
  2275.                                         for (int i = m_predictionHistory.size() - 1; i >= 0; --i)
  2276.                                         {
  2277.                                                 accumulatedTime += m_predictionHistory[i].m_deltaTime;
  2278.                                                 if (accumulatedTime >= predictTime)
  2279.                                                 {
  2280.                                                         if (i > 0)
  2281.                                                         {
  2282.                                                                 m_predictionHistory.erase(m_predictionHistory.begin(), m_predictionHistory.begin() + i);
  2283.                                                         }
  2284.                                                         remainderTime = accumulatedTime - predictTime;
  2285.                                                         break;
  2286.                                                 }
  2287.                                         }
  2288.  
  2289.                                         if (accumulatedTime >= predictTime && m_predictionHistory.size() > 0)
  2290.                                         {
  2291.                                                 Vec3 predPos;
  2292.                                                 Quat predRot;
  2293.                                                 //Vec3 predVel;
  2294.                                                 //Vec3 predAngVel;
  2295.                                                 if (m_predictionHistory.size() == 1)
  2296.                                                 {
  2297.                                                         predPos = m_predictionHistory[0].m_pos;
  2298.                                                         predRot = m_predictionHistory[0].m_rot;
  2299.                                                         //predVel = m_predictionHistory[0].m_velocity;
  2300.                                                         //predAngVel = m_predictionHistory[0].m_angVelocity;
  2301.                                                 }
  2302.                                                 else
  2303.                                                 {
  2304.                                                         float t = (remainderTime / m_predictionHistory[0].m_deltaTime);
  2305.                                                         predPos.SetLerp(m_predictionHistory[0].m_pos, m_predictionHistory[1].m_pos, t);
  2306.                                                         predRot.SetSlerp(m_predictionHistory[0].m_rot, m_predictionHistory[1].m_rot, t);
  2307.                                                         //predVel.SetLerp(m_predictionHistory[0].m_velocity, m_predictionHistory[1].m_velocity, t);
  2308.                                                         //predAngVel.SetLerp(m_predictionHistory[0].m_angVelocity, m_predictionHistory[1].m_angVelocity, t);
  2309.                                                 }
  2310.  
  2311.                                                 float distErrorSq = predPos.GetSquaredDistance(netPos.pos);
  2312.                                                 float rotErrorDotProd = predRot | netPos.rot;
  2313.                                                 //float velErrorSq = predVel.GetSquaredDistance(netPos.vel);
  2314.                                                 //float angVelErrorSq = predAngVel.GetSquaredDistance(netPos.angvel);
  2315.  
  2316.                                                 if (distErrorSq < sqr(0.01f) && rotErrorDotProd > 0.9999f)
  2317.                                                 {
  2318.                                                         needsCorrection = false;
  2319.                                                 }
  2320.                                         }
  2321.                                         else
  2322.                                         {
  2323.                                                 needsCorrection = false;
  2324.                                         }
  2325.                                 }
  2326.  
  2327.                                 if (needsCorrection)
  2328.                                 {
  2329.                                         pe_params_flags savedFlags;
  2330.                                         pPhysics->GetParams(&savedFlags);
  2331.                                         pe_params_flags setFlags;
  2332.                                         setFlags.flagsAND = ~(pef_log_state_changes | pef_log_collisions | pef_log_env_changes | pef_log_poststep);
  2333.                                         pPhysics->SetParams(&setFlags, 1);
  2334.  
  2335.                                         pe_params_pos newPosParams;
  2336.                                         newPosParams.bRecalcBounds = 16 | 32 | 64;
  2337.                                         newPosParams.pos = netPos.pos;
  2338.                                         newPosParams.q = netPos.rot;
  2339.                                         pPhysics->SetParams(&newPosParams, 1);
  2340.  
  2341.                                         pe_action_set_velocity velocity;
  2342.                                         velocity.v = netPos.vel;
  2343.                                         velocity.w = netPos.angvel;
  2344.                                         pPhysics->Action(&velocity, 1);
  2345.  
  2346.                                         if (VehicleCVars().v_clientPredict && m_predictionHistory.size() > 0)
  2347.                                         {
  2348.                                                 // Fast-forward the physics applying all the inputs we recorded
  2349.                                                 ReplayPredictionHistory(remainderTime);
  2350.  
  2351.                                                 pe_status_pos statusNewPos;
  2352.                                                 pe_status_dynamics statusNewDynamics;
  2353.                                                 pPhysics->GetStatus(&statusNewPos);
  2354.                                                 pPhysics->GetStatus(&statusNewDynamics);
  2355.  
  2356.                                                 sample.m_pos = statusNewPos.pos;
  2357.                                                 sample.m_rot = statusNewPos.q;
  2358.                                                 sample.m_velocity = statusNewDynamics.v;
  2359.                                                 sample.m_angVelocity = statusNewDynamics.w;
  2360.  
  2361.                                                 // Restore inputs back to what they were before we messed with them
  2362.                                                 m_pMovement->RequestActions(sample.m_actions);
  2363.                                         }
  2364.  
  2365.                                         pPhysics->SetParams(&savedFlags, 1);
  2366.                                 }
  2367.                                 else
  2368.                                 {
  2369. #if ENABLE_VEHICLE_DEBUG
  2370.                                         m_debugClientPredictData.clear();
  2371. #endif
  2372.                                 }
  2373.  
  2374.                                 if (VehicleCVars().v_clientPredict)
  2375.                                 {
  2376.                                         m_predictionHistory.push_back(sample);
  2377.  
  2378.                                         if (VehicleCVars().v_clientPredictSmoothing)
  2379.                                         {
  2380.                                                 pe_status_pos statusNewPos;
  2381.                                                 pPhysics->GetStatus(&statusNewPos);
  2382.  
  2383.                                                 if (needsCorrection)
  2384.                                                 {
  2385.                                                         // Error calculated this frame
  2386.                                                         Vec3 posError = statusPos.pos - statusNewPos.pos;
  2387.                                                         Quat rotError = statusPos.q * !statusNewPos.q;
  2388.  
  2389.                                                         // Add it on to the error from the previous frames
  2390.                                                         m_clientPositionError.t += posError;
  2391.                                                         m_clientPositionError.q = rotError * m_clientPositionError.q;
  2392.                                                 }
  2393.  
  2394.                                                 // Smooth out the error to 0 over time
  2395.                                                 const float smoothing = approxOneExp(deltaTime * VehicleCVars().v_clientPredictSmoothingConst);
  2396.                                                 m_clientPositionError.t.SetLerp(m_clientPositionError.t, ZERO, smoothing);
  2397.                                                 m_clientPositionError.q.SetSlerp(m_clientPositionError.q, IDENTITY, smoothing);
  2398.  
  2399.                                                 m_clientSmoothedPosition.t.SetLerp(m_clientSmoothedPosition.t, statusNewPos.pos, smoothing);
  2400.                                                 m_clientSmoothedPosition.q.SetSlerp(m_clientSmoothedPosition.q, statusNewPos.q, smoothing);
  2401.                                         }
  2402.                                 }
  2403.                         }
  2404.                 }
  2405.         }
  2406. }
  2407.  
  2408. //------------------------------------------------------------------------
  2409. // NOTE: This function must be thread-safe.
  2410. void CVehicle::ReplayPredictionHistory(const float remainderTime)
  2411. {
  2412.         if (m_predictionHistory.size() > 1 && remainderTime * 2.0f > m_predictionHistory[0].m_deltaTime)
  2413.         {
  2414.                 m_pMovement->SetVehicleNetState(m_predictionHistory[1].m_state);
  2415.         }
  2416.         else
  2417.         {
  2418.                 m_pMovement->SetVehicleNetState(m_predictionHistory[0].m_state);
  2419.         }
  2420.  
  2421. #if ENABLE_VEHICLE_DEBUG
  2422.         m_debugClientPredictData.clear();
  2423. #endif
  2424.         pe_status_pos statusPos;
  2425.         pe_status_dynamics statusDynamics;
  2426.         IPhysicalEntity* pPhysics = GetEntity()->GetPhysics();
  2427.  
  2428.         pe_params_flags set_update;
  2429.         set_update.flagsOR = pef_update;
  2430.         pPhysics->SetParams(&set_update, 1);
  2431.         m_status.doingNetPrediction = true;
  2432.         int physicsTime = gEnv->pPhysicalWorld->GetiPhysicsTime();  // Save the physics time
  2433.  
  2434.         TVehiclePredictionHistory::iterator itHistory;
  2435.         for (itHistory = m_predictionHistory.begin(); itHistory != m_predictionHistory.end(); ++itHistory)
  2436.         {
  2437.                 float timeDiff = itHistory->m_deltaTime;
  2438.                 if (itHistory == m_predictionHistory.begin())
  2439.                 {
  2440.                         timeDiff -= remainderTime;
  2441.                         itHistory->m_deltaTime = timeDiff;
  2442.                 }
  2443.  
  2444.                 pPhysics->GetStatus(&statusPos);
  2445.                 pPhysics->GetStatus(&statusDynamics);
  2446.  
  2447. #if ENABLE_VEHICLE_DEBUG
  2448.                 SDebugClientPredictData data;
  2449.                 data.recordedPos.t = itHistory->m_pos;
  2450.                 data.recordedPos.q = itHistory->m_rot;
  2451.                 data.recordedVel = itHistory->m_velocity;
  2452.                 data.correctedPos.t = statusPos.pos;
  2453.                 data.correctedPos.q = statusPos.q;
  2454.                 data.correctedVel = statusDynamics.v;
  2455.                 m_debugClientPredictData.push_back(data);
  2456. #endif
  2457.  
  2458.                 itHistory->m_pos = statusPos.pos;
  2459.                 itHistory->m_rot = statusPos.q;
  2460.                 itHistory->m_velocity = statusDynamics.v;
  2461.                 itHistory->m_angVelocity = statusDynamics.w;
  2462.  
  2463.                 // Replay inputs
  2464.                 m_pMovement->RequestActions(itHistory->m_actions);
  2465.  
  2466.                 gEnv->pPhysicalWorld->TimeStep(timeDiff, ent_rigid | ent_flagged_only);
  2467.         }
  2468.  
  2469.         gEnv->pPhysicalWorld->SetiPhysicsTime(physicsTime); // Restore the physics time
  2470.         m_status.doingNetPrediction = false;
  2471.         pe_params_flags clear_update;
  2472.         clear_update.flagsAND = ~pef_update;
  2473.         pPhysics->SetParams(&clear_update, 1);
  2474. }
  2475.  
  2476. //------------------------------------------------------------------------
  2477. const SVehicleStatus& CVehicle::GetStatus() const
  2478. {
  2479.         return m_status;
  2480. }
  2481.  
  2482. //------------------------------------------------------------------------
  2483. // AI related
  2484.  
  2485. //------------------------------------------------------------------------
  2486. IMovementController* CVehicle::GetMovementController()
  2487. {
  2488.         if (m_seats.empty())
  2489.                 return NULL;
  2490.  
  2491.         return m_seats[0].second;
  2492. }
  2493.  
  2494. //------------------------------------------------------------------------
  2495. IMovementController* CVehicle::GetPassengerMovementController(EntityId passengerId)
  2496. {
  2497.         CVehicleSeat* pSeat = (CVehicleSeat*)GetSeatForPassenger(passengerId);
  2498.  
  2499.         if (pSeat)
  2500.                 return pSeat->GetMovementController();
  2501.  
  2502.         return NULL;
  2503. }
  2504.  
  2505. //------------------------------------------------------------------------
  2506. IFireController* CVehicle::GetFireController(uint32 controllerNum)
  2507. {
  2508.         if (!(controllerNum < m_seats.size()))
  2509.                 return NULL;
  2510.  
  2511.         return m_seats[controllerNum].second;
  2512. }
  2513.  
  2514. //------------------------------------------------------------------------
  2515. void CVehicle::SetAuthority(bool auth)
  2516. {
  2517.         m_hasAuthority = auth;
  2518.         if (m_pMovement)
  2519.         {
  2520.                 m_pMovement->SetAuthority(auth);
  2521.         }
  2522.         if (auth)
  2523.         {
  2524.                 m_clientSmoothedPosition.t = GetEntity()->GetPos();
  2525.                 m_clientSmoothedPosition.q = GetEntity()->GetRotation();
  2526.         }
  2527. }
  2528.  
  2529. //------------------------------------------------------------------------
  2530. bool CVehicle::NetSerialize(TSerialize ser, EEntityAspects aspect, uint8 profile, int flags)
  2531. {
  2532.         if (m_pMovement)
  2533.                 m_pMovement->Serialize(ser, aspect);
  2534.  
  2535.         // components
  2536.         float prevDmgRatio = (aspect == ASPECT_COMPONENT_DAMAGE) ? GetDamageRatio() : 0.f;
  2537.  
  2538.         for (TVehicleComponentVector::iterator itc = m_components.begin(); itc != m_components.end(); ++itc)
  2539.                 (*itc)->Serialize(ser, aspect);
  2540.  
  2541.         if (aspect == ASPECT_COMPONENT_DAMAGE && ser.IsReading())
  2542.         {
  2543.                 float deltaRatio = GetDamageRatio() - prevDmgRatio;
  2544.                 if (abs(deltaRatio) > 0.001f)
  2545.                 {
  2546.                         EVehicleEvent event = (deltaRatio > 0.f) ? eVE_Damaged : eVE_Repair;
  2547.                         SVehicleEventParams eventParams;
  2548.                         eventParams.fParam = deltaRatio * m_damageMax;
  2549.                         BroadcastVehicleEvent(event, eventParams);
  2550.                 }
  2551.         }
  2552.  
  2553.         for (TVehicleSeatVector::iterator its = m_seats.begin(); its != m_seats.end(); ++its)
  2554.                 (its->second)->Serialize(ser, aspect);
  2555.  
  2556.         NET_PROFILE_BEGIN("Parts", ser.IsReading());
  2557.         for (TVehiclePartVector::iterator itp = m_parts.begin(); itp != m_parts.end(); ++itp)
  2558.         {
  2559.                 itp->second->Serialize(ser, aspect);
  2560.         }
  2561.         NET_PROFILE_END();
  2562.  
  2563.         if (aspect == eEA_Physics)
  2564.         {
  2565.                 if (profile == eVPhys_DemoRecording)
  2566.                 {
  2567.                         uint8 currentProfile = 255;
  2568.                         if (ser.IsWriting())
  2569.                                 currentProfile = GetGameObject()->GetAspectProfile(eEA_Physics);
  2570.                         ser.Value("PhysicalizationProfile", currentProfile);
  2571.                         return NetSerialize(ser, aspect, currentProfile, flags);
  2572.                 }
  2573.  
  2574.                 pe_type type = PE_NONE;
  2575.  
  2576.                 switch (profile)
  2577.                 {
  2578.                 case eVPhys_Physicalized:
  2579.                         {
  2580.                                 type = PE_RIGID;
  2581.                                 if (m_pMovement)
  2582.                                         type = m_pMovement->GetPhysicalizationType();
  2583.                         }
  2584.                         break;
  2585.                 case eVPhys_NotPhysicalized:
  2586.                         type = PE_NONE;
  2587.                         break;
  2588.                 }
  2589.  
  2590.                 if (type == PE_NONE)
  2591.                         return true;
  2592.  
  2593.                 NET_PROFILE_SCOPE("Physics", ser.IsReading());
  2594.  
  2595.                 GetEntity()->PhysicsNetSerializeTyped(ser, type, flags);
  2596.         }
  2597.  
  2598.         return true;
  2599. }
  2600.  
  2601. //------------------------------------------------------------------------
  2602. void CVehicle::FullSerialize(TSerialize ser)
  2603. {
  2604.         MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_Other, 0, "Vehicle serialization");
  2605.         ser.Value("indestructible", m_indestructible);
  2606.         bool isDestroyed = IsDestroyed();
  2607.         ser.Value("isDestroyed", isDestroyed, 'bool');
  2608.  
  2609.         if (ser.IsReading() && isDestroyed != IsDestroyed())
  2610.         {
  2611.                 SetDestroyedStatus(isDestroyed);
  2612.         }
  2613.  
  2614.         ser.BeginGroup("Status");
  2615.         m_status.Serialize(ser, eEA_All);
  2616.         ser.EndGroup();
  2617.  
  2618.         ser.BeginGroup("Components");
  2619.         for (TVehicleComponentVector::iterator ite = m_components.begin(); ite != m_components.end(); ++ite)
  2620.         {
  2621.                 CVehicleComponent* pComponent = *ite;
  2622.                 ser.BeginGroup(pComponent->GetName().c_str());
  2623.                 pComponent->Serialize(ser, eEA_All);
  2624.                 ser.EndGroup();
  2625.         }
  2626.         ser.EndGroup();
  2627.  
  2628.         for (TVehicleDamagesGroupVector::iterator ite = m_damagesGroups.begin(); ite != m_damagesGroups.end(); ++ite)
  2629.         {
  2630.                 CVehicleDamagesGroup* pDamageGroup = *ite;
  2631.                 ser.BeginGroup("DamageGroup");
  2632.                 pDamageGroup->Serialize(ser, eEA_All);
  2633.                 ser.EndGroup();
  2634.         }
  2635.  
  2636.         for (TVehiclePartVector::iterator it = m_parts.begin(); it != m_parts.end(); ++it)
  2637.         {
  2638.                 ser.BeginGroup("Part");
  2639.                 it->second->Serialize(ser, eEA_All);
  2640.                 ser.EndGroup();
  2641.         }
  2642.  
  2643.         if (m_pMovement)
  2644.         {
  2645.                 ser.BeginGroup("Movement");
  2646.                 m_pMovement->Serialize(ser, eEA_All);
  2647.                 ser.EndGroup();
  2648.         }
  2649.  
  2650.         ser.BeginGroup("Seats");
  2651.         for (TVehicleSeatVector::iterator it = m_seats.begin(); it != m_s