BVB Source Codes

CRYENGINE Show ActionGame.cpp Source code

Return Download CRYENGINE: download ActionGame.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include "IGameRulesSystem.h"
  5. #include "ActionGame.h"
  6. #include <CryGame/IGameFramework.h>
  7. #include "Network/GameClientNub.h"
  8. #include "Network/GameServerNub.h"
  9. #include "Network/GameClientChannel.h"
  10. #include "Network/GameServerChannel.h"
  11. #include "Network/GameContext.h"
  12. #include "Network/ServerTimer.h"
  13. #include "Network/DeformingBreak.h" // for debug function
  14. #include "CryAction.h"
  15. #include "CryActionCVars.h"
  16. #include "IActorSystem.h"
  17. #include "MaterialEffects/MaterialEffectsCVars.h"
  18. #include <CryParticleSystem/ParticleParams.h>
  19. #include "DelayedPlaneBreak.h"
  20. #include <CryPhysics/IPhysics.h>
  21. #include <CryFlowGraph/IFlowSystem.h>
  22. #include <CryAction/IMaterialEffects.h>
  23. #include <CryEntitySystem/IBreakableGlassSystem.h>
  24. #include "IPlayerProfiles.h"
  25. #include <CryAISystem/IAISystem.h>
  26. #include <CryAISystem/IAgent.h>
  27. #include "IMovementController.h"
  28. #include "IGameSessionHandler.h"
  29. #include "DialogSystem/DialogSystem.h"
  30. #include <Cry3DEngine/ITimeOfDay.h>
  31. #include "TimeOfDayScheduler.h"
  32. #include "PersistantDebug.h"
  33. #include "Network/GameStats.h"
  34. #include "Animation/PoseModifier/IKTorsoAim.h"
  35. #include <CryGame/IGameTokens.h>
  36. #include <CryMovie/IMovieSystem.h>
  37. #include "IForceFeedbackSystem.h"
  38.  
  39. #include "CryAction.h"
  40. #include "Network/BreakReplicator.h"
  41. #include "Network/ObjectSelector.h"
  42.  
  43. #include <CryLobby/CommonICryLobby.h>
  44. #include <CryLobby/CommonICryMatchMaking.h>
  45. #include <CrySystem/Scaleform/IFlashUI.h>
  46.  
  47. CActionGame* CActionGame::s_this = 0;
  48. int CActionGame::g_procedural_breaking = 0;
  49. int CActionGame::g_joint_breaking = 1;
  50. float CActionGame::g_tree_cut_reuse_dist = 0;
  51. int CActionGame::g_no_secondary_breaking = 0;
  52. int CActionGame::g_no_breaking_by_objects = 0;
  53. int CActionGame::g_breakage_mem_limit = 0;
  54. int CActionGame::g_breakage_debug = 0;
  55. int CActionGame::s_waterMaterialId = -1;
  56. float g_breakageFadeTime = 0.f;
  57. float g_breakageFadeDelay = 0.f;
  58. float g_breakageMinAxisInertia = 0.01f;
  59. int g_breakageNoDebrisCollisions = 0;
  60. float g_glassForceTimeout = 0.f;
  61. float g_glassForceTimeoutSpread = 0.f;
  62. int g_glassNoDecals = 0;
  63. int g_glassAutoShatter = 0;
  64. int g_glassAutoShatterOnExplosions = 0;
  65. int g_glassMaxPanesToBreakPerFrame = 0;
  66. float CActionGame::g_glassAutoShatterMinArea = 0.f;
  67. int g_glassSystemEnable = 1;
  68. /*
  69.    ============================================================================================================================================
  70.    Tree breakage throttling
  71.     If the counter goes above g_breakageTreeMax then tree breakage will stop
  72.     Every time a tree is broken the counter is raised by g_breakageTreeInc
  73.     Every frame the counter is decreased by g_breakageTreeInc
  74.  
  75.     if max = 5, inc = 1, dec = 5, then can only break 5 trees per frame, and the count is reset next frame
  76.     if max = 5, inc = 1, dec = 1, then can only break 5 trees within 5 frames, and the count is reset after an average of 5 frames
  77.     if max = 5, inc = 5, dec = 1, then can only break 1 tree within 1 frame, and the count is reset after 5 frames
  78.  
  79.     If there is a full glass break, then g_breakageTreeIncGlass increases the counter. This throttles tree breakage
  80.     when too much glass is being broken
  81.    ============================================================================================================================================
  82.  */
  83. int g_breakageTreeMax = 0;
  84. int g_breakageTreeInc = 0;
  85. int g_breakageTreeDec = 0;
  86. int g_breakageTreeIncGlass = 0;
  87. int g_waterHitOnly = 0;
  88. #if BREAKAGE_THROTTLE_LOGGING
  89.         #define ThrottleLogAlways CryLogAlways
  90. #else
  91.         #define ThrottleLogAlways(...) ((void)0)
  92. #endif
  93.  
  94. #ifndef _RELEASE
  95. float CActionGame::g_hostMigrationServerDelay = 0.f;
  96. #endif
  97.  
  98. #define MAX_ADDRESS_SIZE (256)
  99.  
  100. void CActionGame::RegisterCVars()
  101. {
  102.         REGISTER_CVAR2("g_procedural_breaking", &g_procedural_breaking, 1, VF_CHEAT, "Toggles procedural mesh breaking (except explosion-breaking)");
  103.         REGISTER_CVAR2("g_joint_breaking", &g_joint_breaking, 1, 0, "Toggles jointed objects breaking");
  104.         REGISTER_CVAR2("g_tree_cut_reuse_dist", &g_tree_cut_reuse_dist, 0, 0,
  105.                        "Maximum distance from a previously made cut that allows reusing");
  106.         REGISTER_CVAR2("g_no_secondary_breaking", &g_no_secondary_breaking, 0, 0,
  107.                        "Prevents secondary procedural breaks (to keep down memory usage)");
  108.         REGISTER_CVAR2("g_no_breaking_by_objects", &g_no_breaking_by_objects, 0, 0,
  109.                        "Prevents procedural breaking caused by rigid bodies");
  110.         REGISTER_CVAR2("g_breakage_mem_limit", &g_breakage_mem_limit, 0, 0,
  111.                        "Sets a budget for procedurally breakable objects (in KBs)");
  112.         REGISTER_CVAR2("g_breakage_debug", &g_breakage_debug, 0, 0,
  113.                        "Turns on debug rendering for broken objects counted against g_breakage_mem_limit");
  114.  
  115. #ifndef _RELEASE
  116.         REGISTER_CVAR2("g_hostMigrationServerDelay", &g_hostMigrationServerDelay, 0.f, 0, "Delay in host migration before promoting to server (seconds)");
  117. #endif
  118.  
  119.         REGISTER_CVAR2("g_breakageFadeDelay", &g_breakageFadeDelay, 6.f, 0, "");
  120.         REGISTER_CVAR2("g_breakageFadeTime", &g_breakageFadeTime, 6.f, 0, "");
  121.         REGISTER_CVAR2("g_breakageMinAxisInertia", &g_breakageMinAxisInertia, 0.01f, 0, "Set this to 1.0 to force broken trees to have spherical inertia");
  122.         REGISTER_CVAR2("g_breakageNoDebrisCollisions", &g_breakageNoDebrisCollisions, 0, 0, "Turns off all collisions for debris, apart from coltype_solid");
  123.  
  124.         REGISTER_CVAR2("g_glassForceTimeout", &g_glassForceTimeout, 0.f, 0, "Make all glass break after a given time, overrides art settings");
  125.         REGISTER_CVAR2("g_glassForceTimeoutSpread", &g_glassForceTimeoutSpread, 0.f, 0, "Add a random amount to forced glass shattering");
  126.         REGISTER_CVAR2("g_glassNoDecals", &g_glassNoDecals, 0, 0, "Turns off glass decals");
  127.         REGISTER_CVAR2("g_glassAutoShatter", &g_glassAutoShatter, 0, 0, "Always smash the whole pane, and spawn fracture effect");
  128.         REGISTER_CVAR2("g_glassAutoShatterOnExplosions", &g_glassAutoShatterOnExplosions, 0, 0, "Just smash the whole pane, and spawn fracture effect for explosions");
  129.         REGISTER_CVAR2("g_glassAutoShatterMinArea", &g_glassAutoShatterMinArea, 0, 0, "If the area of glass is below this, then autoshatter");
  130.         REGISTER_CVAR2("g_glassMaxPanesToBreakPerFrame", &g_glassMaxPanesToBreakPerFrame, 0, 0, "Max glass breaks, before auto-shattering is forced");
  131.  
  132.         REGISTER_CVAR2("g_glassSystemEnable", &g_glassSystemEnable, 1, 0, "Enables the new dynamic breaking system for glass");
  133.  
  134.         REGISTER_CVAR2("g_breakageTreeMax", &g_breakageTreeMax, 0, 0, "Please see comments in ActionGame.cpp");
  135.         REGISTER_CVAR2("g_breakageTreeInc", &g_breakageTreeInc, 0, 0, "Please see comments in ActionGame.cpp");
  136.         REGISTER_CVAR2("g_breakageTreeDec", &g_breakageTreeDec, 0, 0, "Please see comments in ActionGame.cpp");
  137.         REGISTER_CVAR2("g_breakageTreeIncGlass", &g_breakageTreeIncGlass, 0, 0, "Please see comments in ActionGame.cpp");
  138.  
  139.         REGISTER_CVAR2("g_waterHitOnly", &g_waterHitOnly, 0, 0, "Bullet hit FX appears on water and not what's underneath");
  140.  
  141.         CIKTorsoAim::InitCVars();
  142. }
  143.  
  144. // small helper class to make local connections have a fast packet rate - during critical operations
  145. class CAdjustLocalConnectionPacketRate
  146. {
  147. public:
  148.         CAdjustLocalConnectionPacketRate(float rate, float inactivityTimeout)
  149.         {
  150.                 m_old = -1.f;
  151.                 m_oldInactivityTimeout = -1.f;
  152.                 m_oldInactivityTimeoutDev = -1.f;
  153.  
  154.                 if (ICVar* pVar = gEnv->pConsole->GetCVar("g_localPacketRate"))
  155.                 {
  156.                         m_old = pVar->GetFVal();
  157.                         pVar->Set(rate);
  158.                 }
  159.  
  160.                 if (ICVar* pVar = gEnv->pConsole->GetCVar("net_inactivitytimeout"))
  161.                 {
  162.                         m_oldInactivityTimeout = pVar->GetFVal();
  163.                         pVar->Set(inactivityTimeout);
  164.                 }
  165.  
  166.                 if (ICVar* pVar = gEnv->pConsole->GetCVar("net_inactivitytimeoutDevmode"))
  167.                 {
  168.                         m_oldInactivityTimeoutDev = pVar->GetFVal();
  169.                         pVar->Set(inactivityTimeout);
  170.                 }
  171.         }
  172.  
  173.         ~CAdjustLocalConnectionPacketRate()
  174.         {
  175.                 if (m_old > 0)
  176.                 {
  177.                         if (ICVar* pVar = gEnv->pConsole->GetCVar("g_localPacketRate"))
  178.                         {
  179.                                 pVar->Set(m_old);
  180.                         }
  181.                 }
  182.  
  183.                 if (m_oldInactivityTimeout > 0)
  184.                 {
  185.                         if (ICVar* pVar = gEnv->pConsole->GetCVar("net_inactivitytimeout"))
  186.                         {
  187.                                 pVar->Set(m_oldInactivityTimeout);
  188.                         }
  189.                 }
  190.  
  191.                 if (m_oldInactivityTimeoutDev > 0)
  192.                 {
  193.                         if (ICVar* pVar = gEnv->pConsole->GetCVar("net_inactivitytimeoutDevmode"))
  194.                         {
  195.                                 pVar->Set(m_oldInactivityTimeoutDev);
  196.                         }
  197.                 }
  198.         }
  199.  
  200. private:
  201.         float m_old;
  202.         float m_oldInactivityTimeout;
  203.         float m_oldInactivityTimeoutDev;
  204. };
  205.  
  206. CActionGame::CActionGame(CScriptRMI* pScriptRMI)
  207.         : m_pEntitySystem(gEnv->pEntitySystem)
  208.         , m_pNetwork(gEnv->pNetwork)
  209.         , m_pClientNub(0)
  210.         , m_pServerNub(0)
  211.         , m_pGameClientNub(0)
  212.         , m_pGameServerNub(0)
  213.         , m_pGameContext(0)
  214.         , m_pNetContext(0)
  215.         , m_pGameTokenSystem(0)
  216.         , m_pPhysicalWorld(0)
  217.         , m_pGameStats(0)
  218.         , m_pEntHits0(0)
  219.         , m_pCHSlotPool(0)
  220.         , m_lastDynPoolSize(0)
  221. #ifndef _RELEASE
  222.         , m_timeToPromoteToServer(0.f)
  223. #endif
  224.         , m_initState(eIS_Uninited)
  225.         , m_pendingPlaneBreaks(10)
  226.         , m_clientActorID(0)
  227.         , m_pClientActor(NULL)
  228. {
  229.         CRY_ASSERT(!s_this);
  230.         s_this = this;
  231.  
  232.         m_pNetwork->AddHostMigrationEventListener(this, "CActionGame", ELPT_PostEngine);
  233.  
  234.         m_pGameContext = new CGameContext(CCryAction::GetCryAction(), pScriptRMI, this);
  235.         m_pGameTokenSystem = CCryAction::GetCryAction()->GetIGameTokenSystem();
  236.         m_inDeleteEntityCallback = 0;
  237. }
  238.  
  239. CActionGame::~CActionGame()
  240. {
  241. #ifndef _RELEASE
  242.         CryLog("Destroying CActionGame instance %p (level=\"%s\")", this, GetLevelName().c_str());
  243.         INDENT_LOG_DURING_SCOPE();
  244. #endif
  245.  
  246.         m_pNetwork->RemoveHostMigrationEventListener(this);
  247.  
  248.         if (m_pGameStats)
  249.                 m_pGameStats->EndSession();
  250.  
  251.         {
  252.                 IGameSessionHandler* pGameSessionHandler = CCryAction::GetCryAction()->GetIGameSessionHandler();
  253.                 pGameSessionHandler->OnGameShutdown();
  254.         }
  255.  
  256.         if (m_pNetwork)
  257.         {
  258.                 if (!gEnv->IsEditor())
  259.                 {
  260.                         m_pNetwork->SyncWithGame(eNGS_FrameStart);
  261.                         m_pNetwork->SyncWithGame(eNGS_FrameEnd);
  262.                         m_pNetwork->SyncWithGame(eNGS_WakeNetwork);
  263.                 }
  264.                 m_pNetwork->SyncWithGame(eNGS_Shutdown);
  265.         }
  266.  
  267.         if (m_pServerNub)
  268.         {
  269.                 m_pServerNub->DeleteNub();
  270.                 m_pServerNub = 0;
  271.         }
  272.  
  273.         if (m_pClientNub)
  274.         {
  275.                 m_pClientNub->DeleteNub();
  276.                 m_pClientNub = NULL;
  277.         }
  278.  
  279.         if (m_pNetContext)
  280.                 m_pNetContext->DeleteContext();
  281.         m_pNetContext = 0;
  282.  
  283.         if (m_pGameContext && m_pGameContext->GetFramework()->GetIGameRulesSystem() &&
  284.             m_pGameContext->GetFramework()->GetIGameRulesSystem()->GetCurrentGameRules())
  285.                 m_pGameContext->GetFramework()->GetIGameRulesSystem()->GetCurrentGameRules()->RemoveHitListener(this);
  286.  
  287.         if (m_pEntitySystem)
  288.                 m_pEntitySystem->ResetAreas(); // this is called again in UnloadLevel(). but we need it here to avoid unwanted events generated when the player entity is deleted.
  289.         SAFE_DELETE(m_pGameContext);
  290.         SAFE_DELETE(m_pGameClientNub);
  291.         SAFE_DELETE(m_pGameServerNub);
  292.  
  293.         if (m_pNetwork)
  294.         {
  295.                 m_pNetwork->SyncWithGame(eNGS_Shutdown_Clear);
  296.         }
  297.  
  298.         // Pause and wait for the physics
  299.         gEnv->pSystem->SetThreadState(ESubsys_Physics, false);
  300.         EnablePhysicsEvents(false);
  301.  
  302.         CCryAction* pCryAction = CCryAction::GetCryAction();
  303.         if (pCryAction)
  304.                 pCryAction->GetIGameRulesSystem()->DestroyGameRules();
  305.  
  306.         // ~CGameRules uses game stats so destroy game stats after the game rules
  307.         ReleaseGameStats();
  308.  
  309.         if (!gEnv->IsDedicated())
  310.         {
  311.                 //gEnv->bMultiplayer = false;
  312.                 const char* szDefaultGameRules = gEnv->pConsole->GetCVar("sv_gamerulesdefault")->GetString();
  313.                 gEnv->pConsole->GetCVar("sv_gamerules")->Set(szDefaultGameRules);
  314.                 gEnv->pConsole->GetCVar("sv_requireinputdevice")->Set("dontcare");
  315. #ifdef __WITH_PB__
  316.                 gEnv->pConsole->ExecuteString("net_pb_sv_enable false");
  317. #endif
  318.         }
  319.  
  320. #ifdef __WITH_PB__
  321.         if (gEnv->pNetwork)
  322.                 gEnv->pNetwork->CleanupPunkBuster();
  323. #endif
  324.  
  325.         UnloadLevel();
  326.  
  327.         gEnv->bServer = false;
  328.         {
  329.                 const IGameSessionHandler* pGameSessionHandler = CCryAction::GetCryAction()->GetIGameSessionHandler();
  330.                 gEnv->bMultiplayer = pGameSessionHandler ? pGameSessionHandler->IsMultiplayer() : false;
  331.         }
  332. #if CRY_PLATFORM_DESKTOP
  333.         if (!gEnv->IsDedicated()) // Dedi client should remain client
  334.         {
  335.                 gEnv->SetIsClient(false);
  336.         }
  337. #endif
  338.         s_this = 0;
  339. }
  340.  
  341. //////////////////////////////////////////////////////////////////////////
  342. void CActionGame::UnloadLevel()
  343. {
  344.         UnloadPhysicsData();
  345.         CCryAction::GetCryAction()->GetILevelSystem()->UnLoadLevel();
  346. }
  347.  
  348. //////////////////////////////////////////////////////////////////////////
  349. void CActionGame::UnloadPhysicsData()
  350. {
  351.         // clean up broken object refs
  352.         FixBrokenObjects(false);
  353.         ClearBreakHistory();
  354.  
  355.         delete[] m_pCHSlotPool;
  356.         m_pCHSlotPool = m_pFreeCHSlot0 = 0;
  357.  
  358.         SEntityHits* phits, * phitsPool;
  359.         int i;
  360.         for (i = 0, phits = m_pEntHits0, phitsPool = 0; phits; phits = phits->pnext, i++)
  361.         {
  362.                 if (phits->pHits != &phits->hit0) delete[] phits->pHits;
  363.                 if (phits->pnHits != &phits->nhits0) delete[] phits->pnHits;
  364.                 if ((i & 31) == 0)
  365.                 {
  366.                         if (phitsPool) delete[] phitsPool; phitsPool = phits;
  367.                 }
  368.         }
  369.         delete[] phitsPool;
  370.         m_vegStatus.clear();
  371. }
  372.  
  373. ILINE bool CActionGame::AllowProceduralBreaking(uint8 proceduralBreakType)
  374. {
  375.         // bit 1 : test state
  376.         // bit 2 : and (true), or (false)
  377.         // bit 3 : current state
  378.         // bit 4 : skip flag
  379.         static const uint16 truth = 0xf0b2;
  380. #define UPDATE_VAL(skip, isand, test) val = ((truth >> (((skip) << 3) | ((val) << 2) | ((isand) << 1) | (test))) & 1)
  381.  
  382.         uint8 val = 0;
  383.         // single player defaults to on, multiplayer to
  384.         UPDATE_VAL(0, 0, (m_proceduralBreakFlags & ePBF_DefaultAllow) != 0);
  385.         UPDATE_VAL(0, 0, proceduralBreakType == ePBT_Glass);
  386.         UPDATE_VAL((m_proceduralBreakFlags & ePBF_ObeyCVar) == 0, 1, g_procedural_breaking != 0);
  387.         return val == 1;
  388. }
  389.  
  390. void CActionGame::BackupGameStartParams(const SGameStartParams* pGameStartParams)
  391. {
  392.         // This lot has to be deep copied now.  It usually lives on the stack in a calling function
  393.         // but some of it is used by the BlockingConnect process.
  394.         m_startGameParams = *pGameStartParams;
  395.         m_hostname = m_startGameParams.hostname;
  396.         m_connectionString = m_startGameParams.connectionString;
  397.         m_startGameParams.hostname = m_hostname.c_str();
  398.         m_startGameParams.connectionString = m_connectionString.c_str();
  399.  
  400.         if (pGameStartParams->pContextParams)
  401.         {
  402.                 m_levelName = pGameStartParams->pContextParams->levelName;
  403.                 m_gameRules = pGameStartParams->pContextParams->gameRules;
  404.                 m_demoRecorderFilename = pGameStartParams->pContextParams->demoRecorderFilename;
  405.                 m_demoPlaybackFilename = pGameStartParams->pContextParams->demoPlaybackFilename;
  406.  
  407.                 m_gameContextParams.levelName = m_levelName.c_str();
  408.                 m_gameContextParams.gameRules = m_gameRules.c_str();
  409.                 m_gameContextParams.demoRecorderFilename = m_demoRecorderFilename.c_str();
  410.                 m_gameContextParams.demoPlaybackFilename = m_demoPlaybackFilename.c_str();
  411.  
  412.                 m_startGameParams.pContextParams = &m_gameContextParams;
  413.         }
  414. }
  415.  
  416. bool CActionGame::Init(const SGameStartParams* pGameStartParams)
  417. {
  418.         MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_Other, 0, "ActionGame::Init");
  419.  
  420.         if (!pGameStartParams)
  421.         {
  422.                 m_initState = eIS_InitError;
  423.                 return false;
  424.         }
  425.  
  426.         BackupGameStartParams(pGameStartParams);
  427.  
  428.         m_initState = eIS_Initing;
  429.  
  430.         m_fadeEntities.resize(0);
  431.  
  432.         memset(&m_throttling, 0, sizeof(m_throttling));
  433.  
  434.         // Needed for the editor, as the action game won't be destroyed
  435.         m_clientActorID = 0;
  436.         m_pClientActor = NULL;
  437.  
  438.         // initialize client server infrastructure
  439.  
  440.         CAdjustLocalConnectionPacketRate adjustLocalPacketRate(50.0f, 30.0f);
  441.  
  442.         uint32 ctxFlags = 0;
  443.         if ((pGameStartParams->flags & eGSF_Server) == 0 || (pGameStartParams->flags & eGSF_LocalOnly) == 0)
  444.                 ctxFlags |= INetwork::eNCCF_Multiplayer;
  445.         if (m_pNetwork)
  446.         {
  447.                 m_pNetContext = m_pNetwork->CreateNetContext(m_pGameContext, ctxFlags);
  448.                 m_pGameContext->Init(m_pNetContext);
  449.         }
  450.  
  451.         if (gEnv->pAISystem)
  452.         {
  453.                 ICVar* pAIEnabled = NULL;
  454.                 if (gEnv->bMultiplayer)
  455.                 {
  456.                         if (pGameStartParams->flags & eGSF_Server)
  457.                         {
  458.                                 pAIEnabled = gEnv->pConsole->GetCVar("sv_AISystem");
  459.                         }
  460.                         else if (pGameStartParams->flags & eGSF_Client)
  461.                         {
  462.                                 pAIEnabled = gEnv->pConsole->GetCVar("cl_AISystem");
  463.                         }
  464.                 }
  465.  
  466.                 bool aiSystemEnable = (pAIEnabled ? pAIEnabled->GetIVal() != 0 : true);
  467.  
  468.                 gEnv->pAISystem->Enable(aiSystemEnable);
  469.         }
  470.  
  471.         CRY_ASSERT(m_pGameServerNub == NULL);
  472.         CRY_ASSERT(m_pServerNub == NULL);
  473.  
  474.         bool ok = true;
  475.         bool clientRequiresBlockingConnection = false;
  476.  
  477.         string connectionString = pGameStartParams->connectionString;
  478.         if (!connectionString)
  479.                 connectionString = "";
  480.  
  481.         unsigned flags = pGameStartParams->flags;
  482.         if (pGameStartParams->flags & eGSF_Server)
  483.         {
  484.                 ICVar* pReqInput = gEnv->pConsole->GetCVar("sv_requireinputdevice");
  485.                 if (pReqInput)
  486.                 {
  487.                         const char* what = pReqInput->GetString();
  488.                         if (0 == strcmpi(what, "none"))
  489.                         {
  490.                                 flags &= ~(eGSF_RequireKeyboardMouse | eGSF_RequireController);
  491.                         }
  492.                         else if (0 == strcmpi(what, "keyboard"))
  493.                         {
  494.                                 flags |= eGSF_RequireKeyboardMouse;
  495.                                 flags &= ~eGSF_RequireController;
  496.                         }
  497.                         else if (0 == strcmpi(what, "gamepad"))
  498.                         {
  499.                                 flags |= eGSF_RequireController;
  500.                                 flags &= ~eGSF_RequireKeyboardMouse;
  501.                         }
  502.                         else if (0 == strcmpi(what, "dontcare"))
  503.                                 ;
  504.                         else
  505.                         {
  506.                                 GameWarning("Invalid sv_requireinputdevice %s", what);
  507.                                 m_initState = eIS_InitError;
  508.                                 return false;
  509.                         }
  510.                 }
  511.                 //Set the gamerules & map cvar to keep things in sync
  512.                 if (pGameStartParams->pContextParams)
  513.                 {
  514.                         gEnv->pConsole->GetCVar("sv_gamerules")->Set(pGameStartParams->pContextParams->gameRules);
  515.                         gEnv->pConsole->GetCVar("sv_map")->Set(pGameStartParams->pContextParams->levelName);
  516.                 }
  517.         }
  518.         else
  519.         {
  520.                 ICryLobby* pLobby = gEnv->pNetwork->GetLobby();
  521.                 if (pLobby && gEnv->bMultiplayer)
  522.                 {
  523.                         const char* pLevelName = pLobby->GetCryEngineLevelNameHint();
  524.                         if (strlen(pLevelName) != 0)
  525.                         {
  526.                                 m_pGameContext->SetLevelName(pLevelName);
  527.                         }
  528.                         const char* pRulesName = pLobby->GetCryEngineRulesNameHint();
  529.                         if (strlen(pRulesName) != 0)
  530.                         {
  531.                                 m_pGameContext->SetGameRules(pRulesName);
  532.                         }
  533.                 }
  534.         }
  535.  
  536.         // we need to fake demo playback as not LocalOnly, otherwise things not breakable in demo recording will become breakable
  537.         if (flags & eGSF_DemoPlayback)
  538.                 flags &= ~eGSF_LocalOnly;
  539.  
  540.         m_pGameContext->SetContextInfo(flags, pGameStartParams->port, connectionString.c_str());
  541.  
  542.         // although demo playback doesn't allow more than one client player (the local spectator), it should still be multiplayer to be consistent
  543.         // with the recording session (otherwise, things not physicalized in demo recording (multiplayer) will be physicalized in demo playback)
  544.         bool isMultiplayer = !m_pGameContext->HasContextFlag(eGSF_LocalOnly) || (flags & eGSF_DemoPlayback);
  545.  
  546.         const char* configName = isMultiplayer ? "multiplayer" : "singleplayer";
  547.  
  548.         gEnv->pSystem->LoadConfiguration(configName);
  549.  
  550.         gEnv->bMultiplayer = isMultiplayer;
  551.         gEnv->bServer = m_pGameContext->HasContextFlag(eGSF_Server);
  552.  
  553. #if CRY_PLATFORM_DESKTOP
  554.         gEnv->SetIsClient(m_pGameContext->HasContextFlag(eGSF_Client));
  555. #endif
  556.  
  557.         if (gEnv->pNetwork)
  558.         {
  559.                 if (gEnv->bMultiplayer)
  560.                 {
  561.                         gEnv->pNetwork->SetMultithreadingMode(INetwork::NETWORK_MT_PRIORITY_HIGH);
  562.                 }
  563.                 else
  564.                 {
  565.                         gEnv->pNetwork->SetMultithreadingMode(INetwork::NETWORK_MT_PRIORITY_NORMAL);
  566.                 }
  567.  
  568.                 SNetGameInfo gameInfo;
  569.                 gameInfo.maxPlayers = pGameStartParams->maxPlayers;
  570.                 gEnv->pNetwork->SetNetGameInfo(gameInfo);
  571.  
  572.                 InitImmersiveness();
  573.         }
  574.  
  575.         // perform some basic initialization/resetting
  576.         if (!gEnv->IsEditor())
  577.         {
  578.                 if (!gEnv->pSystem->IsSerializingFile()) //GameSerialize will reset and reserve in the right order
  579.                         gEnv->pEntitySystem->Reset();
  580.                 gEnv->pEntitySystem->ReserveEntityId(LOCAL_PLAYER_ENTITY_ID);
  581.         }
  582.  
  583.         m_pPhysicalWorld = gEnv->pPhysicalWorld;
  584.         m_pFreeCHSlot0 = m_pCHSlotPool = new SEntityCollHist[32];
  585.         int i;
  586.         for (i = 0; i < 31; i++)
  587.                 m_pCHSlotPool[i].pnext = m_pCHSlotPool + i + 1;
  588.         m_pCHSlotPool[i].pnext = m_pCHSlotPool;
  589.  
  590.         m_pEntHits0 = new SEntityHits[32];
  591.         for (i = 0; i < 32; i++)
  592.         {
  593.                 m_pEntHits0[i].pHits = &m_pEntHits0[i].hit0;
  594.                 m_pEntHits0[i].pnHits = &m_pEntHits0[i].nhits0;
  595.                 m_pEntHits0[i].nHits = 0;
  596.                 m_pEntHits0[i].nHitsAlloc = 1;
  597.                 m_pEntHits0[i].pnext = m_pEntHits0 + i + 1;
  598.                 m_pEntHits0[i].timeUsed = m_pEntHits0[i].lifeTime = 0;
  599.         }
  600.         m_pEntHits0[i - 1].pnext = 0;
  601.         m_totBreakageSize = 0;
  602.  
  603.         CCryAction::GetCryAction()->AllowSave(true);
  604.         CCryAction::GetCryAction()->AllowLoad(true);
  605.  
  606.         EnablePhysicsEvents(true);
  607.         m_bLoading = false;
  608.  
  609.         m_nEffectCounter = 0;
  610.         m_proceduralBreakFlags = ePBF_DefaultAllow | ePBT_Glass | ePBF_ObeyCVar;
  611.  
  612.         bool hasPbSvStarted = false;
  613.  
  614.         // TODO : Server announce here
  615.         if (m_pGameContext->HasContextFlag(eGSF_Server))
  616.         {
  617.                 ServerInit(pGameStartParams, &ok, &hasPbSvStarted);
  618.         }
  619.  
  620.         CreateGameStats();//Initialize stats tracking object
  621.  
  622.         if (ok && (m_pGameContext->HasContextFlag(eGSF_Client) || m_pGameContext->HasContextFlag(eGSF_DemoRecorder)))
  623.         {
  624.                 ClientInit(pGameStartParams, &ok, &hasPbSvStarted, &clientRequiresBlockingConnection);
  625.         }
  626.  
  627.         m_lastDynPoolSize = 0;
  628.  
  629.         PostInit(pGameStartParams, &ok, &clientRequiresBlockingConnection);
  630.  
  631.         return ok;
  632. }
  633.  
  634. void CActionGame::ServerInit(const SGameStartParams* pGameStartParams, bool* io_ok, bool* io_hasPbSvStarted)
  635. {
  636.         bool& ok = *io_ok;
  637.         bool& hasPbSvStarted = *io_hasPbSvStarted;
  638.  
  639.         CRY_ASSERT(m_pGameContext->GetServerPort() != 0);
  640.  
  641. #ifdef  __WITH_PB__
  642.         if (CCryAction::GetCryAction()->IsPbSvEnabled() && gEnv->bMultiplayer)
  643.         {
  644.                 gEnv->pNetwork->StartupPunkBuster(true);
  645.                 hasPbSvStarted = true;
  646.         }
  647. #endif
  648.  
  649.         m_pGameServerNub = new CGameServerNub();
  650.         m_pGameServerNub->SetGameContext(m_pGameContext);
  651.         m_pGameServerNub->SetMaxPlayers(pGameStartParams->maxPlayers);
  652.  
  653.         char address[256];
  654.         if (pGameStartParams->flags & eGSF_LocalOnly)
  655.         {
  656.                 cry_sprintf(address, "%s:%u", LOCAL_CONNECTION_STRING, pGameStartParams->port);
  657.         }
  658.         else
  659.         {
  660.                 ICVar* pCVar = gEnv->pConsole->GetCVar("sv_bind");
  661.                 if (pCVar && pCVar->GetString())
  662.                 {
  663.                         cry_sprintf(address, "%s:%u", pCVar->GetString(), pGameStartParams->port);
  664.                 }
  665.                 else
  666.                 {
  667.                         cry_sprintf(address, "0.0.0.0:%u", pGameStartParams->port);
  668.                 }
  669.         }
  670.  
  671.         IGameQuery* pGameQuery = m_pGameContext;
  672.         if (m_pGameContext->HasContextFlag(eGSF_NoQueries))
  673.                 pGameQuery = NULL;
  674.         if (m_pNetwork)
  675.                 m_pServerNub = m_pNetwork->CreateNub(address, m_pGameServerNub, 0, pGameQuery);
  676.  
  677.         if (!m_pServerNub)
  678.         {
  679.                 ok = false;
  680.         }
  681. }
  682.  
  683. void CActionGame::ClientInit(const SGameStartParams* pGameStartParams, bool* io_ok, bool* io_hasPbSvStarted, bool* io_requireBlockingConnection)
  684. {
  685.         bool& ok = *io_ok;
  686.         bool& hasPbSvStarted = *io_hasPbSvStarted;
  687.         bool& clientRequiresBlockingConnection = *io_requireBlockingConnection;
  688.  
  689. #ifdef __WITH_PB__
  690.         if (hasPbSvStarted || CCryAction::GetCryAction()->IsPbClEnabled() && gEnv->bMultiplayer)
  691.                 gEnv->pNetwork->StartupPunkBuster(false);
  692. #endif
  693.  
  694.         m_pGameClientNub = new CGameClientNub(CCryAction::GetCryAction());
  695.         m_pGameClientNub->SetGameContext(m_pGameContext);
  696.  
  697.         const char* hostname;
  698.         const char* clientname;
  699.         if (m_pGameContext->HasContextFlag(eGSF_Server))
  700.         {
  701.                 clientname = hostname = LOCAL_CONNECTION_STRING;
  702.         }
  703.         else
  704.         {
  705.                 hostname = pGameStartParams->hostname;
  706.                 clientname = "0.0.0.0";
  707.         }
  708.         CRY_ASSERT(hostname);
  709.  
  710.         string addressFormatter;
  711.         if (strchr(hostname, ':') == 0)
  712.         {
  713.                 if (pGameStartParams->session != CrySessionInvalidHandle)
  714.                 {
  715.                         addressFormatter.Format("<session>%08X,%s:%u", pGameStartParams->session, hostname, m_pGameContext->GetServerPort());
  716.                 }
  717.                 else
  718.                 {
  719.                         addressFormatter.Format("%s:%u", hostname, m_pGameContext->GetServerPort());
  720.                 }
  721.  
  722.         }
  723.         else
  724.         {
  725.                 if (pGameStartParams->session != CrySessionInvalidHandle)
  726.                 {
  727.                         addressFormatter.Format("<session>%08X,%s", pGameStartParams->session, hostname);
  728.                 }
  729.                 else
  730.                 {
  731.                         addressFormatter = hostname;
  732.                 }
  733.         }
  734.         string whereFormatter;
  735.         whereFormatter.Format("%s:0", clientname);
  736.  
  737.         ok = false;
  738.  
  739.         m_pClientNub = m_pNetwork->CreateNub(whereFormatter.c_str(), m_pGameClientNub, 0, 0);
  740.  
  741.         if (!m_pClientNub)
  742.                 return;
  743.  
  744.         if (!m_pClientNub->ConnectTo(addressFormatter.c_str(), m_pGameContext->GetConnectionString(NULL, false)))
  745.                 return;
  746.  
  747.         clientRequiresBlockingConnection |= m_pGameContext->HasContextFlag(eGSF_BlockingClientConnect);
  748.  
  749.         ok = true;
  750. }
  751.  
  752. void CActionGame::PostInit(const SGameStartParams* pGameStartParams, bool* io_ok, bool* io_requireBlockingConnection)
  753. {
  754.         const bool bIsEditor = gEnv->IsEditor();
  755.         const bool bIsDedicated = gEnv->IsDedicated();
  756.         const bool bNonBlocking = (pGameStartParams->flags & eGSF_NonBlockingConnect) != 0;
  757.  
  758.         if (!bIsEditor && !bIsDedicated && bNonBlocking)
  759.         {
  760.                 m_initState = eIS_WaitForConnection;
  761.         }
  762.         else
  763.         {
  764.                 bool& ok = *io_ok;
  765.                 bool& clientRequiresBlockingConnection = *io_requireBlockingConnection;
  766.  
  767.                 if (ok && m_pGameContext->HasContextFlag(eGSF_Server) && m_pGameContext->HasContextFlag(eGSF_Client))
  768.                         clientRequiresBlockingConnection = true;
  769.  
  770.                 if (ok && clientRequiresBlockingConnection)
  771.                 {
  772.                         ok &= BlockingConnect(&CActionGame::ConditionHaveConnection, true, "have connection");
  773.                 }
  774.  
  775.                 if (ok && m_pGameContext->HasContextFlag(eGSF_Server) && !ChangeGameContext(pGameStartParams->pContextParams))
  776.                 {
  777.                         ok = false;
  778.                 }
  779.  
  780.                 if (ok && m_pGameStats)
  781.                         m_pGameStats->StartSession();
  782.  
  783.                 if (ok && m_pGameContext->HasContextFlag(eGSF_BlockingClientConnect) && !m_pGameContext->HasContextFlag(eGSF_NoSpawnPlayer) && m_pGameContext->HasContextFlag(eGSF_Client))
  784.                 {
  785.                         ok &= BlockingConnect(&CActionGame::ConditionHavePlayer, true, "have player");
  786.                 }
  787.  
  788.                 if (ok && m_pGameContext->HasContextFlag(eGSF_BlockingMapLoad))
  789.                 {
  790.                         ok &= BlockingConnect(&CActionGame::ConditionInGame, false, "in game");
  791.                 }
  792.  
  793.                 m_initState = eIS_InitDone;
  794.         }
  795. }
  796.  
  797. void CActionGame::LogModeInformation(const bool isMultiplayer, const char* hostname) const
  798. {
  799.         assert(gEnv->pSystem);
  800.  
  801.         if (gEnv->IsEditor())
  802.         {
  803.                 CryLogAlways("Starting in Editor mode");
  804.         }
  805.         else if (gEnv->IsDedicated())
  806.         {
  807.                 CryLogAlways("Starting in Dedicated server mode");
  808.         }
  809.         else if (!isMultiplayer)
  810.         {
  811.                 CryLogAlways("Starting in Singleplayer mode");
  812.         }
  813.         else if (IsServer())
  814.         {
  815.                 CryLogAlways("Starting in Server mode");
  816.         }
  817.         else if (m_pGameContext->HasContextFlag(eGSF_Client))
  818.         {
  819.                 CryLogAlways("Starting in Client mode");
  820.                 string address = hostname;
  821.                 size_t position = address.find(":");
  822.                 if (position != string::npos)
  823.                 {
  824.                         address = address.substr(0, position);
  825.                 }
  826.                 CryLogAlways("ServerName: %s", address.c_str());
  827.         }
  828. }
  829.  
  830. void CActionGame::UpdateImmersiveness()
  831. {
  832.         bool procMP = !m_pGameContext->HasContextFlag(eGSF_LocalOnly);
  833.         bool immMP = m_pGameContext->HasContextFlag(eGSF_ImmersiveMultiplayer);
  834.         m_proceduralBreakFlags =
  835.           (int)/*(!procMP) **/ ePBF_ObeyCVar +
  836.           (int)procMP * ePBF_AllowGlass +
  837.           (int)(immMP || !procMP) * ePBF_DefaultAllow;
  838.         if (!m_pGameContext->HasContextFlag(eGSF_Server))
  839.                 m_proceduralBreakFlags &= ~(ePBF_DefaultAllow | ePBF_AllowGlass);
  840.         bool isServer = m_pGameContext->HasContextFlag(eGSF_Server);
  841.  
  842.         PhysicsVars* physVars = gEnv->pPhysicalWorld->GetPhysVars();
  843.         physVars->breakImpulseScale = 1.0f * (isServer && (immMP || !procMP && g_joint_breaking));
  844.  
  845.         if (g_breakageNoDebrisCollisions)
  846.         {
  847.                 // Make debris collide with only static geometry
  848.                 physVars->massLimitDebris = 1000.f;
  849.                 physVars->flagsColliderDebris = geom_colltype_debris;
  850.                 physVars->flagsANDDebris = geom_colltype_solid;
  851.         }
  852.         else
  853.         {
  854.                 physVars->massLimitDebris = 1e10f;
  855.                 MARK_UNUSED physVars->flagsColliderDebris;
  856.                 physVars->flagsANDDebris = ~0;
  857.         }
  858.  
  859.         // If set to 1.0f, this forces broken trees to have spherical inertia, which makes them harder to spin about their vertical axis
  860.         physVars->breakageMinAxisInertia = g_breakageMinAxisInertia;
  861.  
  862.         if (gEnv->bMultiplayer && gEnv->bServer)
  863.         {
  864.                 if (immMP)
  865.                 {
  866.                         static ICVar* pLength = gEnv->pConsole->GetCVar("sv_timeofdaylength");
  867.                         static ICVar* pStart = gEnv->pConsole->GetCVar("sv_timeofdaystart");
  868.                         static ICVar* pTOD = gEnv->pConsole->GetCVar("sv_timeofdayenable");
  869.  
  870.                         ITimeOfDay::SAdvancedInfo advancedInfo;
  871.                         gEnv->p3DEngine->GetTimeOfDay()->GetAdvancedInfo(advancedInfo);
  872.  
  873.                         advancedInfo.fAnimSpeed = 0.0f;
  874.                         if (pTOD && pTOD->GetIVal())
  875.                         {
  876.                                 advancedInfo.fStartTime = pStart ? pStart->GetFVal() : 0.0f;
  877.                                 advancedInfo.fEndTime = 24.0f;
  878.                                 if (pLength)
  879.                                 {
  880.                                         float lengthInHours = pLength->GetFVal();
  881.                                         if (lengthInHours > 0.01f)
  882.                                         {
  883.                                                 lengthInHours = CLAMP(pLength->GetFVal(), 0.2f, 24.0f);
  884.                                                 advancedInfo.fAnimSpeed = 1.0f / lengthInHours / 150.0f;
  885.                                         }
  886.                                         advancedInfo.fEndTime = advancedInfo.fStartTime + lengthInHours;
  887.                                 }
  888.                         }
  889.                         gEnv->p3DEngine->GetTimeOfDay()->SetAdvancedInfo(advancedInfo);
  890.                 }
  891.         }
  892.  
  893.         if (immMP && !m_pGameContext->HasContextFlag(eGSF_Server))
  894.                 gEnv->p3DEngine->GetTimeOfDay()->SetTimer(CServerTimer::Get());
  895.         else
  896.                 gEnv->p3DEngine->GetTimeOfDay()->SetTimer(gEnv->pTimer);
  897. }
  898.  
  899. void CActionGame::InitImmersiveness()
  900. {
  901.         bool immMP = m_pGameContext->HasContextFlag(eGSF_ImmersiveMultiplayer);
  902.         UpdateImmersiveness();
  903.  
  904.         if (gEnv->bMultiplayer)
  905.         {
  906.                 gEnv->pSystem->SetConfigSpec(immMP ? CONFIG_VERYHIGH_SPEC : CONFIG_LOW_SPEC, false);
  907.                 if (immMP)
  908.                 {
  909.                         if (gEnv->pConsole->GetCVar("sv_timeofdayenable")->GetIVal())
  910.                         {
  911.                                 static ICVar* pStart = gEnv->pConsole->GetCVar("sv_timeofdaystart");
  912.                                 static ICVar* pTOD = gEnv->pConsole->GetCVar("e_TimeOfDay");
  913.                                 if (pStart && pTOD)
  914.                                         pTOD->Set(pStart->GetFVal());
  915.                         }
  916.                 }
  917.         }
  918. }
  919.  
  920. bool CActionGame::BlockingSpawnPlayer()
  921. {
  922.         CAdjustLocalConnectionPacketRate adjuster(50.0f, 30.0f);
  923.  
  924.         assert(gEnv->IsEditor());
  925.  
  926.         if (!m_pGameContext)
  927.                 return false;
  928.         if (!m_pGameContext->HasContextFlag(eGSF_BlockingClientConnect) || !m_pGameContext->HasContextFlag(eGSF_NoSpawnPlayer))
  929.                 return false;
  930.         if (!m_pGameServerNub)
  931.                 return false;
  932.         TServerChannelMap* pChannelMap = m_pGameServerNub->GetServerChannelMap();
  933.         if (!pChannelMap)
  934.                 return false;
  935.         if (pChannelMap->size() != 1)
  936.                 return false;
  937.         CGameServerChannel* pChannel = pChannelMap->begin()->second;
  938.  
  939.         m_pGameContext->AllowCallOnClientConnect();
  940.  
  941.         return BlockingConnect(&CActionGame::ConditionInGame, true, "in game");
  942. }
  943.  
  944. bool CActionGame::ConditionHaveConnection(CGameClientChannel* pChannel)
  945. {
  946.         return pChannel->GetNetChannel()->IsConnectionEstablished();
  947. }
  948.  
  949. bool CActionGame::ConditionHavePlayer(CGameClientChannel* pChannel)
  950. {
  951.         return pChannel->GetPlayerId() != 0;
  952. }
  953.  
  954. bool CActionGame::ConditionInGame(CGameClientChannel* pChannel)
  955. {
  956.         return CCryAction::GetCryAction()->IsGameStarted() && !CCryAction::GetCryAction()->IsGamePaused();
  957. }
  958.  
  959. CActionGame::eInitTaskState CActionGame::NonBlockingConnect(BlockingConditionFunction condition, bool requireClientChannel, const char* conditionText)
  960. {
  961.         bool done = false;
  962.  
  963.         CGameClientChannel* pChannel = NULL;
  964.         if (requireClientChannel)
  965.         {
  966.                 if (!m_pGameClientNub)
  967.                 {
  968.                         GameWarning("NonBlockingConnect: Client nub doesn't exist while waiting for condition '%s'", conditionText);
  969.                         return eITS_Error;
  970.                 }
  971.                 pChannel = m_pGameClientNub->GetGameClientChannel();
  972.                 if (!pChannel && IsStale()) // '||' => '&&' (see notes below)
  973.                 {
  974.                         GameWarning("NonBlockingConnect: Disconnected while waiting for condition '%s'", conditionText);
  975.                         return eITS_Error;
  976.                 }
  977.         }
  978.         // NOTE: because now we have pre-channel hand-shaking (key exchange), it is legal that
  979.         // a GameChannel will be created a while later than a GameNub is created - Lin
  980.         if (!requireClientChannel || pChannel)
  981.                 done = (this->*condition)(pChannel);
  982.  
  983.         return (done ? eITS_Done : eITS_InProgress);
  984. }
  985.  
  986. bool CActionGame::BlockingConnect(BlockingConditionFunction condition, bool requireClientChannel, const char* conditionText)
  987. {
  988.         LOADING_TIME_PROFILE_SECTION
  989.         MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_Other, 0, "BlockingConnect");
  990.  
  991.         bool ok = false;
  992.  
  993.         ITimer* pTimer = gEnv->pTimer;
  994.         CTimeValue startTime = pTimer->GetAsyncTime();
  995.  
  996.         while (!ok)
  997.         {
  998.                 m_pNetwork->SyncWithGame(eNGS_FrameStart);
  999.                 m_pNetwork->SyncWithGame(eNGS_FrameEnd);
  1000.                 m_pNetwork->SyncWithGame(eNGS_WakeNetwork);
  1001.                 gEnv->pTimer->UpdateOnFrameStart();
  1002.                 CGameClientChannel* pChannel = NULL;
  1003.                 if (requireClientChannel)
  1004.                 {
  1005.                         if (!m_pGameClientNub)
  1006.                         {
  1007.                                 GameWarning("BlockingConnect: Client nub doesn't exist while waiting for condition '%s' (after %.2f seconds)", conditionText, (pTimer->GetAsyncTime() - startTime).GetSeconds());
  1008.                                 break;
  1009.                         }
  1010.                         pChannel = m_pGameClientNub->GetGameClientChannel();
  1011.                         if (!pChannel && IsStale()) // '||' => '&&' (see notes below)
  1012.                         {
  1013.                                 GameWarning("BlockingConnect: Disconnected while waiting for condition '%s' (after %.2f seconds)", conditionText, (pTimer->GetAsyncTime() - startTime).GetSeconds());
  1014.                                 break;
  1015.                         }
  1016.                 }
  1017.                 // NOTE: because now we have pre-channel hand-shaking (key exchange), it is legal that
  1018.                 // a GameChannel will be created a while later than a GameNub is created - Lin
  1019.                 if (!requireClientChannel || pChannel)
  1020.                         ok |= (this->*condition)(pChannel);
  1021.  
  1022.                 if (!gEnv || !gEnv->pSystem || gEnv->pSystem->IsQuitting())
  1023.                         break;                                                      // FIX DT- 20377 PC : SP : DESIGN : CRASH : Pure function call engine error followed by title crash when user hits X button or uses Alt F4 during loading screen
  1024.         }
  1025.  
  1026.         if (ok && gEnv && !gEnv->IsEditor())
  1027.         {
  1028.                 float numSecondsTaken = (pTimer->GetAsyncTime() - startTime).GetSeconds();
  1029.  
  1030.                 if (numSecondsTaken > 2.0f)
  1031.                 {
  1032.                         GameWarning("BlockingConnect: It's taken %.2f seconds to achieve condition '%s' - either you're on slow connection, or you're doing something intensive", numSecondsTaken, conditionText);
  1033.                 }
  1034.         }
  1035.  
  1036.         if (ok == false)
  1037.         {
  1038.                 float numSecondsTaken = (pTimer->GetAsyncTime() - startTime).GetSeconds();
  1039.                 CryLog("BlockingConnect: Failed to achieve condition '%s' (tried for %.2f seconds)", conditionText, numSecondsTaken);
  1040.         }
  1041.  
  1042.         return ok;
  1043. }
  1044.  
  1045. bool CActionGame::ChangeGameContext(const SGameContextParams* pGameContextParams)
  1046. {
  1047.         if (!IsServer())
  1048.         {
  1049.                 GameWarning("Can't ChangeGameContext() on client");
  1050.                 CRY_ASSERT(!"Can't ChangeGameContext() on client");
  1051.                 return false;
  1052.         }
  1053.  
  1054.         CRY_ASSERT(pGameContextParams);
  1055.  
  1056.         return m_pGameContext->ChangeContext(true, pGameContextParams);
  1057. }
  1058.  
  1059. IActor* CActionGame::GetClientActor()
  1060. {
  1061.         if (!m_pGameClientNub)
  1062.                 return NULL;
  1063.  
  1064.         CGameClientChannel* pGameClientChannel = m_pGameClientNub->GetGameClientChannel();
  1065.         if (!pGameClientChannel)
  1066.                 return NULL;
  1067.         EntityId playerId = pGameClientChannel->GetPlayerId();
  1068.         if (!playerId)
  1069.                 return NULL;
  1070.         if (m_pGameContext->GetNetContext()->IsDemoPlayback())
  1071.                 return gEnv->pGameFramework->GetIActorSystem()->GetCurrentDemoSpectator();
  1072.  
  1073.         //ID caching causes problems in the editor
  1074.         if (m_clientActorID != playerId || gEnv->IsEditor())
  1075.         {
  1076.                 m_clientActorID = playerId;
  1077.                 m_pClientActor = CCryAction::GetCryAction()->GetIActorSystem()->GetActor(playerId);
  1078.         }
  1079.  
  1080.         return m_pClientActor;
  1081. }
  1082.  
  1083. bool CActionGame::ControlsEntity(EntityId id)
  1084. {
  1085.         return m_pGameContext->ControlsEntity(id);
  1086. }
  1087.  
  1088. bool CActionGame::Update()
  1089. {
  1090.         if (m_initState == eIS_InitDone)
  1091.         {
  1092.                 const float deltaTime = gEnv->pTimer->GetFrameTime();
  1093.                 _smart_ptr<CActionGame> pThis(this);
  1094.  
  1095.                 IGameRulesSystem* pgrs;
  1096.                 IGameRules* pgr;
  1097.                 if (m_pGameContext && (pgrs = m_pGameContext->GetFramework()->GetIGameRulesSystem()) && (pgr = pgrs->GetCurrentGameRules()))
  1098.                         pgr->AddHitListener(this);
  1099.                 UpdateImmersiveness();
  1100.  
  1101.                 CServerTimer::Get()->UpdateOnFrameStart();
  1102.  
  1103. #ifdef _GAMETOKENSDEBUGINFO
  1104.                 if (m_pGameTokenSystem)
  1105.                         m_pGameTokenSystem->DebugDraw();
  1106. #endif
  1107.  
  1108.                 if (g_breakage_debug)
  1109.                         DrawBrokenMeshes();
  1110.                 UpdateBrokenMeshes(deltaTime);
  1111.  
  1112.                 if (gEnv->bMultiplayer)
  1113.                 {
  1114.                         m_throttling.m_brokenTreeCounter -= g_breakageTreeDec;
  1115.                         if (m_throttling.m_brokenTreeCounter < 0)
  1116.                                 m_throttling.m_brokenTreeCounter = 0;
  1117.                         if (m_throttling.m_numGlassEvents > 0)
  1118.                                 m_throttling.m_numGlassEvents--;
  1119.                         UpdateFadeEntities(deltaTime);
  1120.                 }
  1121.  
  1122.                 if (m_pGameStats && IsServer())
  1123.                         m_pGameStats->Update();
  1124.  
  1125.                 if (s_waterMaterialId == -1)
  1126.                 {
  1127.                         s_waterMaterialId = gEnv->p3DEngine->GetMaterialManager()->GetSurfaceTypeManager()->GetSurfaceTypeByName("mat_water")->GetId();
  1128.                 }
  1129.                 // if the game context returns true, then it wants to abort it's mission
  1130.                 // that probably means that loading the level failed... and in any case
  1131.                 // it also probably means that we've been deleted.
  1132.                 // only call IsStale if the game context indicates it's not yet finished
  1133.                 // (returns false) - is stale will check if we're a client based system
  1134.                 // and still have an active client
  1135.                 return (m_pGameContext && m_pGameContext->Update()) || IsStale();
  1136.         }
  1137.         else
  1138.         {
  1139.                 switch (m_initState)
  1140.                 {
  1141.                 case eIS_WaitForConnection:
  1142.                         {
  1143.                                 eInitTaskState done = NonBlockingConnect(&CActionGame::ConditionHaveConnection, true, "have connection");
  1144.  
  1145.                                 if (done == eITS_Error)
  1146.                                 {
  1147.                                         m_initState = eIS_InitError;
  1148.                                         break;
  1149.                                 }
  1150.                                 else if (done == eITS_Done)
  1151.                                 {
  1152.                                         if (m_pGameContext->HasContextFlag(eGSF_Server) && !ChangeGameContext(m_startGameParams.pContextParams))
  1153.                                         {
  1154.                                                 m_initState = eIS_InitError;
  1155.                                                 break;
  1156.                                         }
  1157.  
  1158.                                         if (m_pGameStats)
  1159.                                         {
  1160.                                                 m_pGameStats->StartSession();
  1161.                                         }
  1162.  
  1163.                                         m_initState = eIS_WaitForPlayer;
  1164.                                 }
  1165.                                 break;
  1166.                         }
  1167.  
  1168.                 case eIS_WaitForPlayer:
  1169.                         {
  1170.                                 const bool bNoSpawnPlayer = m_pGameContext->HasContextFlag(eGSF_NoSpawnPlayer);
  1171.                                 const bool bClient = m_pGameContext->HasContextFlag(eGSF_Client);
  1172.  
  1173.                                 if (!bNoSpawnPlayer && bClient)
  1174.                                 {
  1175.                                         eInitTaskState done = NonBlockingConnect(&CActionGame::ConditionHavePlayer, true, "have player");
  1176.  
  1177.                                         if (done == eITS_Error)
  1178.                                         {
  1179.                                                 m_initState = eIS_InitError;
  1180.                                                 break;
  1181.                                         }
  1182.                                         else if (done == eITS_Done)
  1183.                                         {
  1184.                                                 m_initState = eIS_WaitForInGame;
  1185.                                         }
  1186.                                 }
  1187.                                 else
  1188.                                 {
  1189.                                         m_initState = eIS_WaitForInGame;
  1190.                                 }
  1191.                         }
  1192.                         break;
  1193.  
  1194.                 case eIS_WaitForInGame:
  1195.                         {
  1196.                                 eInitTaskState done = NonBlockingConnect(&CActionGame::ConditionInGame, false, "in game");
  1197.  
  1198.                                 if (done == eITS_Error)
  1199.                                 {
  1200.                                         m_initState = eIS_InitError;
  1201.                                         break;
  1202.                                 }
  1203.                                 else if (done == eITS_Done)
  1204.                                 {
  1205.                                         m_initState = eIS_InitDone;
  1206.                                 }
  1207.                         }
  1208.                         break;
  1209.  
  1210.                 default:
  1211.                 case eIS_InitError:
  1212.                         // returning true causes this ActionGame object to be deleted
  1213.                         return true;
  1214.                 }
  1215.         }
  1216.  
  1217.         return false;
  1218. }
  1219.  
  1220. void CActionGame::OnBreakageSpawnedEntity(IEntity* pEntity, IPhysicalEntity* pPhysEntity, IPhysicalEntity* pSrcPhysEntity)
  1221. {
  1222.         // For now this is MP only
  1223.         assert(gEnv->bMultiplayer);
  1224.  
  1225.         // The breakable manager spawned a new entity - add it to the fade list
  1226.         if (pSrcPhysEntity != pPhysEntity)
  1227.         {
  1228.                 DynArray<SEntityFadeState>::iterator it = m_fadeEntities.push_back();
  1229.                 it->entId = pEntity->GetId();
  1230.                 it->time = 0.f;
  1231.                 it->bCollisions = 1;
  1232.         }
  1233. }
  1234.  
  1235. void CActionGame::UpdateFadeEntities(float dt)
  1236. {
  1237.         if (const int N = m_fadeEntities.size())
  1238.         {
  1239.                 int n = 0;
  1240.                 SEntityFadeState* p = &m_fadeEntities[0];
  1241.                 const float inv = 1.f / (g_breakageFadeTime + 0.01f);
  1242.                 for (int i = 0; i < N; i++)
  1243.                 {
  1244.                         SEntityFadeState* state = &m_fadeEntities[i];
  1245.                         if (IEntity* pEntity = gEnv->pEntitySystem->GetEntity(state->entId))
  1246.                         {
  1247.                                 {
  1248.                                         const float newTime = state->time + dt;
  1249.                                         const float t = newTime - g_breakageFadeDelay;
  1250.                                         IPhysicalEntity* pent = pEntity->GetPhysics();
  1251.                                         if (t >= g_breakageFadeTime)
  1252.                                         {
  1253.                                                 FreeBrokenMeshesForEntity(pent);
  1254.                                                 continue;
  1255.                                         }
  1256.                                         if (t > 0.f)
  1257.                                         {
  1258.                                                 float opacity = 1.f - t * inv;
  1259.                                                 pEntity->SetOpacity(opacity);
  1260.                                                 if (pent && state->bCollisions)
  1261.                                                 {
  1262.                                                         // Turn off some collisions
  1263.                                                         // NB: by leaving pe_params_part.ipart undefined, all the geom flags will changed
  1264.                                                         pe_params_part pp;
  1265.                                                         pp.flagsAND = ~(geom_colltype_ray | geom_colltype_vehicle | geom_colltype_player);
  1266.                                                         pent->SetParams(&pp);
  1267.                                                         state->bCollisions = 0;
  1268.                                                 }
  1269.                                         }
  1270.                                         state->time = newTime;
  1271.                                         *p = *state;
  1272.                                         ++n;
  1273.                                         ++p;
  1274.                                 }
  1275.                         }
  1276.                 }
  1277.                 if (n != N)
  1278.                 {
  1279.                         m_fadeEntities.resize(n);
  1280.                 }
  1281.         }
  1282. }
  1283.  
  1284. IGameObject* CActionGame::GetEntityGameObject(IEntity* pEntity)
  1285. {
  1286.         return static_cast<CGameObject*>(pEntity ? pEntity->GetProxy(ENTITY_PROXY_USER) : 0);
  1287. }
  1288.  
  1289. IGameObject* CActionGame::GetPhysicalEntityGameObject(IPhysicalEntity* pPhysEntity)
  1290. {
  1291.         IEntity* pEntity = gEnv->pEntitySystem->GetEntityFromPhysics(pPhysEntity);
  1292.         if (pEntity)
  1293.                 return static_cast<CGameObject*>(pEntity->GetProxy(ENTITY_PROXY_USER));
  1294.         return 0;
  1295. }
  1296.  
  1297. bool CActionGame::IsStale()
  1298. {
  1299.         if (m_pGameClientNub && m_pClientNub)
  1300.                 if (!m_pClientNub->IsConnecting() && !m_pGameClientNub->GetGameClientChannel() && !CCryAction::GetCryAction()->IsGameSessionMigrating())
  1301.                         return true;
  1302.  
  1303.         return false;
  1304. }
  1305.  
  1306. /////////////////////////////////////////////////////////////////////////////
  1307. // Host Migration listener
  1308. IHostMigrationEventListener::EHostMigrationReturn CActionGame::OnInitiate(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
  1309. {
  1310.         if (!hostMigrationInfo.ShouldMigrateNub())
  1311.         {
  1312.                 return IHostMigrationEventListener::Listener_Done;
  1313.         }
  1314.  
  1315.         CryLogAlways("[Host Migration]: CActionGame::OnInitiate() started");
  1316.  
  1317.         if (gEnv->pInput)
  1318.         {
  1319.                 //disable rumble
  1320.                 gEnv->pInput->ForceFeedbackEvent(SFFOutputEvent(eIDT_Gamepad, eFF_Rumble_Basic, SFFTriggerOutputData::Initial::ZeroIt, 0.0f, 0.0f, 0.0f));
  1321.         }
  1322.         IForceFeedbackSystem* pForceFeedbackSystem = gEnv->pGameFramework->GetIForceFeedbackSystem();
  1323.         if (pForceFeedbackSystem)
  1324.         {
  1325.                 pForceFeedbackSystem->StopAllEffects();
  1326.         }
  1327.  
  1328.         // Save any state information that needs preserving across the migration
  1329.         IActorSystem* pActorSystem = gEnv->pGameFramework->GetIActorSystem();
  1330.  
  1331.         if (s_this->m_pGameClientNub == NULL)
  1332.         {
  1333.                 return IHostMigrationEventListener::Listener_Terminate;
  1334.         }
  1335.  
  1336.         // Store migrating player name (used for the migrating connection handshake string)
  1337.         CGameClientChannel* pGameClientChannel = s_this->m_pGameClientNub->GetGameClientChannel();
  1338.         if (pGameClientChannel != NULL)
  1339.         {
  1340.                 hostMigrationInfo.m_playerID = pGameClientChannel->GetPlayerId();
  1341.                 IActor* pActor = pActorSystem->GetActor(hostMigrationInfo.m_playerID);
  1342.  
  1343.                 if (pActor)
  1344.                 {
  1345.                         hostMigrationInfo.SetMigratedPlayerName(pActor->GetEntity()->GetName());
  1346.                 }
  1347.                 else
  1348.                 {
  1349.                         CryLogAlways("[Host Migration]: no actor found - aborting");
  1350.                         return IHostMigrationEventListener::Listener_Terminate;
  1351.                 }
  1352.         }
  1353.  
  1354.         CryLogAlways("[Host Migration]: CActionGame::OnInitiate() finished");
  1355.         return IHostMigrationEventListener::Listener_Done;
  1356. }
  1357.  
  1358. IHostMigrationEventListener::EHostMigrationReturn CActionGame::OnDisconnectClient(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
  1359. {
  1360.         if (!hostMigrationInfo.ShouldMigrateNub())
  1361.         {
  1362.                 return IHostMigrationEventListener::Listener_Done;
  1363.         }
  1364.  
  1365.         bool done = false;
  1366.  
  1367.         switch (state)
  1368.         {
  1369.         case eDS_Disconnect:
  1370.                 CryLogAlways("[Host Migration]: CActionGame::OnDisconnectClient() started");
  1371.                 // Do the disconnect
  1372.                 if (m_pGameClientNub)
  1373.                 {
  1374.                         m_pGameClientNub->Disconnect(eDC_UserRequested, "Host migrating");
  1375.                 }
  1376.                 if (m_pClientNub != NULL)
  1377.                 {
  1378.                         m_pClientNub->DeleteNub();
  1379.                         m_pClientNub = NULL;
  1380.                 }
  1381.                 else
  1382.                 {
  1383.                         CryLog("[Host Migration]: CActionGame::OnDisconnectClient() - m_pClientNub is NULL");
  1384.                 }
  1385.  
  1386.                 // TODO: Don't think SyncWithGame(eNGS_Shutdown) is necessary
  1387.                 //s_this->m_pNetwork->SyncWithGame(eNGS_Shutdown);
  1388.  
  1389.                 state = eDS_Disconnecting;
  1390.                 break;
  1391.  
  1392.         case eDS_Disconnecting:
  1393.                 CryLogAlways("[Host Migration]: CActionGame::OnDisconnectClient() waiting");
  1394.                 // Wait for the disconnect to complete
  1395.                 if (m_pGameClientNub)
  1396.                 {
  1397.                         if (m_pGameClientNub->GetGameClientChannel() == NULL)
  1398.                         {
  1399.                                 state = eDS_Disconnected;
  1400.                         }
  1401.                 }
  1402.                 else
  1403.                 {
  1404.                         state = eDS_Disconnected;
  1405.                 }
  1406.                 break;
  1407.  
  1408.         case eDS_Disconnected: // Intentional fall-through
  1409.                 if (CCryAction::GetCryAction()->GetIMaterialEffects())
  1410.                 {
  1411.                         // This is a speculative fix for a crash that happened where a delayed decal was created that referenced a deleted CStatObj on a host migration.
  1412.                         // Curiously it was a bit of glass (probably broken) and its ref count was -1 (!). So this won't fix the cause, but should help stop that particular crash.
  1413.                         CCryAction::GetCryAction()->GetIMaterialEffects()->ClearDelayedEffects();
  1414.                 }
  1415.  
  1416.                 CryLogAlways("[Host Migration]: CActionGame::OnDisconnectClient() finished");
  1417.         default:
  1418.                 done = true;
  1419.                 break;
  1420.         }
  1421.  
  1422.         if (done)
  1423.         {
  1424.                 return IHostMigrationEventListener::Listener_Done;
  1425.         }
  1426.  
  1427.         return IHostMigrationEventListener::Listener_Wait;
  1428. }
  1429.  
  1430. IHostMigrationEventListener::EHostMigrationReturn CActionGame::OnDemoteToClient(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
  1431. {
  1432.         if (!hostMigrationInfo.ShouldMigrateNub())
  1433.         {
  1434.                 return IHostMigrationEventListener::Listener_Done;
  1435.         }
  1436.  
  1437.         CryLogAlways("[Host Migration]: CActionGame::OnDemoteToClient() started");
  1438.  
  1439.         if (s_this->m_pServerNub)
  1440.         {
  1441.                 s_this->m_pServerNub->DeleteNub();
  1442.                 s_this->m_pServerNub = NULL;
  1443.         }
  1444.  
  1445.         gEnv->bServer = false;
  1446.  
  1447.         CryLogAlways("[Host Migration]: CActionGame::OnDemoteToClient() finished");
  1448.         return IHostMigrationEventListener::Listener_Done;
  1449. }
  1450.  
  1451. IHostMigrationEventListener::EHostMigrationReturn CActionGame::OnPromoteToServer(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
  1452. {
  1453.         if (!hostMigrationInfo.ShouldMigrateNub())
  1454.         {
  1455.                 return IHostMigrationEventListener::Listener_Done;
  1456.         }
  1457.  
  1458.         CryLogAlways("[Host Migration]: CActionGame::OnPromoteToServer() started");
  1459.  
  1460.         // Create a server on this machine
  1461.         gEnv->bServer = true;
  1462.  
  1463.         // Pause to allow the feature tester to run host migration tests on a single pc, must be after bServer is set so that other OnPromoteToServer listeners work
  1464. #ifndef _RELEASE
  1465.         if (g_hostMigrationServerDelay > 0.f)
  1466.         {
  1467.                 const CTimeValue currentTime = gEnv->pTimer->GetAsyncTime();
  1468.                 const float currentTimeInSeconds = currentTime.GetSeconds();
  1469.  
  1470.                 if (m_timeToPromoteToServer == 0.f)
  1471.                 {
  1472.                         m_timeToPromoteToServer = currentTimeInSeconds + g_hostMigrationServerDelay;
  1473.                         return IHostMigrationEventListener::Listener_Wait;
  1474.                 }
  1475.  
  1476.                 if (currentTimeInSeconds < m_timeToPromoteToServer)
  1477.                 {
  1478.                         return IHostMigrationEventListener::Listener_Wait;
  1479.                 }
  1480.         }
  1481. #endif
  1482.  
  1483.         IConsole* pConsole = gEnv->pConsole;
  1484.         ICVar* pCVar = pConsole->GetCVar("sv_maxplayers");
  1485.         int maxPlayers = pCVar->GetIVal();
  1486.  
  1487.         // Set the server name
  1488.         IPlayerProfileManager* pPlayerProfileManager = gEnv->pGameFramework->GetIPlayerProfileManager();
  1489.         CryFixedStringT<128> serverName(s_this->m_pNetwork->GetHostName());
  1490.         serverName.append(" ");
  1491.         serverName.append(pPlayerProfileManager->GetCurrentProfile(pPlayerProfileManager->GetCurrentUser())->GetName());
  1492.         gEnv->pConsole->GetCVar("sv_servername")->Set(serverName.c_str());
  1493.  
  1494.         // Create a new game server nub
  1495.         s_this->m_pGameServerNub = new CGameServerNub();
  1496.         s_this->m_pGameServerNub->SetGameContext(s_this->m_pGameContext);
  1497.         s_this->m_pGameServerNub->SetMaxPlayers(maxPlayers);
  1498.  
  1499.         char address[MAX_ADDRESS_SIZE];
  1500.         pCVar = gEnv->pConsole->GetCVar("sv_bind");
  1501.         if (pCVar && pCVar->GetString())
  1502.         {
  1503.                 cry_sprintf(address, "%s:%u", pCVar->GetString(), s_this->m_pGameContext->GetServerPort());
  1504.         }
  1505.         else
  1506.         {
  1507.                 cry_sprintf(address, "0.0.0.0:%u", s_this->m_pGameContext->GetServerPort());
  1508.         }
  1509.  
  1510.         IGameQuery* pGameQuery = s_this->m_pGameContext;
  1511.         if (s_this->m_pGameContext->HasContextFlag(eGSF_NoQueries))
  1512.         {
  1513.                 pGameQuery = NULL;
  1514.         }
  1515.  
  1516.         if (s_this->m_pNetwork)
  1517.         {
  1518.                 s_this->m_pServerNub = s_this->m_pNetwork->CreateNub(address, s_this->m_pGameServerNub, 0, pGameQuery);
  1519.         }
  1520.  
  1521.         if (s_this->m_pServerNub == NULL)
  1522.         {
  1523.                 // Failed
  1524.                 CryLogAlways("Host migration error: unable to create server");
  1525.                 return IHostMigrationEventListener::Listener_Terminate;
  1526.         }
  1527.  
  1528.         CryLogAlways("[Host Migration]: CActionGame::OnPromoteToServer() finished");
  1529. #ifndef _RELEASE
  1530.         m_timeToPromoteToServer = 0.f;
  1531. #endif
  1532.         return IHostMigrationEventListener::Listener_Done;
  1533. }
  1534.  
  1535. IHostMigrationEventListener::EHostMigrationReturn CActionGame::OnReconnectClient(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
  1536. {
  1537.         if (!hostMigrationInfo.ShouldMigrateNub())
  1538.         {
  1539.                 return IHostMigrationEventListener::Listener_Done;
  1540.         }
  1541.  
  1542.         bool done = false;
  1543.  
  1544.         switch (state)
  1545.         {
  1546.         case eRS_Reconnect:
  1547.                 {
  1548.                         CryLogAlways("[Host Migration]: CActionGame::OnReconnectClient() started");
  1549.  
  1550.                         // Initiate client reconnection to the migrated server
  1551.                         s_this->m_pGameClientNub->SetGameContext(s_this->m_pGameContext);
  1552.  
  1553.                         // Create a new client nub
  1554.                         CryFixedStringT<64> address;
  1555.                         address.Format("%s:0", (hostMigrationInfo.IsNewHost() ? LOCAL_CONNECTION_STRING : "0.0.0.0"));
  1556.                         s_this->m_pClientNub = s_this->m_pNetwork->CreateNub(address.c_str(), s_this->m_pGameClientNub, NULL, NULL);
  1557.  
  1558.                         bool succeeded = false;
  1559.                         if (s_this->m_pClientNub)
  1560.                         {
  1561.                                 // Attempt to connect our client nub to the newly created server
  1562.                                 address.Format("<session>%08X,%s", hostMigrationInfo.m_session, hostMigrationInfo.m_newServer.c_str());
  1563.  
  1564.                                 CryLogAlways("[Host Migration]: Will use %s as connection address", address.c_str());
  1565.  
  1566.                                 // Migrating players take the name originally assigned to them by the server (e.g. andy(2))
  1567.                                 if (s_this->m_pClientNub->ConnectTo(address.c_str(), s_this->m_pGameContext->GetConnectionString(&hostMigrationInfo.m_migratedPlayerName, false)))
  1568.                                 {
  1569.                                         succeeded = true;
  1570.                                         state = eRS_Reconnecting;
  1571.                                 }
  1572.                         }
  1573.  
  1574.                         if (!succeeded)
  1575.                         {
  1576.                                 state = eRS_Terminated;
  1577.                         }
  1578.                 }
  1579.                 break;
  1580.  
  1581.         case eRS_Reconnecting:
  1582.                 CryLogAlways("[Host Migration]: CActionGame::OnReconnectClient() waiting");
  1583.  
  1584.                 // Wait for the reconnect to complete
  1585.                 if (s_this->m_pGameClientNub->GetGameClientChannel() != NULL)
  1586.                 {
  1587.                         s_this->m_pGameClientNub->GetGameClientChannel()->SetPlayerIdOnMigration(hostMigrationInfo.m_playerID);
  1588.                         state = eRS_Reconnected;
  1589.                 }
  1590.                 break;
  1591.  
  1592.         case eRS_Terminated:
  1593.                 // Failed
  1594.                 CryLogAlways("Host migration error: unable to reconnect client");
  1595.                 return IHostMigrationEventListener::Listener_Terminate;
  1596.  
  1597.         case eRS_Reconnected: // Intentional fall-through
  1598.                 CryLogAlways("[Host Migration]: CActionGame::OnReconnectClient() finished");
  1599.         default:
  1600.                 if (hostMigrationInfo.IsNewHost())
  1601.                 {
  1602.                         // Store the server channel so that CNetContext can take ownership of game entities
  1603.                         hostMigrationInfo.m_pServerChannel = s_this->m_pGameServerNub->GetLocalChannel();
  1604.                 }
  1605.                 done = true;
  1606.                 break;
  1607.         }
  1608.  
  1609.         if (done)
  1610.         {
  1611.                 return IHostMigrationEventListener::Listener_Done;
  1612.         }
  1613.         return IHostMigrationEventListener::Listener_Wait;
  1614. }
  1615.  
  1616. IHostMigrationEventListener::EHostMigrationReturn CActionGame::OnFinalise(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
  1617. {
  1618.         if (!hostMigrationInfo.ShouldMigrateNub())
  1619.         {
  1620.                 return IHostMigrationEventListener::Listener_Done;
  1621.         }
  1622.  
  1623.         CryLogAlways("[Host Migration]: CActionGame::OnFinalise() started");
  1624.  
  1625.         if (!gEnv->bServer && s_this->m_pGameServerNub)
  1626.         {
  1627.                 // If this is a demoted server, deferred deletion of the game
  1628.                 // server nub happens here instead of OnDemoteToClient() to
  1629.                 // allow channels the chance to disconnect (different thread)
  1630.                 SAFE_DELETE(s_this->m_pGameServerNub);
  1631.         }
  1632.  
  1633.         CryLogAlways("[Host Migration]: CActionGame::OnFinalise() finished");
  1634.         return IHostMigrationEventListener::Listener_Done;
  1635. }
  1636.  
  1637. IHostMigrationEventListener::EHostMigrationReturn CActionGame::OnTerminate(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
  1638. {
  1639.         return IHostMigrationEventListener::Listener_Done;
  1640. }
  1641.  
  1642. IHostMigrationEventListener::EHostMigrationReturn CActionGame::OnReset(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
  1643. {
  1644.         return IHostMigrationEventListener::Listener_Done;
  1645. }
  1646. /////////////////////////////////////////////////////////////////////////////
  1647.  
  1648. void CActionGame::AddGlobalPhysicsCallback(int event, void (* proc)(const EventPhys*, void*), void* userdata)
  1649. {
  1650.         int idx = (event & (0xff << 8)) != 0;
  1651.         if (event & eEPE_OnCollisionLogged || event & eEPE_OnCollisionImmediate)
  1652.                 m_globalPhysicsCallbacks.collision[idx].insert(TGlobalPhysicsCallbackSet::value_type(proc, userdata));
  1653.  
  1654.         if (event & eEPE_OnPostStepLogged || event & eEPE_OnPostStepImmediate)
  1655.                 m_globalPhysicsCallbacks.postStep[idx].insert(TGlobalPhysicsCallbackSet::value_type(proc, userdata));
  1656.  
  1657.         if (event & eEPE_OnStateChangeLogged || event & eEPE_OnStateChangeImmediate)
  1658.                 m_globalPhysicsCallbacks.stateChange[idx].insert(TGlobalPhysicsCallbackSet::value_type(proc, userdata));
  1659.  
  1660.         if (event & eEPE_OnCreateEntityPartLogged || event & eEPE_OnCreateEntityPartImmediate)
  1661.                 m_globalPhysicsCallbacks.createEntityPart[idx].insert(TGlobalPhysicsCallbackSet::value_type(proc, userdata));
  1662.  
  1663.         if (event & eEPE_OnUpdateMeshLogged || event & eEPE_OnUpdateMeshImmediate)
  1664.                 m_globalPhysicsCallbacks.updateMesh[idx].insert(TGlobalPhysicsCallbackSet::value_type(proc, userdata));
  1665. }
  1666.  
  1667. void CActionGame::RemoveGlobalPhysicsCallback(int event, void (* proc)(const EventPhys*, void*), void* userdata)
  1668. {
  1669.         int idx = (event & (0xff << 8)) != 0;
  1670.         if (event & eEPE_OnCollisionLogged || event & eEPE_OnCollisionImmediate)
  1671.                 m_globalPhysicsCallbacks.collision[idx].erase(TGlobalPhysicsCallbackSet::value_type(proc, userdata));
  1672.  
  1673.         if (event & eEPE_OnPostStepLogged || event & eEPE_OnPostStepImmediate)
  1674.                 m_globalPhysicsCallbacks.postStep[idx].erase(TGlobalPhysicsCallbackSet::value_type(proc, userdata));
  1675.  
  1676.         if (event & eEPE_OnStateChangeLogged || event & eEPE_OnStateChangeImmediate)
  1677.                 m_globalPhysicsCallbacks.stateChange[idx].erase(TGlobalPhysicsCallbackSet::value_type(proc, userdata));
  1678.  
  1679.         if (event & eEPE_OnCreateEntityPartLogged || event & eEPE_OnCreateEntityPartImmediate)
  1680.                 m_globalPhysicsCallbacks.createEntityPart[idx].erase(TGlobalPhysicsCallbackSet::value_type(proc, userdata));
  1681.  
  1682.         if (event & eEPE_OnUpdateMeshLogged || event & eEPE_OnUpdateMeshImmediate)
  1683.                 m_globalPhysicsCallbacks.updateMesh[idx].erase(TGlobalPhysicsCallbackSet::value_type(proc, userdata));
  1684. }
  1685.  
  1686. void CActionGame::EnablePhysicsEvents(bool enable)
  1687. {
  1688.         IPhysicalWorld* pPhysicalWorld = gEnv->pPhysicalWorld;
  1689.  
  1690.         if (!pPhysicalWorld)
  1691.                 return;
  1692.  
  1693.         if (enable)
  1694.         {
  1695.  
  1696.                 pPhysicalWorld->AddEventClient(EventPhysBBoxOverlap::id, OnBBoxOverlap, 1);
  1697.                 pPhysicalWorld->AddEventClient(EventPhysCollision::id, OnCollisionLogged, 1);
  1698.                 pPhysicalWorld->AddEventClient(EventPhysPostStep::id, OnPostStepLogged, 1);
  1699.                 pPhysicalWorld->AddEventClient(EventPhysStateChange::id, OnStateChangeLogged, 1);
  1700.                 pPhysicalWorld->AddEventClient(EventPhysCreateEntityPart::id, OnCreatePhysicalEntityLogged, 1, 0.1f);
  1701.                 pPhysicalWorld->AddEventClient(EventPhysUpdateMesh::id, OnUpdateMeshLogged, 1, 0.1f);
  1702.                 pPhysicalWorld->AddEventClient(EventPhysRemoveEntityParts::id, OnRemovePhysicalEntityPartsLogged, 1, 2.0f);
  1703.                 pPhysicalWorld->AddEventClient(EventPhysCollision::id, OnCollisionImmediate, 0);
  1704.                 pPhysicalWorld->AddEventClient(EventPhysPostStep::id, OnPostStepImmediate, 0);
  1705.                 pPhysicalWorld->AddEventClient(EventPhysStateChange::id, OnStateChangeImmediate, 0);
  1706.                 pPhysicalWorld->AddEventClient(EventPhysCreateEntityPart::id, OnCreatePhysicalEntityImmediate, 0, 10.0f);
  1707.                 pPhysicalWorld->AddEventClient(EventPhysUpdateMesh::id, OnUpdateMeshImmediate, 0, 10.0f);
  1708.                 pPhysicalWorld->AddEventClient(EventPhysEntityDeleted::id, OnPhysEntityDeleted, 0);
  1709.         }
  1710.         else
  1711.         {
  1712.                 pPhysicalWorld->RemoveEventClient(EventPhysBBoxOverlap::id, OnBBoxOverlap, 1);
  1713.                 pPhysicalWorld->RemoveEventClient(EventPhysCollision::id, OnCollisionLogged, 1);
  1714.                 pPhysicalWorld->RemoveEventClient(EventPhysPostStep::id, OnPostStepLogged, 1);
  1715.                 pPhysicalWorld->RemoveEventClient(EventPhysStateChange::id, OnStateChangeLogged, 1);
  1716.                 pPhysicalWorld->RemoveEventClient(EventPhysCreateEntityPart::id, OnCreatePhysicalEntityLogged, 1);
  1717.                 pPhysicalWorld->RemoveEventClient(EventPhysUpdateMesh::id, OnUpdateMeshLogged, 1);
  1718.                 pPhysicalWorld->RemoveEventClient(EventPhysRemoveEntityParts::id, OnRemovePhysicalEntityPartsLogged, 1);
  1719.                 pPhysicalWorld->RemoveEventClient(EventPhysCollision::id, OnCollisionImmediate, 0);
  1720.                 pPhysicalWorld->RemoveEventClient(EventPhysPostStep::id, OnPostStepImmediate, 0);
  1721.                 pPhysicalWorld->RemoveEventClient(EventPhysStateChange::id, OnStateChangeImmediate, 0);
  1722.                 pPhysicalWorld->RemoveEventClient(EventPhysCreateEntityPart::id, OnCreatePhysicalEntityImmediate, 0);
  1723.                 pPhysicalWorld->RemoveEventClient(EventPhysUpdateMesh::id, OnUpdateMeshImmediate, 0);
  1724.                 pPhysicalWorld->RemoveEventClient(EventPhysEntityDeleted::id, OnPhysEntityDeleted, 0);
  1725.         }
  1726. }
  1727.  
  1728. int CActionGame::OnBBoxOverlap(const EventPhys* pEvent)
  1729. {
  1730.         EventPhysBBoxOverlap* pOverlap = (EventPhysBBoxOverlap*)pEvent;
  1731.         IEntity* pEnt = 0;
  1732.         pEnt = GetEntity(pOverlap->iForeignData[0], pOverlap->pForeignData[0]);
  1733.  
  1734.         if (pOverlap->iForeignData[1] == PHYS_FOREIGN_ID_STATIC)
  1735.         {
  1736.                 pe_status_rope sr;
  1737.                 IRenderNode* rn = (IRenderNode*)pOverlap->pEntity[1]->GetForeignData(PHYS_FOREIGN_ID_STATIC);
  1738.  
  1739.                 if (rn != NULL && eERType_Vegetation == rn->GetRenderNodeType())
  1740.                 {
  1741.                         bool hit_veg = false;
  1742.                         int idx = 0;
  1743.                         IPhysicalEntity* phys = rn->GetBranchPhys(idx);
  1744.                         while (phys != 0)
  1745.                         {
  1746.                                 phys->GetStatus(&sr);
  1747.  
  1748.                                 if (sr.nCollDyn > 0)
  1749.                                 {
  1750.                                         hit_veg = true;
  1751.                                         break;
  1752.                                 }
  1753.                                 //CryLogAlways("colldyn: %d collstat: %d", sr.nCollDyn, sr.nCollStat);
  1754.                                 idx++;
  1755.                                 phys = rn->GetBranchPhys(idx);
  1756.                         }
  1757.                         if (hit_veg && pEnt)
  1758.                         {
  1759.                                 bool play_sound = false;
  1760.                                 if (s_this->m_vegStatus.find(pEnt->GetId()) == s_this->m_vegStatus.end())
  1761.                                 {
  1762.                                         play_sound = true;
  1763.                                         s_this->m_vegStatus[pEnt->GetId()] = pEnt->GetWorldPos();
  1764.                                 }
  1765.                                 else
  1766.                                 {
  1767.                                         float distSquared = (pEnt->GetWorldPos() - s_this->m_vegStatus[pEnt->GetId()]).GetLengthSquared();
  1768.                                         if (distSquared > 2.0f * 2.0f)
  1769.                                         {
  1770.                                                 play_sound = true;
  1771.                                                 s_this->m_vegStatus[pEnt->GetId()] = pEnt->GetWorldPos();
  1772.                                         }
  1773.                                 }
  1774.                                 if (play_sound)
  1775.                                 {
  1776.                                         IMaterialEffects* pMaterialEffects = CCryAction::GetCryAction()->GetIMaterialEffects();
  1777.                                         TMFXEffectId effectId = pMaterialEffects ? pMaterialEffects->GetEffectIdByName("vegetation", PathUtil::GetFileName(rn->GetName())) : InvalidEffectId;
  1778.                                         if (effectId != InvalidEffectId)
  1779.                                         {
  1780.                                                 SMFXRunTimeEffectParams params;
  1781.                                                 params.pos = rn->GetBBox().GetCenter();
  1782.                                                 //params.soundSemantic = eSoundSemantic_Physics_General;
  1783.  
  1784.                                                 pe_status_dynamics dyn;
  1785.  
  1786.                                                 if (pOverlap->pEntity[0])
  1787.                                                 {
  1788.                                                         pOverlap->pEntity[0]->GetStatus(&dyn);
  1789.                                                         const float speed = min(1.0f, dyn.v.GetLengthSquared() / (10.0f * 10.0f));
  1790.                                                         params.AddAudioRtpc("speed", speed);
  1791.                                                 }
  1792.                                                 pMaterialEffects->ExecuteEffect(effectId, params);
  1793.                                         }
  1794.                                 }
  1795.                         }
  1796.                 }
  1797.         }
  1798.         return 1;
  1799. }
  1800.  
  1801. int CActionGame::OnCollisionLogged(const EventPhys* pEvent)
  1802. {
  1803.         FUNCTION_PROFILER(GetISystem(), PROFILE_ACTION);
  1804.  
  1805.         for (TGlobalPhysicsCallbackSet::const_iterator it = s_this->m_globalPhysicsCallbacks.collision[0].begin();
  1806.              it != s_this->m_globalPhysicsCallbacks.collision[0].end();
  1807.              ++it)
  1808.         {
  1809.                 it->first(pEvent, it->second);
  1810.         }
  1811.  
  1812.         const EventPhysCollision* pCollision = static_cast<const EventPhysCollision*>(pEvent);
  1813.         IGameRules::SGameCollision gameCollision;
  1814.         memset(&gameCollision, 0, sizeof(IGameRules::SGameCollision));
  1815.         gameCollision.pCollision = pCollision;
  1816.         if (pCollision->iForeignData[0] == PHYS_FOREIGN_ID_ENTITY)
  1817.         {
  1818.                 //gameCollision.pSrcEntity = gEnv->pEntitySystem->GetEntityFromPhysics(gameCollision.pCollision->pEntity[0]);
  1819.                 gameCollision.pSrcEntity = (IEntity*)pCollision->pForeignData[0];
  1820.                 gameCollision.pSrc = GetEntityGameObject(gameCollision.pSrcEntity);
  1821.         }
  1822.         if (pCollision->iForeignData[1] == PHYS_FOREIGN_ID_ENTITY)
  1823.         {
  1824.                 //gameCollision.pTrgEntity = gEnv->pEntitySystem->GetEntityFromPhysics(gameCollision.pCollision->pEntity[1]);
  1825.                 gameCollision.pTrgEntity = (IEntity*)pCollision->pForeignData[1];
  1826.                 gameCollision.pTrg = GetEntityGameObject(gameCollision.pTrgEntity);
  1827.         }
  1828.  
  1829.         SGameObjectEvent event(eGFE_OnCollision, eGOEF_ToExtensions | eGOEF_ToGameObject | eGOEF_LoggedPhysicsEvent);
  1830.         event.ptr = (void*)pCollision;
  1831.         if (gameCollision.pSrc && gameCollision.pSrc->WantsPhysicsEvent(eEPE_OnCollisionLogged))
  1832.                 gameCollision.pSrc->SendEvent(event);
  1833.         if (gameCollision.pTrg && gameCollision.pTrg->WantsPhysicsEvent(eEPE_OnCollisionLogged))
  1834.                 gameCollision.pTrg->SendEvent(event);
  1835.  
  1836.         if (gameCollision.pSrc)
  1837.         {
  1838.                 IRenderNode* pNode = NULL;
  1839.                 if (pCollision->iForeignData[1] == PHYS_FOREIGN_ID_ENTITY)
  1840.                 {
  1841.                         IEntity* pTarget = (IEntity*)pCollision->pForeignData[1];
  1842.                         if (pTarget)
  1843.                         {
  1844.                                 pNode = pTarget->GetRenderNode();
  1845.                         }
  1846.                 }
  1847.                 else if (pCollision->iForeignData[1] == PHYS_FOREIGN_ID_STATIC)
  1848.                         pNode = (IRenderNode*)pCollision->pForeignData[1];
  1849.                 /*else
  1850.                    if (pCollision->iForeignData[1] == PHYS_FOREIGN_ID_FOLIAGE)
  1851.                    {
  1852.                    CStatObjFoliage *pFolliage = (CStatObjFoliage*)pCollision->pForeignData[1];
  1853.                    if (pFolliage)
  1854.                     pNode = pFolliage->m_pVegInst;
  1855.                    }*/
  1856.                 if (pNode)
  1857.                         gEnv->p3DEngine->SelectEntity(pNode);
  1858.         }
  1859.  
  1860.         IGameRules* pGameRules = s_this->m_pGameContext->GetFramework()->GetIGameRulesSystem()->GetCurrentGameRules();
  1861.         if (pGameRules)
  1862.         {
  1863.                 if (!pGameRules->OnCollision(gameCollision))
  1864.                         return 0;
  1865.  
  1866.                 pGameRules->OnCollision_NotifyAI(pEvent);
  1867.         }
  1868.  
  1869.         OnCollisionLogged_Breakable(pEvent);
  1870.         OnCollisionLogged_MaterialFX(pEvent);
  1871.  
  1872.         return 1;
  1873. }
  1874.  
  1875. bool CActionGame::ProcessHitpoints(const Vec3& pt, IPhysicalEntity* pent, int partid, ISurfaceType* pMat, int iDamage)
  1876. {
  1877.         if (m_bLoading)
  1878.                 return true;
  1879.         int i, imin, id;
  1880.         Vec3 ptloc;
  1881.         SEntityHits* phits;
  1882.         pe_status_pos sp;
  1883.         std::map<int, SEntityHits*>::iterator iter;
  1884.         float curtime = gEnv->pTimer->GetCurrTime();
  1885.         sp.partid = partid;
  1886.         if (!pent->GetStatus(&sp))
  1887.                 return false;
  1888.         ptloc = (pt - sp.pos) * sp.q;
  1889.  
  1890.         id = m_pPhysicalWorld->GetPhysicalEntityId(pent) * 256 + partid;
  1891.         if ((iter = m_mapEntHits.find(id)) != m_mapEntHits.end())
  1892.                 phits = iter->second;
  1893.         else
  1894.         {
  1895.                 for (phits = m_pEntHits0; phits->timeUsed + phits->lifeTime > curtime && phits->pnext; phits = phits->pnext)
  1896.                         ;
  1897.                 if (phits->timeUsed + phits->lifeTime > curtime)
  1898.                 {
  1899.                         phits->pnext = new SEntityHits[32];
  1900.                         for (i = 0; i < 32; i++)
  1901.                         {
  1902.                                 phits->pnext[i].pHits = &phits->pnext[i].hit0;
  1903.                                 phits->pnext[i].pnHits = &phits->pnext[i].nhits0;
  1904.                                 phits->pnext[i].nHits = 0;
  1905.                                 phits->pnext[i].nHitsAlloc = 1;
  1906.                                 phits->pnext[i].pnext = phits->pnext + i + 1;
  1907.                                 phits->pnext[i].timeUsed = phits->pnext[i].lifeTime = 0;
  1908.                         }
  1909.                         phits->pnext[i - 1].pnext = 0;
  1910.                         phits = phits->pnext;
  1911.                 }
  1912.                 phits->nHits = 0;
  1913.                 phits->hitRadius = 100.0f;
  1914.                 phits->hitpoints = 1;
  1915.                 phits->maxdmg = 100;
  1916.                 phits->nMaxHits = 64;
  1917.                 phits->lifeTime = 10.0f;
  1918.                 const ISurfaceType::SPhysicalParams& physParams = pMat->GetPhyscalParams();
  1919.                 phits->hitRadius = physParams.hit_radius;
  1920.                 phits->hitpoints = (int)physParams.hit_points;
  1921.                 phits->maxdmg = (int)physParams.hit_maxdmg;
  1922.                 phits->lifeTime = physParams.hit_lifetime;
  1923.                 m_mapEntHits.insert(std::pair<int, SEntityHits*>(id, phits));
  1924.         }
  1925.         phits->timeUsed = curtime;
  1926.  
  1927.         for (i = 1, imin = 0; i < phits->nHits; i++)
  1928.                 if ((phits->pHits[i] - ptloc).len2() < (phits->pHits[imin] - ptloc).len2())
  1929.                         imin = i;
  1930.         if (phits->nHits == 0 || (phits->pHits[imin] - ptloc).len2() > sqr(phits->hitRadius) && phits->nHits < phits->nMaxHits)
  1931.         {
  1932.                 if (phits->nHitsAlloc == phits->nHits)
  1933.                 {
  1934.                         Vec3* pts = phits->pHits;
  1935.                         memcpy(phits->pHits = new Vec3[phits->nHitsAlloc = phits->nHits + 1], pts, phits->nHits * sizeof(Vec3));
  1936.                         if (pts != &phits->hit0) delete[] pts;
  1937.                         int* ns = phits->pnHits;
  1938.                         memcpy(phits->pnHits = new int[phits->nHitsAlloc], ns, phits->nHits * sizeof(int));
  1939.                         if (ns != &phits->nhits0) delete[] ns;
  1940.                 }
  1941.                 phits->pHits[imin = phits->nHits] = ptloc;
  1942.                 phits->pnHits[phits->nHits++] = min(phits->maxdmg, iDamage);
  1943.         }
  1944.         else
  1945.         {
  1946.                 iDamage = min(phits->maxdmg, iDamage);
  1947.                 phits->pHits[imin] = (phits->pHits[imin] * (float)phits->pnHits[imin] + ptloc * (float)iDamage) / (float)(phits->pnHits[imin] + iDamage);
  1948.                 phits->pnHits[imin] += iDamage;
  1949.         }
  1950.  
  1951.         if (phits->pnHits[imin] >= phits->hitpoints)
  1952.         {
  1953.                 memmove(phits->pHits + imin, phits->pHits + imin + 1, (phits->nHits - imin - 1) * sizeof(phits->pHits[0]));
  1954.                 memmove(phits->pnHits + imin, phits->pnHits + imin + 1, (phits->nHits - imin - 1) * sizeof(phits->pnHits[0]));
  1955.                 --phits->nHits;
  1956.                 phits->hitpoints = FtoI(pMat->GetPhyscalParams().hit_points_secondary);
  1957.                 return true;
  1958.         }
  1959.         return false;
  1960. }
  1961.  
  1962. SBreakEvent& CActionGame::RegisterBreakEvent(const EventPhysCollision* pColl, float energy)
  1963. {
  1964.         if (m_bLoading)
  1965.                 return m_breakEvents[m_iCurBreakEvent];
  1966.  
  1967.         BreakLogAlways("   CActionGame::RegisterBreakEvent() - generating break event for store");
  1968.         SBreakEvent be;
  1969.         memset(&be, 0, sizeof(be));
  1970.         IEntity* pEntity;
  1971.         pe_status_pos sp;
  1972.  
  1973.         switch (be.itype = pColl->iForeignData[1])
  1974.         {
  1975.         case PHYS_FOREIGN_ID_ENTITY:
  1976.                 be.idEnt = (pEntity = (IEntity*)pColl->pForeignData[1])->GetId();
  1977.                 pColl->pEntity[1]->GetStatus(&sp);
  1978.                 be.pos = sp.pos;
  1979.                 be.rot = sp.q;
  1980.                 be.scale = pEntity->GetScale();
  1981.                 break;
  1982.         case PHYS_FOREIGN_ID_STATIC:
  1983.                 IRenderNode* pVeg = (IRenderNode*)pColl->pForeignData[1];
  1984.                 be.eventPos = pColl->pt;
  1985.                 be.hash = CObjectSelector::CalculateHash(pVeg, true);
  1986.                 break;
  1987.         }
  1988.  
  1989.         be.pt = pColl->pt;
  1990.         be.n = pColl->n;
  1991.         be.vloc[0] = pColl->vloc[0];
  1992.         be.vloc[1] = pColl->vloc[1];
  1993.         be.mass[0] = pColl->mass[0];
  1994.         be.mass[1] = pColl->mass[1];
  1995.         be.idmat[0] = pColl->idmat[0];
  1996.         be.idmat[1] = pColl->idmat[1];
  1997.         be.partid[0] = pColl->partid[0];
  1998.         be.partid[1] = pColl->partid[1];
  1999.         be.iPrim[0] = pColl->iPrim[0];
  2000.         be.iPrim[1] = pColl->iPrim[1];
  2001.         be.penetration = pColl->penetration;
  2002.         be.energy = energy;
  2003.         be.radius = pColl->radius;
  2004.         be.time = gEnv->pTimer->GetCurrTime();
  2005.         be.iBrokenObjectIndex = -1;
  2006.  
  2007.         return StoreBreakEvent(be);
  2008. }
  2009.  
  2010. /////////////////////////////////
  2011. // Store break event for later playback. This should only occur with break events that
  2012. //              have been received over the network or generated locally
  2013. SBreakEvent& CActionGame::StoreBreakEvent(const SBreakEvent& breakEvent)
  2014. {
  2015.         BreakLogAlways("   CActionGame::StoreBreakEvent() - logging to m_breakEvents");
  2016.         m_breakEvents.push_back(breakEvent);
  2017.         m_breakEvents.back().iState = eBES_Processed;
  2018.         CCryAction::GetCryAction()->OnBreakEvent(static_cast<uint16>(m_breakEvents.size() - 1));
  2019.  
  2020.         return m_breakEvents.back();
  2021. }
  2022.  
  2023. void CActionGame::PerformPlaneBreak(const EventPhysCollision& epc, SBreakEvent* pRecordedEvent, int flags, CDelayedPlaneBreak* pDelayedTask)
  2024. {
  2025.         // TODO: improve
  2026.         bool actuallyLoading = s_this->m_bLoading;
  2027.  
  2028.         class CRestoreLoadingFlag
  2029.         {
  2030.         public:
  2031.                 CRestoreLoadingFlag() : m_bLoading(s_this->m_bLoading) {}
  2032.                 ~CRestoreLoadingFlag() { s_this->m_bLoading = m_bLoading; }
  2033.  
  2034.         private:
  2035.                 bool m_bLoading;
  2036.         };
  2037.         CRestoreLoadingFlag restoreLoadingFlag;
  2038.  
  2039.         if (pRecordedEvent)
  2040.                 s_this->m_bLoading = true; // fake loading here
  2041.  
  2042.         pe_params_part pp;
  2043.         IStatObj* pStatObj = 0;
  2044.         IStatObj* pStatObjHost = 0;
  2045.         IStatObj::SSubObject* pSubObj;
  2046.         IRenderNode* pBrush;
  2047.         IMaterial* pRenderMat;
  2048.         IPhysicalEntity* pPhysEnt;
  2049.         float r = epc.radius;
  2050.         pp.pMatMapping = 0;
  2051.         pp.flagsOR = geom_can_modify;
  2052.         Matrix34A mtx;
  2053.         SProcBrokenObjRec rec;
  2054.         rec.itype = epc.pEntity[1] ? epc.pEntity[1]->GetiForeignData() : epc.iForeignData[1];
  2055.         rec.mass = -1.0f;
  2056.         rec.pBrush = NULL;
  2057.         rec.pStatObjOrg = NULL;
  2058.         ISurfaceTypeManager* pSurfaceTypeManager = gEnv->p3DEngine->GetMaterialManager()->GetSurfaceTypeManager();
  2059.         ISurfaceType* pMat = pSurfaceTypeManager->GetSurfaceType(epc.idmat[1]);
  2060.         if (!pMat)
  2061.                 return;
  2062.  
  2063.         ISurfaceType::SBreakable2DParams* pb2d = pMat->GetBreakable2DParams();
  2064.         float timeout = 0.0f;
  2065.         const char* killFX = 0;
  2066.         if (pb2d)
  2067.         {
  2068.                 timeout = pb2d->destroy_timeout + pb2d->destroy_timeout_spread * cry_random(-1.0f, 1.0f);
  2069.                 killFX = pb2d->full_fracture_fx;
  2070.                 if (!pb2d->blast_radius_first && !pb2d->blast_radius)
  2071.                         r = 0.0f;
  2072.                 else if (!pb2d->blast_radius_first && (epc.vloc[0].len2() < sqr(100.0f) || epc.mass[0] > 1.0f))
  2073.                         r = max(r, 100.0f); // make sure larger particles (grenades) shatter 'no-holes' windows
  2074.         }
  2075.  
  2076.         if (g_glassForceTimeout != 0.f)
  2077.         {
  2078.                 timeout = g_glassForceTimeout + cry_random(0.0f, 1.0f) * g_glassForceTimeoutSpread;
  2079.         }
  2080.  
  2081.         //IEntity* pEntitySrc = epc.pEntity[0] ? (IEntity*)epc.pEntity[0]->GetForeignData(PHYS_FOREIGN_ID_ENTITY) : 0;
  2082.         IEntity* pEntityTrg = epc.pEntity[1] ? (IEntity*)epc.pEntity[1]->GetForeignData(PHYS_FOREIGN_ID_ENTITY) : 0;
  2083.  
  2084.         if (pEntityTrg && rec.itype == PHYS_FOREIGN_ID_ENTITY)
  2085.         {
  2086.                 BreakLogAlways("> PHYS_FOREIGN_ID_ENTITY");
  2087.                 assert(pEntityTrg);
  2088.                 if ((pStatObj = pEntityTrg->GetStatObj(ENTITY_SLOT_ACTUAL)) &&
  2089.                     (pStatObj->GetFlags() & (STATIC_OBJECT_COMPOUND | STATIC_OBJECT_CLONE)) == STATIC_OBJECT_COMPOUND)
  2090.                 {
  2091.                         SProcBrokenObjRec rec1;
  2092.                         pe_params_part ppt;
  2093.                         rec1.itype = PHYS_FOREIGN_ID_ENTITY;
  2094.                         rec1.islot = -1;
  2095.                         rec1.idEnt = pEntityTrg->GetId();
  2096.                         (rec1.pStatObjOrg = pStatObj)->AddRef();
  2097.                         pe_status_nparts status_nparts;
  2098.                         for (rec1.mass = 0, ppt.ipart = epc.pEntity[1]->GetStatus(&status_nparts) - 1; ppt.ipart >= 0; ppt.ipart--)
  2099.                         {
  2100.                                 MARK_UNUSED ppt.partid;
  2101.                                 if (epc.pEntity[1]->GetParams(&ppt) != 0)
  2102.                                         rec1.mass += ppt.mass;
  2103.                         }
  2104.                         s_this->m_brokenObjs.push_back(rec1);
  2105.                 }
  2106.                 pStatObj = pEntityTrg->GetStatObj(epc.partid[1]);
  2107.                 mtx = pEntityTrg->GetSlotWorldTM(epc.partid[1]);
  2108.                 pRenderMat = (pEntityTrg->GetRenderInterface())->GetRenderMaterial(epc.partid[1]);
  2109.                 // FIXME, workaround
  2110.                 if ((pRenderMat && !_stricmp(pRenderMat->GetName(), "default") || !pRenderMat) && pStatObj && pStatObj->GetMaterial())
  2111.                         pRenderMat = pStatObj->GetMaterial();
  2112.                 // ~FIXME
  2113.                 pPhysEnt = pEntityTrg->GetPhysics();
  2114.                 rec.idEnt = pEntityTrg->GetId();
  2115.                 rec.islot = epc.partid[1];
  2116.         }
  2117.         else if (rec.itype == PHYS_FOREIGN_ID_STATIC)
  2118.         {
  2119.                 BreakLogAlways("> PHYS_FOREIGN_ID_STATIC");
  2120.                 pStatObj = (pBrush = ((IRenderNode*)epc.pForeignData[1]))->GetEntityStatObj(0, 0, &mtx);
  2121.                 if (pStatObj && pStatObj->GetFlags() & STATIC_OBJECT_COMPOUND)
  2122.                 {
  2123.                         if (pSubObj = (pStatObjHost = pStatObj)->GetSubObject(epc.partid[1]))
  2124.                         {
  2125.                                 pStatObj = pSubObj->pStatObj;
  2126.                                 if (!pSubObj->bIdentityMatrix)
  2127.                                         mtx = mtx * pSubObj->tm;
  2128.                         }
  2129.                         else
  2130.                                 pStatObj = 0;
  2131.                 }
  2132.                 pPhysEnt = ((IRenderNode*)epc.pForeignData[1])->GetPhysics();
  2133.                 pRenderMat = pBrush->GetMaterial();
  2134.                 rec.pBrush = pBrush;
  2135.                 rec.islot = 0;
  2136.         }
  2137.  
  2138.         int iBrokenObjectIndex = -1;
  2139.         bool bEntityMustBreakGlass = false;
  2140.         bool bIsClientBreak = false;  // Did the client break this bit of glass
  2141.  
  2142.         if (pStatObj)
  2143.         {
  2144.                 if (!pDelayedTask && ((!pRecordedEvent || pRecordedEvent->iState == eBES_Generated)) && !(pStatObj->GetFlags() & STATIC_OBJECT_GENERATED))
  2145.                 {
  2146.                         if (epc.pEntity[0] && epc.pEntity[0]->GetType() == PE_LIVING)
  2147.                         {
  2148.                                 IEntity* pEntitySrc = (IEntity*)epc.pEntity[0]->GetForeignData(PHYS_FOREIGN_ID_ENTITY);
  2149.                                 IActor* pActor = pEntitySrc ? gEnv->pGameFramework->GetIActorSystem()->GetActor(pEntitySrc->GetId()) : NULL;
  2150.                                 if (!pActor || !pActor->CanBreakGlass())
  2151.                                 {
  2152.                                         return;
  2153.                                 }
  2154.                                 else
  2155.                                 {
  2156.                                         bEntityMustBreakGlass = pActor->MustBreakGlass();
  2157.                                 }
  2158.                         }
  2159.                 }
  2160.                 SBreakEvent& be = pRecordedEvent ? *pRecordedEvent :
  2161.                                   (pDelayedTask ? s_this->m_breakEvents[pDelayedTask->m_iBreakEvent] : s_this->RegisterBreakEvent(&epc, 0));
  2162.  
  2163.                 // Is the break event in the event list ?
  2164.                 const int breakEventSize = s_this->m_breakEvents.size();
  2165.                 const SBreakEvent* breaks = &(*(s_this->m_breakEvents.begin()));
  2166.                 bool bIsStoredEvent = (breakEventSize > 0) && (&be >= breaks) && (&be < (breaks + breakEventSize));
  2167.  
  2168.                 if (!pDelayedTask)
  2169.                 {
  2170.                         //If this is a locally generated break event, or a recorded one that has arrived via
  2171.                         //      the network, we want to do full processing on it, and record it for later playback
  2172.                         if (!pRecordedEvent || pRecordedEvent->iState == eBES_Generated)
  2173.                         {
  2174.                                 if (!(pStatObj->GetFlags() & STATIC_OBJECT_GENERATED))
  2175.                                 {
  2176.                                         BreakLogAlways("> Marked as original brush, not generated");
  2177.  
  2178.                                         //================================================
  2179.                                         // We now allow clients to break the glass
  2180.                                         // The server will also only send the first break
  2181.                                         // Secondary breaks will be sent for client-joins
  2182.                                         //================================================
  2183.                                         if (pRecordedEvent == NULL && !s_this->IsServer() && (flags & ePPB_PlaybackEvent) == 0)
  2184.                                         {
  2185.                                                 bIsClientBreak = true;
  2186.                                         }
  2187.  
  2188.                                         //Some breaks resulting in new StatObj do not result in the STATIC_OBJECT_GENERATED
  2189.                                         //      flag being set, so we want to check the existing broken objects list for a brush match.
  2190.                                         //      We're not checking for a statobj match, because new statobjs can be generated that will
  2191.                                         //      not match with the original, and we want to record the index of the original for
  2192.                                         //      later reversion in the kill cam
  2193.                                         for (int i = 0; i < s_this->m_brokenObjs.size(); i++)
  2194.                                         {
  2195.                                                 //assert(s_this->m_brokenObjs[i].pBrush);
  2196.                                                 if (s_this->m_brokenObjs[i].pBrush == rec.pBrush)
  2197.                                                 {
  2198.                                                         BreakLogAlways(">> Found brush match at index %d", i);
  2199.                                                         iBrokenObjectIndex = i;
  2200.                                                         break;
  2201.                                                 }
  2202.                                         }
  2203.  
  2204.                                         //If there  is not an already-existing record of the object being broken, generate a new one
  2205.                                         if (iBrokenObjectIndex == -1)
  2206.                                         {
  2207.                                                 (rec.pStatObjOrg = pStatObjHost ? pStatObjHost : pStatObj)->AddRef();
  2208.                                                 s_this->m_brokenObjs.push_back(rec);
  2209.                                                 iBrokenObjectIndex = s_this->m_brokenObjs.size() - 1;
  2210.                                                 BreakLogAlways("  Adding new statobj break at index %d, statobj 0x%p, original statobj 0x%p, brush 0x%p, original is %shost", iBrokenObjectIndex, pStatObj, rec.pStatObjOrg, rec.pBrush, pStatObjHost ? "" : "not ");
  2211.                                         }
  2212.                                 }
  2213.                                 else
  2214.                                 {
  2215.                                         //The object is a generated one, and should therefore already be in the broken objects list
  2216.                                         //      find the existing entry in the broken objects list and use the index from that
  2217.                                         if (rec.itype == PHYS_FOREIGN_ID_STATIC)
  2218.                                         {
  2219.                                                 BreakLogAlways("> Searching m_brokenObjs for match, StatObj marked as generated");
  2220.                                                 for (int i = 0; i < s_this->m_brokenObjs.size(); i++)
  2221.                                                 {
  2222.                                                         assert(s_this->m_brokenObjs[i].pBrush);
  2223.                                                         BreakLogAlways(">>  Index: %0d, pBrush 0x%p", i, s_this->m_brokenObjs[i].pBrush);
  2224.                                                         if (s_this->m_brokenObjs[i].pBrush == rec.pBrush)
  2225.                                                         {
  2226.                                                                 BreakLogAlways(">>>  Found existing pBrush break at index %d, statobj 0x%p  <<<", i, pStatObj);
  2227.                                                                 iBrokenObjectIndex = i;
  2228.                                                                 break;
  2229.                                                         }
  2230.                                                 }
  2231.                                         }
  2232.  
  2233.                                         //TODO: This code to be used when glass breakage on entities is working in killcam
  2234.  
  2235.                                         //        if(iBrokenObjectIndex == -1)
  2236.                                         //        {
  2237.                                         //          BreakLogAlways(">>>  Failed to find existing statobj break, looking for pBrush: 0x%p  <<<\n>>>  Now searching on EntityID (NOT PTR) 0x%08X", rec.pBrush, rec.idEnt);
  2238.                                         //          for(int i = 0; i < s_this->m_brokenObjs.size(); i++)
  2239.                                         //          {
  2240.                                         //            BreakLogAlways(">>  Index: %0d, entID 0x%08X", i, s_this->m_brokenObjs[i].idEnt );
  2241.                                         //            if(s_this->m_brokenObjs[i].idEnt == rec.idEnt)
  2242.                                         //            {
  2243.                                         //              BreakLogAlways(">>>  Found existing ENTITY break at index %d <<<", i);
  2244.                                         //              iBrokenObjectIndex = i;
  2245.                                         //              break;
  2246.                                         //            }
  2247.                                         //          }
  2248.                                         //
  2249.                                         //          if(iBrokenObjectIndex == -1)
  2250.                                         //          {
  2251.                                         //            BreakLogAlways(">>>  FAILED TO FIND ENTITY OR BRUSH  <<<");
  2252.                                         //          }
  2253.                                         //        }
  2254.                                 }
  2255.                         }
  2256.  
  2257.                         if (iBrokenObjectIndex != -1)
  2258.                         {
  2259.                                 if (!pRecordedEvent || pRecordedEvent->iState == eBES_Generated)
  2260.                                 {
  2261.                                         //Only new events and recorded events from the network will enter this
  2262.                                         be.iBrokenObjectIndex = iBrokenObjectIndex;
  2263.                                         BreakLogAlways("Storing broken object index as: %d, original statobj 0x%p, pBrush 0x%p", iBrokenObjectIndex, rec.pStatObjOrg, rec.pBrush);
  2264.                                 }
  2265.  
  2266.                                 if (be.iState == eBES_Generated && !bIsStoredEvent)
  2267.                                 {
  2268.                                         // This is not in the recorded events, we still want to store it for Kill Cam
  2269.                                         CryLog("Should not happen!");
  2270.                                         be = s_this->StoreBreakEvent(be);
  2271.                                         bIsStoredEvent = true;
  2272.                                 }
  2273.                         }
  2274.                 } // if (!pDelayedTask)
  2275.  
  2276.                 int bIsExplosion = iszero(epc.idmat[0] + 1);  // idmat==-1 is an explosion
  2277.                 uint32 processFlags = 0;
  2278.                 if (pDelayedTask)
  2279.                 {
  2280.                         processFlags = pDelayedTask->m_islandIn.processFlags;
  2281.                 }
  2282.                 else
  2283.                 {
  2284.                         processFlags |= (pPhysEnt ? pPhysEnt->GetType() == PE_STATIC : ePlaneBreak_Static);
  2285.                         processFlags |= (ePlaneBreak_AutoSmash) * (g_glassAutoShatter | (bIsExplosion & g_glassAutoShatterOnExplosions));
  2286.                         if (s_this->m_bLoading && (flags & ePPB_EnableParticleEffects) == 0)
  2287.                                 processFlags |= (ePlaneBreak_NoFractureEffect);
  2288.                         if ((processFlags & ePlaneBreak_AutoSmash) == 0)
  2289.                         {
  2290.                                 s_this->m_throttling.m_brokenTreeCounter += g_breakageTreeIncGlass;
  2291.                                 s_this->m_throttling.m_numGlassEvents++;
  2292.                         }
  2293.                         if (g_glassMaxPanesToBreakPerFrame && s_this->m_throttling.m_numGlassEvents > g_glassMaxPanesToBreakPerFrame)
  2294.                         {
  2295.                                 // We are over budget, force autoshattering
  2296.                                 processFlags |= ePlaneBreak_AutoSmash;
  2297.                                 ThrottleLogAlways("THROTTLING: autosmashing glass, too many events");
  2298.                         }
  2299.                         if (flags & ePPB_PlaybackEvent)
  2300.                         {
  2301.                                 processFlags |= ePlaneBreak_PlaybackEvent;
  2302.                         }
  2303.                 }
  2304.  
  2305.                 IStatObj* pStatObjAux = NULL;
  2306.                 IStatObj* pStatObjNew = NULL;
  2307.                 CDelayedPlaneBreak dpb;
  2308.  
  2309.                 if (epc.iPrim[1] >= 0 &&
  2310.                     bIsStoredEvent &&
  2311.                     pDelayedTask == NULL &&
  2312.                     (!actuallyLoading || (flags & ePPB_PlaybackEvent) || (processFlags & ePlaneBreak_PlaybackEvent)))
  2313.                 {
  2314.                         pDelayedTask = &dpb;
  2315.                 }
  2316.  
  2317.                 /*      - ProcessImpact -
  2318.                  *
  2319.                  *  pStatObjAux==NULL, then an island was given to ProcessImpact, and pStatObjNew is the new broken glass
  2320.                  *
  2321.                  *  pStatObjAux!=NULL, then an island extraction took place
  2322.                  *    pStatObj stays the same
  2323.                  *    pStatObjNew = remainder
  2324.                  *              pStatObjAux = broken glass
  2325.                  *    if there is no host, one is created with one slot
  2326.                  *              pStatObjNew is placed into the original sub slot (or first)
  2327.                  *              pStatObjAux is appended to a new slot at the end
  2328.                  */
  2329.  
  2330.                 // Fill breakable impact struct
  2331.                 IBreakableManager* pBreakableManager = gEnv->pEntitySystem->GetBreakableManager();
  2332.                 SProcessImpactIn in;
  2333.                 {
  2334.                         in.pthit = epc.pt;
  2335.                         in.hitvel = epc.vloc[0];
  2336.                         in.hitnorm = epc.n;
  2337.                         in.hitmass = epc.mass[0];
  2338.                         in.hitradius = r;
  2339.                         in.itriHit = epc.iPrim[1];
  2340.                         in.pStatObj = pStatObj;
  2341.                         in.pStatObjAux = pStatObjAux;
  2342.                         in.mtx = mtx;
  2343.                         in.pMat = pMat;
  2344.                         in.pRenderMat = pRenderMat;
  2345.                         in.processFlags = processFlags;
  2346.                         in.eventSeed = be.seed;
  2347.                         in.bLoading = s_this->m_bLoading;
  2348.                         in.glassAutoShatterMinArea = CActionGame::g_glassAutoShatterMinArea;
  2349.                         in.addChunkFunc = &CActionGame::AddBroken2DChunkId;
  2350.                         in.bVerify = false;
  2351.                 }
  2352.  
  2353.                 SProcessImpactOut out;
  2354.                 EProcessImpactResult result = eProcessImpact_BadGeometry;
  2355.  
  2356.                 // Try to break with the new system if:
  2357.                 //      a) Not auto-smashing; no difference in systems in this case
  2358.                 //      b) First break; don't want to interfere with partially-broken mesh
  2359.                 if (g_glassSystemEnable
  2360.                     && !(processFlags &= ePlaneBreak_AutoSmash)
  2361.                     && !(pStatObj->GetFlags() & STATIC_OBJECT_GENERATED))
  2362.                 {
  2363.                         IBreakableGlassSystem* pGlassSys = CCryAction::GetCryAction()->GetIBreakableGlassSystem();
  2364.  
  2365.                         if (pGlassSys && pGlassSys->BreakGlassObject(epc, bEntityMustBreakGlass))
  2366.                         {
  2367.                                 result = eProcessImpact_Done;
  2368.                         }
  2369.                 }
  2370.  
  2371.                 // Clear pointers if successful, else fall back to old system
  2372.                 if (result == eProcessImpact_Done)
  2373.                 {
  2374.                         pStatObjNew = pStatObjAux = NULL;
  2375.                 }
  2376.                 else
  2377.                 {
  2378.                         if (pDelayedTask)
  2379.                         {
  2380.                                 in.bDelay = true;
  2381.                                 in.pIslandOut = (pDelayedTask->m_status == CDelayedPlaneBreak::eStatus_DONE) ? &pDelayedTask->m_islandOut : 0;
  2382.                         }
  2383.                         else
  2384.                         {
  2385.                                 in.bDelay = false;
  2386.                                 in.pIslandOut = 0;
  2387.                         }
  2388.  
  2389.                         result = pBreakableManager->ProcessPlaneImpact(in, out);
  2390.  
  2391.                         be.seed = out.eventSeed;
  2392.                         pStatObjNew = out.pStatObjNew;
  2393.                         pStatObjAux = out.pStatObjAux;
  2394.                 }
  2395.  
  2396.                 if (result == eProcessImpact_Delayed ||
  2397.                     result == eProcessImpact_DelayedMeshOnly)
  2398.                 {
  2399.                         assert(pDelayedTask != 0);
  2400.                         pDelayedTask->m_islandIn = out.islandIn;
  2401.                         pDelayedTask->m_bMeshPrepOnly = (result == eProcessImpact_DelayedMeshOnly);
  2402.                         pDelayedTask->m_status = CDelayedPlaneBreak::eStatus_STARTED;
  2403.  
  2404.                         for (int i = s_this->m_pendingPlaneBreaks.size() - 1; i >= 0; i--)
  2405.                         {
  2406.                                 if (s_this->m_pendingPlaneBreaks[i].m_status != CDelayedPlaneBreak::eStatus_NONE)
  2407.                                 {
  2408.                                         if ((s_this->m_pendingPlaneBreaks[i].m_islandIn.pStatObj == dpb.m_islandIn.pStatObj) &&
  2409.                                             (s_this->m_pendingPlaneBreaks[i].m_islandIn.itriSeed == dpb.m_islandIn.itriSeed))
  2410.                                         {
  2411.                                                 // Already doing a delayed break on the same pane of glass, ignore this request
  2412.                                                 return;
  2413.                                         }
  2414.                                 }
  2415.                                 else
  2416.                                 {
  2417.                                         CDelayedPlaneBreak& dpbTrg = s_this->m_pendingPlaneBreaks[i];
  2418.                                         dpbTrg = dpb;
  2419.                                         dpbTrg.m_iBreakEvent = (int)(&be - &s_this->m_breakEvents[0]);
  2420.                                         dpbTrg.m_epc = epc;
  2421.                                         dpbTrg.m_islandIn.pStatObj->AddRef();
  2422.                                         dpbTrg.m_idx = i;
  2423.                                         dpbTrg.m_count = s_this->m_pendingPlaneBreaks.size();
  2424.                                         gEnv->p3DEngine->GetDeferredPhysicsEventManager()->DispatchDeferredEvent(&dpbTrg);
  2425.                                         return;
  2426.                                 }
  2427.                         }
  2428.                         if (gEnv->bMultiplayer)
  2429.                         {
  2430.                                 // No more tasks, do it immediately
  2431.                                 in.bDelay = false;
  2432.                                 pBreakableManager->ProcessPlaneImpact(in, out);
  2433.  
  2434.                                 be.seed = out.eventSeed;
  2435.                                 pStatObjNew = out.pStatObjNew;
  2436.                                 pStatObjAux = out.pStatObjAux;
  2437.                         }
  2438.                         else
  2439.                         {
  2440.                                 return;
  2441.                         }
  2442.                 }
  2443.  
  2444.                 //CryLogAlways("CActionGame::PerformPlaneBreak() - ProcessImpact returned pStatObjNew: 0x%p\n  pStatObjAux: 0x%p", pStatObjNew, pStatObjAux);
  2445.  
  2446.                 be.bFirstBreak = iszero(pStatObj->GetFlags() & STATIC_OBJECT_GENERATED);  // keep note whether this is a primary or secondary break
  2447.  
  2448.                 EventPhysMono mono;
  2449.                 mono.pEntity = epc.pEntity[1];
  2450.                 mono.pForeignData = epc.pForeignData[1];
  2451.                 mono.iForeignData = epc.iForeignData[1];
  2452.                 if (gEnv->bServer || bIsClientBreak)
  2453.                         s_this->m_pGameContext->OnBrokeSomething(be, &mono, true);
  2454.  
  2455.                 // Was the break successful?
  2456.                 if (pStatObjAux == NULL && (pStatObj->GetFlags() & (STATIC_OBJECT_GENERATED | STATIC_OBJECT_CLONE)) == 0 && pStatObjNew == pStatObj)
  2457.                         return;
  2458.  
  2459.                 if (pStatObjAux || pStatObjNew && (!(pStatObjNew->GetFlags() & STATIC_OBJECT_GENERATED) ||
  2460.                                                    pStatObjNew->GetPhysGeom() && pStatObjNew->GetPhysGeom()->pMatMapping))
  2461.                         MARK_UNUSED pp.pMatMapping;
  2462.                 if (!pStatObjAux)
  2463.                 {
  2464.                         if (!pStatObjNew)
  2465.                         {
  2466.                                 s_this->RegisterBrokenMesh(epc.pEntity[1], 0, epc.partid[1], 0, 0, timeout, killFX);
  2467.                         }
  2468.                         else if (!(pStatObjNew->GetFlags() & STATIC_OBJECT_COMPOUND))
  2469.                         {
  2470.                                 phys_geometry* physGeom = pStatObjNew->GetPhysGeom();
  2471.                                 IGeometry* pGeom = physGeom ? physGeom->pGeom : NULL;
  2472.                                 s_this->RegisterBrokenMesh(epc.pEntity[1], pGeom, epc.partid[1], pStatObjNew, 0, timeout, killFX);
  2473.                         }
  2474.                 }
  2475.                 if (rec.itype == PHYS_FOREIGN_ID_STATIC && pStatObjAux && !pStatObjHost)
  2476.                 {
  2477.                         pStatObjHost = gEnv->p3DEngine->CreateStatObj();
  2478.                         pStatObjHost->SetSubObjectCount(1);
  2479.                         pStatObjHost->SetFlags(pStatObjHost->GetFlags() | STATIC_OBJECT_CLONE | STATIC_OBJECT_COMPOUND);
  2480.                         if (pStatObj)
  2481.                                 pStatObjHost->SetFilePath(pStatObj->GetFilePath());
  2482.                         pStatObjHost->FreeIndexedMesh();
  2483.                         pStatObjHost->SetMaterial(pStatObj->GetMaterial());
  2484.                         goto ForceObjUpdate;
  2485.                 }
  2486.                 if (pStatObjNew != pStatObj)
  2487.                 {
  2488.                         if (rec.itype == PHYS_FOREIGN_ID_ENTITY)
  2489.                         {
  2490.                                 assert(pEntityTrg);
  2491.                                 pp.partid = pEntityTrg->SetStatObj(pStatObjNew, epc.partid[1], true);
  2492.                                 if (pEntityTrg->GetPhysics())
  2493.                                         pEntityTrg->GetPhysics()->SetParams(&pp);
  2494.                         }
  2495.                         else if (rec.itype == PHYS_FOREIGN_ID_STATIC)
  2496.                         {
  2497. ForceObjUpdate:
  2498.                                 if (pStatObjHost)
  2499.                                 {
  2500.                                         if (!(pStatObjHost->GetFlags() & STATIC_OBJECT_CLONE))
  2501.                                                 pStatObjHost = pStatObjHost->Clone(false, false, false);
  2502.                                         pp.pPhysGeom = pStatObjNew ? pStatObjNew->GetPhysGeom() : 0;
  2503.                                         if (pSubObj = pStatObjHost->GetSubObject(epc.partid[1]))
  2504.                                         {
  2505.                                                 if (pSubObj->pStatObj)
  2506.                                                         pSubObj->pStatObj->Release();
  2507.                                                 if (pSubObj->pStatObj = pStatObjNew)
  2508.                                                         pSubObj->pStatObj->AddRef();
  2509.                                                 pStatObjHost->Invalidate(false);
  2510.                                         }
  2511.                                         pStatObjNew = pStatObjHost;
  2512.                                 }
  2513.                                 pBrush->SetEntityStatObj(0, pStatObjNew);
  2514.                                 if (!pStatObjHost)
  2515.                                         pBrush->Physicalize(true);
  2516.                                 pp.partid = epc.partid[1];
  2517.                                 if (pBrush->GetPhysics())
  2518.                                         if (pp.pPhysGeom)
  2519.                                                 pBrush->GetPhysics()->SetParams(&pp);
  2520.                                         else
  2521.                                                 pBrush->GetPhysics()->RemoveGeometry(pp.partid);
  2522.                         }
  2523.  
  2524.                         if (pEntityTrg && pStatObjNew)
  2525.                         {
  2526.                                 if (IGameObject* pGameObject = gEnv->pGameFramework->GetGameObject(pEntityTrg->GetId()))
  2527.                                 {
  2528.                                         SGameObjectEvent evt(eGFE_OnBreakable2d, eGOEF_ToExtensions);
  2529.                                         evt.ptr = (void*)&epc;
  2530.                                         evt.param = pStatObjNew;
  2531.                                         pGameObject->SendEvent(evt);
  2532.                                 }
  2533.                         }
  2534.                 }
  2535.                 if (pStatObjAux)
  2536.                 {
  2537.                         if (rec.itype == PHYS_FOREIGN_ID_ENTITY)
  2538.                         {
  2539.                                 assert(pEntityTrg);
  2540.                                 pEntityTrg->SetStatObj(pStatObjAux, -1, true);
  2541.                                 SProcBrokenObjRec rec2;
  2542.                                 rec2.itype = PHYS_FOREIGN_ID_ENTITY;
  2543.                                 rec2.islot = -1;
  2544.                                 rec2.idEnt = pEntityTrg->GetId();
  2545.                                 rec2.pStatObjOrg = 0;
  2546.                                 s_this->m_brokenObjs.push_back(rec2);
  2547.                                 const_cast<EventPhysCollision&>(epc).partid[1] =
  2548.                                   ((pStatObj = pEntityTrg->GetStatObj(ENTITY_SLOT_ACTUAL)) && (pStatObj->GetFlags() & STATIC_OBJECT_COMPOUND) ?
  2549.                                    pStatObj->GetSubObjectCount() : pEntityTrg->GetSlotCount()) - 1;
  2550.                         }
  2551.                         else if (rec.itype == PHYS_FOREIGN_ID_STATIC)
  2552.                         {
  2553.                                 PREFAST_ASSUME(pStatObjHost);
  2554.                                 pp.partid = pStatObjHost->GetSubObjectCount();