BVB Source Codes

CRYENGINE Show TimeDemoRecorder.cpp Source code

Return Download CRYENGINE: download TimeDemoRecorder.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. // -------------------------------------------------------------------------
  4. //  File name:   timedemorecorder.cpp
  5. //  Version:     v1.00
  6. //  Created:     2/8/2003 by Timur.
  7. //  Compilers:   Visual Studio.NET
  8. //  Description:
  9. // -------------------------------------------------------------------------
  10. //  History:
  11. //  Pascal Kross, 18.05.2015, Added HMD support with TIMEDEMO_FILE_VERSION_7
  12. //
  13. ////////////////////////////////////////////////////////////////////////////
  14.  
  15. #include "StdAfx.h"
  16. #include "TimeDemoRecorder.h"
  17. #include <CrySystem/File/CryFile.h>
  18. #include <IActorSystem.h>
  19. #include <CryAISystem/IAgent.h>
  20. #include <ILevelSystem.h>
  21. #include <CrySystem/ITestSystem.h>
  22. #include <CryMovie/IMovieSystem.h>
  23. #include "IMovementController.h"
  24. #include <CrySystem/Profilers/IStatoscope.h>
  25. #include <Cry3DEngine/ITimeOfDay.h>
  26. #include <ITimeDemoRecorder.h>
  27. #include <CrySystem/VR/IHMDManager.h>
  28. #include <CrySystem/VR/IHMDDevice.h>
  29. #include <CryCore/Platform/CryWindows.h>
  30.  
  31. //////////////////////////////////////////////////////////////////////////
  32. // Brush Export structures.
  33. //////////////////////////////////////////////////////////////////////////
  34. #define TIMEDEMO_FILE_SIGNATURE         "CRY "
  35. #define TIMEDEMO_FILE_TYPE              150
  36. #define TIMEDEMO_FILE_VERSION_1         1
  37. #define TIMEDEMO_FILE_VERSION_2         2
  38. #define TIMEDEMO_FILE_VERSION_3         4 // ?
  39. #define TIMEDEMO_FILE_VERSION_4         6
  40. #define TIMEDEMO_FILE_VERSION_7         7
  41. #define TIMEDEMO_FILE_VERSION           TIMEDEMO_FILE_VERSION_7
  42.  
  43. #define TIMEDEMO_MAX_INPUT_EVENTS       16
  44. #define TIMEDEMO_MAX_GAME_EVENTS        1 // For now...
  45. #define TIMEDEMO_MAX_DESCRIPTION_LENGTH 64
  46.  
  47. #define FIXED_TIME_STEP                 (30) // Assume running at 30fps.
  48.  
  49. enum ETimeDemoFileFlags
  50. {
  51.         eTimeDemoCompressed = 0x0001,
  52. };
  53.  
  54. #pragma pack(push,1)
  55. struct STimeDemoHeader
  56. {
  57.         char signature[4];  // File signature.
  58.         int  filetype;      // File type.
  59.         int  version;       // File version.
  60.         int  nDataOffset;   // Offset where frame data starts.
  61.  
  62.         //////////////////////////////////////////////////////////////////////////
  63.         int    numFrames;   // Number of frames.
  64.         int    nFrameSize;  // Size of the per frame data in bytes.
  65.         float  totalTime;
  66.         char   levelname[128];
  67.         // @see ETimeDemoFileFlags
  68.         uint32 nDemoFlags;
  69.         uint32 nCompressedDataSize;
  70.         uint32 nUncompressedDataSze;
  71.         char   reserved[116];
  72.  
  73.         //////////////////////////////////////////////////////////////////////////
  74.         void SwapEndianThis()
  75.         {
  76.                 SwapEndian(filetype);
  77.                 SwapEndian(version);
  78.                 SwapEndian(nDataOffset);
  79.                 SwapEndian(numFrames);
  80.                 SwapEndian(nFrameSize);
  81.                 SwapEndian(totalTime);
  82.                 SwapEndian(nDemoFlags);
  83.                 SwapEndian(nCompressedDataSize);
  84.                 SwapEndian(nUncompressedDataSze);
  85.         }
  86. };
  87.  
  88. //////////////////////////////////////////////////////////////////////////
  89. struct STimeDemoHeader_4 : public STimeDemoHeader
  90. {
  91.         uint16 fixedTimeStep;
  92.  
  93.         void SwapEndianThis()
  94.         {
  95.                 STimeDemoHeader::SwapEndianThis();
  96.                 SwapEndian(fixedTimeStep);
  97.         }
  98. };
  99.  
  100. //////////////////////////////////////////////////////////////////////////
  101. struct STimeDemoFrame_1
  102. {
  103.         Vec3         curPlayerPosition;
  104.         Ang3         angles;
  105.         float        frametime;
  106.  
  107.         unsigned int nActionFlags[2];
  108.         float        fLeaning;
  109.         int          nPolygonsPerFrame;
  110.         char         reserved[28];
  111. };
  112.  
  113. //////////////////////////////////////////////////////////////////////////
  114. struct STimeDemoFrameEvent_2
  115. {
  116. #ifndef NEED_ENDIAN_SWAP
  117.         struct
  118.         {
  119.                 uint16 deviceType : 4;
  120.                 uint16 state      : 4;
  121.                 uint16 modifiers  : 4;
  122.                 uint16 reserved   : 4;
  123.         };
  124. #else
  125.         struct
  126.         {
  127.                 uint16 state      : 4;
  128.                 uint16 deviceType : 4;
  129.                 uint16 reserved   : 4;
  130.                 uint16 modifiers  : 4;
  131.         };
  132. #endif
  133.         uint16 keyId;
  134.         float  value;
  135.  
  136.         void   SwapEndianThis()
  137.         {
  138.                 SwapEndian(keyId); // this points to the first uint32 in structure
  139.                 SwapEndian(value);
  140.         }
  141. };
  142. struct STimeDemoFrame_2
  143. {
  144.         Vec3                  curPlayerPosition;
  145.         Ang3                  curCameraAngles;
  146.         Quat                  curViewRotation;
  147.         float                 frametime;
  148.  
  149.         unsigned int          nActionFlags[2];
  150.         float                 fLeaning;
  151.         int                   nPolygonsPerFrame;
  152.         uint8                 numInputEvents;
  153.  
  154.         STimeDemoFrameEvent_2 inputEvents[TIMEDEMO_MAX_INPUT_EVENTS];
  155.         char                  reserved[32];
  156.  
  157.         //////////////////////////////////////////////////////////////////////////
  158.         void SwapEndianThis()
  159.         {
  160.                 SwapEndian(curPlayerPosition);
  161.                 SwapEndian(curCameraAngles);
  162.                 SwapEndian(curViewRotation);
  163.                 SwapEndian(frametime);
  164.                 SwapEndian(nActionFlags[0]);
  165.                 SwapEndian(nActionFlags[1]);
  166.                 SwapEndian(fLeaning);
  167.                 SwapEndian(nPolygonsPerFrame);
  168.                 SwapEndian(numInputEvents);
  169.                 for (int i = 0; i < TIMEDEMO_MAX_INPUT_EVENTS; i++)
  170.                         inputEvents[i].SwapEndianThis();
  171.         }
  172. };
  173.  
  174. struct SRecordedGameEvent
  175. {
  176.         uint32 gameEventType;
  177.         char   entityName[TIMEDEMO_MAX_DESCRIPTION_LENGTH];
  178.         char   description[TIMEDEMO_MAX_DESCRIPTION_LENGTH];
  179.         char   description2[TIMEDEMO_MAX_DESCRIPTION_LENGTH];
  180.         float  value;
  181.         int32  extra;
  182.  
  183.         void operator=(const STimeDemoGameEvent& event)
  184.         {
  185.                 gameEventType = event.gameEventType;
  186.                 value = event.value;
  187.                 extra = event.extra;
  188.  
  189.                 cry_strcpy(entityName, event.entityName.c_str());
  190.                 cry_strcpy(description, event.description.c_str());
  191.                 cry_strcpy(description2, event.description2.c_str());
  192.         }
  193.  
  194.         void SwapEndianThis()
  195.         {
  196.                 SwapEndian(extra);
  197.                 SwapEndian(value);
  198.         }
  199. };
  200.  
  201. STimeDemoGameEvent::STimeDemoGameEvent(const SRecordedGameEvent& event)
  202.         : entityName(event.entityName)
  203.         , gameEventType(event.gameEventType)
  204.         , description(event.description)
  205.         , description2(event.description2)
  206.         , value(event.value)
  207.         , extra(event.extra)
  208. {}
  209.  
  210. struct STimeDemoFrame_3
  211. {
  212.         int                   nFrameDataSize; // Size of this frame in bytes.
  213.  
  214.         Vec3                  curPlayerPosition;
  215.         Ang3                  curCameraAngles;
  216.         Quat                  curViewRotation;
  217.         float                 frametime;
  218.  
  219.         unsigned int          nActionFlags[2];
  220.         float                 fLeaning;
  221.         int                   nPolygonsPerFrame;
  222.         int                   numInputEvents;
  223.         STimeDemoFrameEvent_2 inputEvents[TIMEDEMO_MAX_INPUT_EVENTS];
  224.  
  225.         char                  reserved[32];
  226.  
  227.         //char data[]; // Special frame data.
  228.         //////////////////////////////////////////////////////////////////////////
  229.         void SwapEndianThis()
  230.         {
  231.                 SwapEndian(curPlayerPosition);
  232.                 SwapEndian(curCameraAngles);
  233.                 SwapEndian(curViewRotation);
  234.                 SwapEndian(frametime);
  235.                 SwapEndian(nActionFlags[0]);
  236.                 SwapEndian(nActionFlags[1]);
  237.                 SwapEndian(fLeaning);
  238.                 SwapEndian(nPolygonsPerFrame);
  239.                 SwapEndian(numInputEvents);
  240.                 for (int i = 0; i < TIMEDEMO_MAX_INPUT_EVENTS; i++)
  241.                         inputEvents[i].SwapEndianThis();
  242.         }
  243. };
  244.  
  245. struct STimeDemoFrame_4
  246. {
  247.         int                   nFrameDataSize; // Size of this frame in bytes.
  248.  
  249.         Vec3                  curPlayerPosition;
  250.         Ang3                  curCameraAngles;
  251.         Quat                  curViewRotation;
  252.         float                 frametime;
  253.  
  254.         unsigned int          nActionFlags[2];
  255.         float                 fLeaning;
  256.         int                   nPolygonsPerFrame;
  257.         int                   numInputEvents;
  258.         STimeDemoFrameEvent_2 inputEvents[TIMEDEMO_MAX_INPUT_EVENTS];
  259.         int                   numGameEvents;
  260.         SRecordedGameEvent    gameEvents[TIMEDEMO_MAX_GAME_EVENTS];
  261.  
  262.         uint32                bFollow; // if true, data from the next timedemo frame will be collected in this frame
  263.  
  264.         char                  reserved[32];
  265.  
  266.         //char data[]; // Special frame data.
  267.         //////////////////////////////////////////////////////////////////////////
  268.         void SwapEndianThis()
  269.         {
  270.                 SwapEndian(curPlayerPosition);
  271.                 SwapEndian(curCameraAngles);
  272.                 SwapEndian(curViewRotation);
  273.                 SwapEndian(frametime);
  274.                 SwapEndian(nActionFlags[0]);
  275.                 SwapEndian(nActionFlags[1]);
  276.                 SwapEndian(fLeaning);
  277.                 SwapEndian(nPolygonsPerFrame);
  278.                 SwapEndian(numInputEvents);
  279.                 SwapEndian(numGameEvents);
  280.                 for (int i = 0; i < TIMEDEMO_MAX_INPUT_EVENTS; i++)
  281.                         inputEvents[i].SwapEndianThis();
  282.                 for (int i = 0; i < TIMEDEMO_MAX_GAME_EVENTS; i++)
  283.                         gameEvents[i].SwapEndianThis();
  284.         }
  285. };
  286.  
  287. struct STimeDemoFrame_7
  288. {
  289.         int                   nFrameDataSize;
  290.  
  291.         Vec3                  curPlayerPosition;
  292.         Quat                  curPlayerRotation;
  293.         Quat                  curViewRotation;
  294.         Vec3                  curHmdPositionOffset;
  295.         Quat                  curHmdViewRotation;
  296.         float                 frametime;
  297.  
  298.         unsigned int          nActionFlags[2];
  299.         float                 fLeaning;
  300.         int                   nPolygonsPerFrame;
  301.         int                   numInputEvents;
  302.         STimeDemoFrameEvent_2 inputEvents[TIMEDEMO_MAX_INPUT_EVENTS];
  303.         int                   numGameEvents;
  304.         SRecordedGameEvent    gameEvents[TIMEDEMO_MAX_GAME_EVENTS];
  305.  
  306.         uint32                bFollow;
  307.  
  308.         char                  reserved[32];
  309.  
  310.         //////////////////////////////////////////////////////////////////////////
  311.         void SwapEndianThis()
  312.         {
  313.                 SwapEndian(curPlayerPosition);
  314.                 SwapEndian(curPlayerRotation);
  315.                 SwapEndian(curViewRotation);
  316.                 SwapEndian(curHmdPositionOffset);
  317.                 SwapEndian(curHmdViewRotation);
  318.                 SwapEndian(frametime);
  319.                 SwapEndian(nActionFlags[0]);
  320.                 SwapEndian(nActionFlags[1]);
  321.                 SwapEndian(fLeaning);
  322.                 SwapEndian(nPolygonsPerFrame);
  323.                 SwapEndian(numInputEvents);
  324.                 SwapEndian(numGameEvents);
  325.                 for (int i = 0; i < TIMEDEMO_MAX_INPUT_EVENTS; ++i)
  326.                 {
  327.                         inputEvents[i].SwapEndianThis();
  328.                 }
  329.                 for (int i = 0; i < TIMEDEMO_MAX_GAME_EVENTS; ++i)
  330.                 {
  331.                         gameEvents[i].SwapEndianThis();
  332.                 }
  333.         }
  334. };
  335.  
  336. #pragma pack(pop)
  337.  
  338. //////////////////////////////////////////////////////////////////////////
  339.  
  340. CTimeDemoRecorder* CTimeDemoRecorder::s_pTimeDemoRecorder = 0;
  341. ICVar* CTimeDemoRecorder::s_timedemo_file = 0;
  342.  
  343. //////////////////////////////////////////////////////////////////////////
  344. void CTimeDemoRecorder::cmd_StartRecordingTimeDemo(IConsoleCmdArgs* pArgs)
  345. {
  346.         if (s_pTimeDemoRecorder)
  347.         {
  348.                 if (s_pTimeDemoRecorder->IsRecording())
  349.                         return;
  350.  
  351.                 if (pArgs->GetArgCount() > 1)
  352.                 {
  353.                         s_timedemo_file->Set(pArgs->GetArg(1));
  354.                 }
  355.                 s_pTimeDemoRecorder->Record(true);
  356.         }
  357. }
  358.  
  359. //////////////////////////////////////////////////////////////////////////
  360. void CTimeDemoRecorder::cmd_Play(IConsoleCmdArgs* pArgs)
  361. {
  362.         if (s_pTimeDemoRecorder)
  363.         {
  364.                 if (pArgs->GetArgCount() > 1)
  365.                 {
  366.                         s_timedemo_file->Set(pArgs->GetArg(1));
  367.                 }
  368.                 s_pTimeDemoRecorder->StartDemoDelayed(2);
  369.         }
  370. }
  371.  
  372. //////////////////////////////////////////////////////////////////////////
  373. void CTimeDemoRecorder::cmd_Stop(IConsoleCmdArgs* pArgs)
  374. {
  375.         if (s_pTimeDemoRecorder)
  376.                 s_pTimeDemoRecorder->Record(false);
  377.         if (s_pTimeDemoRecorder)
  378.                 s_pTimeDemoRecorder->Play(false);
  379. }
  380.  
  381. //////////////////////////////////////////////////////////////////////////
  382. void CTimeDemoRecorder::cmd_StartDemoChain(IConsoleCmdArgs* pArgs)
  383. {
  384.         if (pArgs->GetArgCount() > 1)
  385.         {
  386.                 const char* sLevelsFile = pArgs->GetArg(1);
  387.                 s_pTimeDemoRecorder->StartChainDemo(sLevelsFile, false);
  388.         }
  389.         else
  390.         {
  391.                 s_pTimeDemoRecorder->StartChainDemo("test_chainlevels.txt", true);
  392.         }
  393. }
  394.  
  395. //////////////////////////////////////////////////////////////////////////
  396. void CTimeDemoRecorder::cmd_StartDemoLevel(IConsoleCmdArgs* pArgs)
  397. {
  398.         const int argCount = pArgs->GetArgCount();
  399.         if (argCount > 1)
  400.         {
  401.                 const int levelCount = argCount - 1;
  402.  
  403.                 std::vector<const char*> levels(levelCount);
  404.  
  405.                 for (int i = 0; i < levelCount; ++i)
  406.                         levels[i] = pArgs->GetArg(i + 1);
  407.  
  408.                 s_pTimeDemoRecorder->StartDemoLevel(&(levels.front()), levelCount);
  409.         }
  410.         else
  411.         {
  412.                 CryLogAlways("Expect level name(s)");
  413.         }
  414. }
  415.  
  416. static void OnChange_demo_num_orientations(ICVar* pCVar)
  417. {
  418.         if (pCVar->GetIVal() < 1)
  419.                 pCVar->Set(1);
  420. }
  421.  
  422. //////////////////////////////////////////////////////////////////////////
  423. //////////////////////////////////////////////////////////////////////////
  424. CTimeDemoRecorder::CTimeDemoRecorder()
  425.         : m_listeners(1)
  426.         , m_bRecording(false)
  427.         , m_bPlaying(false)
  428.         , m_bPaused(false)
  429.         , m_bDemoFinished(false)
  430.         , m_demoEnded(false)
  431.         , m_bChainloadingDemo(false)
  432.         , m_currentFrame(0)
  433.         , m_nTotalPolysRecorded(0)
  434.         , m_nTotalPolysPlayed(0)
  435.         , m_lastPlayedTotalTime(0)
  436.         , m_lastAveFrameRate(0)
  437.         , m_sumFPS(0)
  438.         , m_minFPS(0)
  439.         , m_maxFPS(0)
  440.         , m_currFPS(0)
  441.         , m_minFPSCounter(0)
  442.         , m_minFPS_Frame(0)
  443.         , m_maxFPS_Frame(0)
  444.         , m_nCurrPolys(0)
  445.         , m_nMaxPolys(0)
  446.         , m_nMinPolys(0)
  447.         , m_nPolysPerSec(0)
  448.         , m_nPolysCounter(0)
  449.         , m_fpsCounter(0)
  450.         , m_fileVersion(TIMEDEMO_FILE_VERSION)
  451.         , m_bEnabledProfiling(false)
  452.         , m_bVisibleProfiling(false)
  453.         , m_oldPeakTolerance(0.0f)
  454.         , m_fixedTimeStep(0)
  455.         , m_pTimeDemoInfo(nullptr)
  456.         , m_numLoops(0)
  457.         , m_bAIEnabled(false)
  458.         , m_countDownPlay(0)
  459.         , m_prevGodMode(0)
  460.         , m_nCurrentDemoLevel(0)
  461.         , m_lastChainDemoTime(0.0f)
  462. {
  463.         s_pTimeDemoRecorder = this;
  464.  
  465.         //gEnv->pGameFramework->GetIGameplayRecorder()->EnableGameStateRecorder(false, this, false);
  466.  
  467.         CRY_ASSERT(GetISystem());
  468.  
  469.         // Register demo variables.
  470.         s_timedemo_file = REGISTER_STRING("demo_file", "timedemo", 0, "Time Demo Filename");
  471.         REGISTER_CVAR2("demo_game_state", &m_demo_gameState, 0, 0, "enable/disable the game state recording");
  472.         REGISTER_CVAR2("demo_profile", &m_demo_profile, 1, 0, "Enable demo profiling");
  473.         REGISTER_CVAR2("demo_noinfo", &m_demo_noinfo, 0, 0, "Disable info display during demo playback");
  474.  
  475.         REGISTER_COMMAND("record", &CTimeDemoRecorder::cmd_StartRecordingTimeDemo, 0,
  476.                          "Starts recording of a time demo.\n"
  477.                          "Usage: record demoname\n"
  478.                          "File 'demoname.tmd' will be created.");
  479.  
  480.         REGISTER_COMMAND("stoprecording", &CTimeDemoRecorder::cmd_Stop, 0,
  481.                          "Stops recording of a time demo.\n"
  482.                          "Usage: stoprecording\n"
  483.                          "File 'demoname.?' will be saved.");
  484.  
  485.         REGISTER_COMMAND("demo", &CTimeDemoRecorder::cmd_Play, 0,
  486.                          "Plays a time demo from file.\n"
  487.                          "Usage: demo demoname\n");
  488.  
  489.         REGISTER_COMMAND("stopdemo", &CTimeDemoRecorder::cmd_Stop, 0,
  490.                          "Stop playing a time demo.\n");
  491.  
  492.         REGISTER_COMMAND("demo_StartDemoChain", &CTimeDemoRecorder::cmd_StartDemoChain, 0, "Load's a file at 1st argument with the list of levels and play time demo on each\n");
  493.         REGISTER_COMMAND("demo_StartDemoLevel", &CTimeDemoRecorder::cmd_StartDemoLevel, 0, "Prepares and starts time demos for the specified set of level names\n");
  494.  
  495.         REGISTER_CVAR2("demo_num_runs", &m_maxLoops, 1, 0, "Number of times to loop timedemo");
  496.         REGISTER_CVAR2("demo_scroll_pause", &m_demo_scroll_pause, 1, 0, "ScrollLock pauses demo play/record");
  497.         REGISTER_CVAR2("demo_quit", &m_demo_quit, 0, 0, "Quit game after demo runs finished");
  498.         REGISTER_CVAR2("demo_finish_memreplay_sizer", &m_finish_replaysizer, 0, 0, "Add a crysizer tree to memreplay when demo is finished");
  499.         REGISTER_CVAR2("demo_finish_memreplay_stop", &m_finish_replaystop, 0, 0, "Stop memreplay when demo is finished");
  500.         REGISTER_CVAR2("demo_screenshot_frame", &m_demo_screenshot_frame, 0, 0, "Make screenshot on specified frame during demo playback, If Negative then do screen shoot every N frame");
  501.         REGISTER_CVAR2("demo_max_frames", &m_demo_max_frames, 100000, 0, "Max number of frames to save");
  502.         REGISTER_CVAR2("demo_savestats", &m_demo_savestats, 0, 0, "Save level stats at the end of the loop");
  503.         REGISTER_CVAR2("demo_ai", &m_demo_ai, 1, 0, "Enable/Disable AI during the demo");
  504.  
  505.         // Note: Do not restart the level for Hunt, because the timedemo logic uses the regular map command and not mission which is doing other stuff.
  506.         REGISTER_CVAR2("demo_restart_level", &m_demo_restart_level, 0, 0, "Restart level after each loop: 0 = Off; 1 = use quicksave on first playback; 2 = load level start");
  507.  
  508.         REGISTER_CVAR2("demo_panoramic", &m_demo_panoramic, 0, 0, "Panoramic view when playing back demo");
  509.         REGISTER_CVAR2("demo_fixed_timestep", &m_demo_fixed_timestep, FIXED_TIME_STEP, 0, "number of updates per second");
  510.         REGISTER_CVAR2("demo_vtune", &m_demo_vtune, 0, 0, "Enables VTune profiling when running time demo");
  511.         REGISTER_CVAR2("demo_time_of_day", &m_demo_time_of_day, -1, 0, "Sets the time of day to override in game settings if not negative");
  512.         REGISTER_CVAR2("demo_save_every_frame", &m_demo_save_every_frame, 0, 0, "Save timedemo every frame during recording, in case game crashes timedemo will be reliable");
  513.         REGISTER_CVAR2("demo_use_hmd_rotation", &m_demo_use_hmd_rotation, 0, 0, "Uses alternative entity and view rotation for HMD Devices");
  514.  
  515.         REGISTER_STRING("demo_finish_cmd", "", 0, "Console command to run when demo is finished");
  516.  
  517.         REGISTER_CVAR2_CB("demo_num_orientations", &m_numOrientations, 1, 0, "Number of horizontal orientations to play the demo using\n"
  518.                                                                              "e.g. 3 will play: looking ahead, 120deg left, 120deg right\n"
  519.                                                                              "default/min: 1",
  520.                           OnChange_demo_num_orientations);
  521. }
  522.  
  523. //////////////////////////////////////////////////////////////////////////
  524. CTimeDemoRecorder::~CTimeDemoRecorder()
  525. {
  526.         s_pTimeDemoRecorder = 0;
  527. }
  528.  
  529. //////////////////////////////////////////////////////////////////////////
  530. void CTimeDemoRecorder::Reset()
  531. {
  532.         m_bRecording = false;
  533.         m_bPlaying = false;
  534.         m_bDemoFinished = false;
  535.         m_bPaused = false;
  536.         m_bChainloadingDemo = false;
  537.         m_demoEnded = false;
  538. }
  539.  
  540. //////////////////////////////////////////////////////////////////////////
  541. const char* CTimeDemoRecorder::GetCurrentLevelPath()
  542. {
  543.         static char buf[_MAX_PATH];
  544.         gEnv->pGameFramework->GetAbsLevelPath(buf, sizeof(buf));
  545.         return &buf[0];
  546.         /*
  547.            ILevel *pLevel = gEnv->pGameFramework->GetILevelSystem()->GetCurrentLevel();
  548.            if (!pLevel)
  549.             return "";
  550.            ILevelInfo *pLevelInfo = pLevel->GetLevelInfo();
  551.            if (!pLevelInfo)
  552.             return "";
  553.            return pLevelInfo->GetPath();
  554.          */
  555. }
  556.  
  557. //////////////////////////////////////////////////////////////////////////
  558. void CTimeDemoRecorder::Record(bool bEnable)
  559. {
  560.         if (bEnable == m_bRecording)
  561.                 return;
  562.  
  563.         if (bEnable == m_bRecording)
  564.                 return;
  565.  
  566.         if (gEnv->pMovieSystem)
  567.                 gEnv->pMovieSystem->StopAllSequences();
  568.  
  569.         m_bRecording = bEnable;
  570.         m_bPlaying = false;
  571.         if (m_bRecording)
  572.         {
  573.                 SaveAllEntitiesState();
  574.  
  575.                 uint64 onEventSubscriptions = 0;
  576.                 onEventSubscriptions |= ENTITY_EVENT_BIT(ENTITY_EVENT_XFORM);
  577.                 onEventSubscriptions |= ENTITY_EVENT_BIT(ENTITY_EVENT_HIDE);
  578.                 onEventSubscriptions |= ENTITY_EVENT_BIT(ENTITY_EVENT_UNHIDE);
  579.                 onEventSubscriptions |= ENTITY_EVENT_BIT(ENTITY_EVENT_ATTACH);
  580.                 onEventSubscriptions |= ENTITY_EVENT_BIT(ENTITY_EVENT_DETACH);
  581.                 onEventSubscriptions |= ENTITY_EVENT_BIT(ENTITY_EVENT_DETACH_THIS);
  582.                 onEventSubscriptions |= ENTITY_EVENT_BIT(ENTITY_EVENT_ENABLE_PHYSICS);
  583.                 onEventSubscriptions |= ENTITY_EVENT_BIT(ENTITY_EVENT_ENTER_SCRIPT_STATE);
  584.  
  585.                 gEnv->pEntitySystem->AddSink(this, IEntitySystem::OnEvent, onEventSubscriptions);
  586.  
  587.                 // Start recording.
  588.                 m_records.clear();
  589.                 m_records.reserve(1000);
  590.  
  591.                 m_currentFrameInputEvents.clear();
  592.                 m_currentFrameEntityEvents.clear();
  593.                 // Start listening input events.
  594.                 if (gEnv->pInput)
  595.                         gEnv->pInput->AddEventListener(this);
  596.  
  597.                 StartSession();
  598.  
  599.                 m_recordStartTime = GetTime();
  600.                 m_lastFrameTime = m_recordStartTime;
  601.         }
  602.         else
  603.         {
  604.                 // Stop recording.
  605.                 m_recordedDemoTime = m_totalDemoTime;
  606.                 m_lastFrameTime = GetTime();
  607.  
  608.                 gEnv->pEntitySystem->RemoveSink(this);
  609.  
  610.                 m_currentFrameInputEvents.clear();
  611.                 m_currentFrameEntityEvents.clear();
  612.                 // Stop listening tho the input events.
  613.                 if (gEnv->pInput)
  614.                         gEnv->pInput->RemoveEventListener(this);
  615.  
  616.                 StopSession();
  617.  
  618.                 // Save after stopping.
  619.                 string filename = PathUtil::Make(GetCurrentLevelPath(), s_timedemo_file->GetString(), "tmd");
  620.                 s_pTimeDemoRecorder->Save(filename.c_str());
  621.         }
  622.         m_currentFrame = 0;
  623.         m_totalDemoTime.SetMilliSeconds(0);
  624.  
  625.         SignalRecording(bEnable);
  626. }
  627.  
  628. //////////////////////////////////////////////////////////////////////////
  629. void CTimeDemoRecorder::Play(bool bEnable)
  630. {
  631.         if (bEnable == m_bPlaying)
  632.                 return;
  633.  
  634.         if (bEnable)
  635.         {
  636.                 CRY_ASSERT(*GetCurrentLevelPath() != 0);
  637.  
  638.                 // Try to load demo file.
  639.                 string filename = PathUtil::Make(GetCurrentLevelPath(), s_timedemo_file->GetString(), "tmd");
  640.  
  641.                 // Put it back later!
  642.                 Load(filename);
  643.  
  644.                 if (m_records.empty())
  645.                 {
  646.                         m_bDemoFinished = true;
  647.                         return;
  648.                 }
  649.  
  650.                 if (gEnv->pStatoscope)
  651.                         gEnv->pStatoscope->AddUserMarker("TimeDemo", "Start playing");
  652.         }
  653.         else
  654.         {
  655.                 if (m_bPlaying)
  656.                 {
  657.                         // Turning off playback.
  658.                         if (m_demo_savestats != 0)
  659.                         {
  660.                                 if (m_nCurrentDemoLevel >= m_demoLevels.size())
  661.                                 {
  662.                                         // Save stats after last run only.
  663.                                         gEnv->pConsole->ExecuteString("SaveLevelStats");
  664.                                 }
  665.                         }
  666.  
  667.                         if (gEnv->pStatoscope)
  668.                                 gEnv->pStatoscope->AddUserMarker("TimeDemo", "Stop playing");
  669.                 }
  670.         }
  671.  
  672.         m_bPlaying = bEnable;
  673.  
  674.         IActor* pClActor = gEnv->pGameFramework->GetClientActor();
  675.         if (pClActor)
  676.         {
  677.                 IAnimatedCharacter* pAnimChar = pClActor->GetAnimatedCharacter();
  678.                 if (pAnimChar)
  679.                         pAnimChar->SetNoMovementOverride(m_bPlaying);
  680.         }
  681.  
  682.         if (m_bPlaying)
  683.         {
  684.                 string levelName = GetCurrentLevelName();
  685.                 LogInfo("==============================================================");
  686.                 LogInfo("TimeDemo Play Started ,Level=%s (Total Frames: %d, Recorded Time: %.2fs)", levelName.c_str(), (int)m_records.size(), m_recordedDemoTime.GetSeconds());
  687.  
  688.                 m_bDemoFinished = false;
  689.  
  690.                 RestoreAllEntitiesState();
  691.  
  692.                 // Start demo playback.
  693.                 m_lastPlayedTotalTime = 0;
  694.                 StartSession();
  695.         }
  696.         else
  697.         {
  698.                 LogInfo("AutoTest Play Ended, (%d Runs Performed)", m_numLoops);
  699.                 LogInfo("==============================================================");
  700.  
  701.                 // End demo playback.
  702.                 m_lastPlayedTotalTime = m_totalDemoTime.GetSeconds();
  703.                 StopSession();
  704.         }
  705.         m_bRecording = false;
  706.         m_currentFrame = 0;
  707.         m_totalDemoTime.SetMilliSeconds(0);
  708.         m_lastFpsTimeRecorded = GetTime();
  709.  
  710.         m_numLoops = 0;
  711.         m_fpsCounter = 0;
  712.         m_lastFpsTimeRecorded = GetTime();
  713.  
  714.         m_currFPS = 0;
  715.         m_sumFPS = 0;
  716.         m_minFPS = 10000;
  717.         m_maxFPS = -10000;
  718.         m_nMaxPolys = INT_MIN;
  719.         m_nMinPolys = INT_MAX;
  720.  
  721.         SignalPlayback(bEnable);
  722. }
  723.  
  724. //////////////////////////////////////////////////////////////////////////
  725. void CTimeDemoRecorder::Save(const char* filename)
  726. {
  727.         // Not save empty file.
  728.         if (m_records.empty())
  729.                 return;
  730.  
  731.         m_file = filename;
  732.  
  733.         // Save Time demo file.
  734.         // #if TIMEDEMO_FILE_VERSION== TIMEDEMO_FILE_VERSION_4
  735.         //  STimeDemoHeader_4 hdr;
  736.         // #else
  737.         STimeDemoHeader hdr;
  738.         //#endif
  739.  
  740.         memset(&hdr, 0, sizeof(hdr));
  741.  
  742.         cry_strcpy(hdr.levelname, GetCurrentLevelPath());
  743.         hdr.nDataOffset = sizeof(hdr);
  744.         //hdr.nFrameSize = sizeof(STimeDemoFrame_3);
  745.  
  746.         memcpy(hdr.signature, TIMEDEMO_FILE_SIGNATURE, 4);
  747.         hdr.filetype = TIMEDEMO_FILE_TYPE;
  748.         hdr.version = TIMEDEMO_FILE_VERSION;
  749.  
  750. #if TIMEDEMO_FILE_VERSION == TIMEDEMO_FILE_VERSION_3
  751.  
  752.         hdr.nFrameSize = sizeof(STimeDemoFrame_3);
  753.         hdr.nDemoFlags = 0;
  754.         hdr.numFrames = m_records.size();
  755.         hdr.totalTime = m_recordedDemoTime.GetSeconds();
  756.  
  757.         hdr.nUncompressedDataSze = hdr.nFrameSize * hdr.numFrames;
  758.  
  759.         std::vector<STimeDemoFrame_3> file_records;
  760.         file_records.resize(hdr.numFrames);
  761.  
  762.         for (int i = 0; i < hdr.numFrames; i++)
  763.         {
  764.                 FrameRecord& rec = m_records[i];
  765.                 STimeDemoFrame_3& frame = file_records[i];
  766.                 ZeroStruct(frame);
  767.                 ZeroStruct(frame.inputEvents);
  768.                 frame.nFrameDataSize = sizeof(frame);
  769.                 frame.curViewRotation = rec.playerViewRotation;
  770.                 frame.curCameraAngles = rec.cameraAngles;
  771.                 frame.curPlayerPosition = rec.playerPosition;
  772.                 frame.frametime = rec.frameTime;
  773.                 *frame.nActionFlags = *rec.nActionFlags;
  774.                 frame.fLeaning = rec.fLeaning;
  775.                 frame.nPolygonsPerFrame = rec.nPolygons;
  776.                 frame.numInputEvents = 0;
  777.                 for (InputEventsList::const_iterator it = rec.inputEventsList.begin();
  778.                      it != rec.inputEventsList.end() && frame.numInputEvents < TIMEDEMO_MAX_INPUT_EVENTS; ++it)
  779.                 {
  780.                         const SInputEvent& inputEvent = *it;
  781.                         frame.inputEvents[frame.numInputEvents].deviceType = inputEvent.deviceType;
  782.                         frame.inputEvents[frame.numInputEvents].modifiers = inputEvent.modifiers;
  783.                         frame.inputEvents[frame.numInputEvents].state = inputEvent.state;
  784.                         frame.inputEvents[frame.numInputEvents].keyId = inputEvent.keyId;
  785.                         frame.inputEvents[frame.numInputEvents].value = inputEvent.value;
  786.                         frame.numInputEvents++;
  787.                 }
  788.         }
  789.  
  790. #endif
  791. #if TIMEDEMO_FILE_VERSION == TIMEDEMO_FILE_VERSION_7
  792.  
  793.         hdr.nFrameSize = sizeof(STimeDemoFrame_7);
  794.         hdr.nDemoFlags = 0;
  795.         hdr.numFrames = m_records.size();
  796.  
  797.         float* pHdrFixedTimeStep = (float*)hdr.reserved;
  798.         *pHdrFixedTimeStep = (float)m_demo_fixed_timestep;
  799.         // check possible extra frames for carrying extra game events
  800.  
  801.         int n = hdr.numFrames;
  802.         for (int i = 0; i < n; i++)
  803.         {
  804.                 FrameRecord& rec = m_records[i];
  805.                 int gesize = rec.gameEvents.size();
  806.                 if (gesize > TIMEDEMO_MAX_GAME_EVENTS)
  807.                         hdr.numFrames += (gesize - 1) / TIMEDEMO_MAX_GAME_EVENTS;
  808.         }
  809.  
  810.         hdr.totalTime = m_recordedDemoTime.GetSeconds();
  811.         hdr.nUncompressedDataSze = hdr.nFrameSize * hdr.numFrames;
  812.  
  813.         std::vector<STimeDemoFrame_7> file_records;
  814.         file_records.resize(hdr.numFrames);
  815.  
  816.         for (int i = 0, fr = 0; fr < hdr.numFrames; ++i, ++fr)
  817.         {
  818.                 FrameRecord& rec = m_records[i];
  819.  
  820.                 STimeDemoFrame_7& frame = file_records[fr];
  821.  
  822.                 frame.curPlayerPosition = rec.playerPosition;
  823.                 frame.curPlayerRotation = rec.playerRotation;
  824.                 frame.curViewRotation = rec.playerViewRotation;
  825.                 frame.curHmdPositionOffset = rec.hmdPositionOffset;
  826.                 frame.curHmdViewRotation = rec.hmdViewRotation;
  827.                 frame.frametime = rec.frameTime;
  828.                 *frame.nActionFlags = *rec.nActionFlags;
  829.                 frame.fLeaning = rec.fLeaning;
  830.                 frame.nPolygonsPerFrame = rec.nPolygons;
  831.  
  832.                 //input events
  833.                 frame.numInputEvents = 0;
  834.                 frame.bFollow = 0;
  835.  
  836.                 ZeroStruct(frame.inputEvents);
  837.                 ZeroStruct(frame.gameEvents);
  838.                 for (InputEventsList::const_iterator it = rec.inputEventsList.begin();
  839.                      it != rec.inputEventsList.end() && frame.numInputEvents < TIMEDEMO_MAX_INPUT_EVENTS; ++it)
  840.                 {
  841.                         const SInputEvent& inputEvent = *it;
  842.                         frame.inputEvents[frame.numInputEvents].deviceType = inputEvent.deviceType;
  843.                         frame.inputEvents[frame.numInputEvents].modifiers = inputEvent.modifiers;
  844.                         frame.inputEvents[frame.numInputEvents].state = inputEvent.state;
  845.                         frame.inputEvents[frame.numInputEvents].keyId = inputEvent.keyId;
  846.                         frame.inputEvents[frame.numInputEvents].value = inputEvent.value;
  847.                         frame.numInputEvents++;
  848.                 }
  849.  
  850.                 // game events
  851.                 // LEAVE THE GAME EVENTS FOR LAST (extended frames)
  852.                 frame.numGameEvents = rec.gameEvents.size();
  853.  
  854.                 int remainingEvents = frame.numGameEvents - TIMEDEMO_MAX_GAME_EVENTS;
  855.                 if (frame.numGameEvents > TIMEDEMO_MAX_GAME_EVENTS)
  856.                         frame.numGameEvents = TIMEDEMO_MAX_GAME_EVENTS;
  857.  
  858.                 int fc = 0;
  859.                 for (int j = 0; j < frame.numGameEvents; j++)
  860.                         frame.gameEvents[j] = rec.gameEvents[fc++];
  861.  
  862.                 bool bExtended = false;
  863.  
  864.                 STimeDemoFrame_7* pAddedFrame = &frame;
  865.                 if (remainingEvents > 0)
  866.                         bExtended = true;
  867.                 while (remainingEvents > 0)
  868.                 {
  869.                         //      GameWarning("Timedemo: Exceeding number of game events in frame %i. Those game events will not be recorded.",i);
  870.                         pAddedFrame->bFollow = 1;
  871.                         fr++;
  872.                         pAddedFrame = &file_records[fr];
  873.                         pAddedFrame->numGameEvents = min(remainingEvents, TIMEDEMO_MAX_GAME_EVENTS);
  874.                         remainingEvents -= TIMEDEMO_MAX_GAME_EVENTS;
  875.                         CRY_ASSERT(pAddedFrame->numGameEvents < TIMEDEMO_MAX_GAME_EVENTS);
  876.                         for (int j = 0; j < pAddedFrame->numGameEvents; j++)
  877.                         {
  878.                                 pAddedFrame->gameEvents[j] = rec.gameEvents[fc++];
  879.                         }
  880.                 }
  881.  
  882.                 if (bExtended)
  883.                         pAddedFrame->bFollow = 0;
  884.         }
  885.  
  886. #endif
  887.  
  888.         //////////////////////////////////////////////////////////////////////////
  889.         // Save to file.
  890.         //////////////////////////////////////////////////////////////////////////
  891.  
  892.         CCryFile file;
  893.         if (!file.Open(filename, "wb"))
  894.         {
  895.                 GetISystem()->Warning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, 0, filename, "Cannot open time demo file %s", filename);
  896.                 return;
  897.         }
  898.  
  899.         size_t nCompressedSize = hdr.nUncompressedDataSze * 2 + 1024;
  900.         char* pCompressedData = new char[nCompressedSize];
  901.         if (GetISystem()->CompressDataBlock(&file_records[0], hdr.nUncompressedDataSze, pCompressedData, nCompressedSize))
  902.         {
  903.                 // Save compressed.
  904.                 hdr.nCompressedDataSize = nCompressedSize;
  905.                 hdr.nDemoFlags |= eTimeDemoCompressed;
  906.  
  907.                 file.Write(&hdr, sizeof(hdr));
  908.                 file.Write(pCompressedData, hdr.nCompressedDataSize);
  909.         }
  910.         else
  911.         {
  912.                 // Save uncompressed.
  913.                 file.Write(&hdr, sizeof(hdr));
  914.                 file.Write(&file_records[0], hdr.nUncompressedDataSze);
  915.         }
  916.  
  917.         delete[]pCompressedData;
  918.  
  919.         /*
  920.            XmlNodeRef root = GetISystem()->CreateXmlNode( "TimeDemo" );
  921.            root->setAttr( "TotalTime",m_recordedDemoTime );
  922.            for (FrameRecords::iterator it = m_records.begin(); it != m_records.end(); ++it)
  923.            {
  924.             FrameRecord &rec = *it;
  925.             XmlNodeRef xmlRecord = root->newChild( "Frame" );
  926.             xmlRecord->setAttr( "Pos",rec.playerPos );
  927.             xmlRecord->setAttr( "Ang",rec.playerRotation );
  928.             xmlRecord->setAttr( "Time",rec.frameTime );
  929.            }
  930.            root->saveToFile( filename );
  931.          */
  932. }
  933.  
  934. //////////////////////////////////////////////////////////////////////////
  935. void CTimeDemoRecorder::AddFrameRecord(const FrameRecord& rec)
  936. {
  937.         m_records.push_back(rec);
  938. }
  939.  
  940. //////////////////////////////////////////////////////////////////////////
  941. bool CTimeDemoRecorder::Load(const char* filename)
  942. {
  943.         // ignore invalid file access fro time demo playback
  944.         CDebugAllowFileAccess ignoreInvalidFileAccess;
  945.  
  946.         stl::free_container(m_records);
  947.         m_recordedDemoTime.SetMilliSeconds(0);
  948.         m_totalDemoTime.SetMilliSeconds(0);
  949.  
  950.         IInput* pIInput = GetISystem()->GetIInput(); // Cache IInput pointer.
  951.  
  952.         CCryFile file;
  953.         if (!file.Open(filename, "rb", ICryPak::FOPEN_ONDISK))
  954.         {
  955.                 char str[256];
  956.                 CryGetCurrentDirectory(sizeof(str), str);
  957.  
  958.                 GetISystem()->Warning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, 0, filename, "Cannot open time demo file %s (%s)", filename, str);
  959.                 return false;
  960.         }
  961.  
  962.         // Load Time demo file.
  963.         // #if TIMEDEMO_FILE_VERSION== TIMEDEMO_FILE_VERSION_4
  964.         //  STimeDemoHeader_4 hdr;
  965.         // #else
  966.         STimeDemoHeader hdr;
  967.         //#endif
  968.  
  969.         file.ReadRaw(&hdr, sizeof(hdr));
  970.  
  971.         if (hdr.signature[0] == 'C' && hdr.signature[1] == 'R' && hdr.signature[2] == 'Y' && (uint8)hdr.signature[3] == 0x96)
  972.         {
  973.                 // This is old header.
  974.                 file.Seek(0, SEEK_SET);
  975.                 file.ReadRaw(((char*)&hdr) + 1, sizeof(hdr) - 1); // Old header was 1 byte shorter at the signature.
  976.         }
  977.  
  978.         // Swap endian if needed.
  979.         hdr.SwapEndianThis();
  980.  
  981.         m_recordedDemoTime = hdr.totalTime;
  982.         m_totalDemoTime = m_recordedDemoTime;
  983.  
  984.         m_file = filename;
  985.         m_records.reserve(hdr.numFrames);
  986.  
  987.         m_fileVersion = hdr.version;
  988.  
  989.         const float fixedTimeStepMin = 0.0f;
  990.         const float fixedTimeStepMax = 1000.f;
  991.  
  992.         switch (m_fileVersion)
  993.         {
  994.         case TIMEDEMO_FILE_VERSION_1:
  995.                 {
  996.                         for (int i = 0; i < hdr.numFrames && !file.IsEof(); i++)
  997.                         {
  998.                                 STimeDemoFrame_1 frame;
  999.                                 FrameRecord rec;
  1000.                                 file.ReadRaw(&frame, sizeof(frame));
  1001.  
  1002.                                 Quat rot;
  1003.                                 rot.SetRotationXYZ(Ang3(DEG2RAD(frame.angles)));
  1004.                                 rot = rot * Quat::CreateRotationZ(gf_PI); // to fix some game to camera rotation issues.
  1005.                                 rec.playerViewRotation = rot;
  1006.                                 rec.cameraAngles = frame.angles;
  1007.                                 rec.playerPosition = frame.curPlayerPosition;
  1008.                                 rec.frameTime = frame.frametime;
  1009.                                 *rec.nActionFlags = *frame.nActionFlags;
  1010.                                 rec.fLeaning = frame.fLeaning;
  1011.                                 rec.nPolygons = frame.nPolygonsPerFrame;
  1012.                                 AddFrameRecord(rec);
  1013.                         }
  1014.                 }
  1015.                 break;
  1016.  
  1017.         case TIMEDEMO_FILE_VERSION_2:
  1018.                 {
  1019.                         char* pFrameData = new char[hdr.nUncompressedDataSze];
  1020.                         if (hdr.nDemoFlags & eTimeDemoCompressed)
  1021.                         {
  1022.                                 char* pCompressedData = new char[hdr.nCompressedDataSize];
  1023.                                 // Read Compressed.
  1024.                                 file.ReadRaw(pCompressedData, hdr.nCompressedDataSize);
  1025.  
  1026.                                 // Uncompress data.
  1027.                                 size_t uncompressedSize = hdr.nUncompressedDataSze;
  1028.                                 GetISystem()->DecompressDataBlock(pCompressedData, hdr.nCompressedDataSize, pFrameData, uncompressedSize);
  1029.                                 CRY_ASSERT(uncompressedSize == hdr.nUncompressedDataSze);
  1030.                                 if (uncompressedSize != hdr.nUncompressedDataSze)
  1031.                                 {
  1032.                                         GameWarning("Corrupted compressed time demo file %s", filename);
  1033.                                         delete[]pCompressedData;
  1034.                                         return false;
  1035.                                 }
  1036.                                 delete[]pCompressedData;
  1037.                         }
  1038.                         else
  1039.                         {
  1040.                                 // Read Uncompressed.
  1041.                                 if (file.ReadRaw(pFrameData, hdr.nUncompressedDataSze) != hdr.nUncompressedDataSze)
  1042.                                 {
  1043.                                         GameWarning("Corrupted time demo file %s", filename);
  1044.                                         return false;
  1045.                                 }
  1046.                         }
  1047.                         CRY_ASSERT(sizeof(STimeDemoFrame_2) * hdr.numFrames == hdr.nUncompressedDataSze);
  1048.                         if (sizeof(STimeDemoFrame_2) * hdr.numFrames != hdr.nUncompressedDataSze)
  1049.                         {
  1050.                                 GameWarning("Corrupted time demo file %s", filename);
  1051.                                 return false;
  1052.                         }
  1053.                         STimeDemoFrame_2* pFileFrame = (STimeDemoFrame_2*)pFrameData;
  1054.                         for (int i = 0; i < hdr.numFrames; i++)
  1055.                         {
  1056.                                 STimeDemoFrame_2& frame = *pFileFrame++;
  1057.                                 frame.SwapEndianThis(); // Swap endian if needed
  1058.  
  1059.                                 FrameRecord rec;
  1060.  
  1061.                                 rec.playerViewRotation = frame.curViewRotation;
  1062.                                 rec.cameraAngles = frame.curCameraAngles;
  1063.                                 rec.playerPosition = frame.curPlayerPosition;
  1064.                                 rec.frameTime = frame.frametime;
  1065.                                 *rec.nActionFlags = *frame.nActionFlags;
  1066.                                 rec.fLeaning = frame.fLeaning;
  1067.                                 rec.nPolygons = frame.nPolygonsPerFrame;
  1068.                                 if (frame.numInputEvents > 0)
  1069.                                 {
  1070.                                         for (int j = 0; j < frame.numInputEvents; j++)
  1071.                                         {
  1072.                                                 SInputEvent inputEvent;
  1073.                                                 inputEvent.deviceType = (EInputDeviceType)frame.inputEvents[j].deviceType;
  1074.                                                 inputEvent.modifiers = frame.inputEvents[j].modifiers;
  1075.                                                 inputEvent.state = (EInputState)frame.inputEvents[j].state;
  1076.                                                 inputEvent.keyId = (EKeyId)frame.inputEvents[j].keyId;
  1077.                                                 inputEvent.value = frame.inputEvents[j].value;
  1078.                                                 SInputSymbol* pInputSymbol = pIInput ? pIInput->LookupSymbol(inputEvent.deviceType, 0, inputEvent.keyId) : 0;
  1079.                                                 if (pInputSymbol)
  1080.                                                         inputEvent.keyName = pInputSymbol->name;
  1081.                                                 rec.inputEventsList.push_back(inputEvent);
  1082.                                         }
  1083.                                 }
  1084.                                 AddFrameRecord(rec);
  1085.                         }
  1086.  
  1087.                         delete[]pFrameData;
  1088.                 }
  1089.                 break;
  1090.  
  1091.         case TIMEDEMO_FILE_VERSION_3:
  1092.                 {
  1093.                         char* pFrameData = new char[hdr.nUncompressedDataSze];
  1094.                         if (hdr.nDemoFlags & eTimeDemoCompressed)
  1095.                         {
  1096.                                 char* pCompressedData = new char[hdr.nCompressedDataSize];
  1097.                                 // Read Compressed.
  1098.                                 file.ReadRaw(pCompressedData, hdr.nCompressedDataSize);
  1099.  
  1100.                                 // Uncompress data.
  1101.                                 size_t uncompressedSize = hdr.nUncompressedDataSze;
  1102.                                 GetISystem()->DecompressDataBlock(pCompressedData, hdr.nCompressedDataSize, pFrameData, uncompressedSize);
  1103.                                 CRY_ASSERT(uncompressedSize == hdr.nUncompressedDataSze);
  1104.                                 if (uncompressedSize != hdr.nUncompressedDataSze)
  1105.                                 {
  1106.                                         GameWarning("Corrupted compressed time demo file %s", filename);
  1107.                                         delete[]pCompressedData;
  1108.                                         return false;
  1109.                                 }
  1110.                                 delete[]pCompressedData;
  1111.                         }
  1112.                         else
  1113.                         {
  1114.                                 // Read Uncompressed.
  1115.                                 if (file.ReadRaw(pFrameData, hdr.nUncompressedDataSze) != hdr.nUncompressedDataSze)
  1116.                                 {
  1117.                                         GameWarning("Corrupted time demo file %s", filename);
  1118.                                         return false;
  1119.                                 }
  1120.                         }
  1121.  
  1122.                         CRY_ASSERT(sizeof(STimeDemoFrame_3) * hdr.numFrames == hdr.nUncompressedDataSze);
  1123.                         if (sizeof(STimeDemoFrame_3) * hdr.numFrames != hdr.nUncompressedDataSze)
  1124.                         {
  1125.                                 GameWarning("Corrupted time demo file %s", filename);
  1126.                                 return false;
  1127.                         }
  1128.  
  1129.                         STimeDemoFrame_3* pFileFrame = (STimeDemoFrame_3*)pFrameData;
  1130.                         for (int i = 0; i < hdr.numFrames; i++)
  1131.                         {
  1132.                                 STimeDemoFrame_3& frame = *pFileFrame++;
  1133.                                 frame.SwapEndianThis(); // Swap endian if needed
  1134.                                 FrameRecord rec;
  1135.  
  1136.                                 rec.playerViewRotation = frame.curViewRotation;
  1137.                                 rec.cameraAngles = frame.curCameraAngles;
  1138.                                 rec.playerPosition = frame.curPlayerPosition;
  1139.                                 rec.frameTime = frame.frametime;
  1140.                                 *rec.nActionFlags = *frame.nActionFlags;
  1141.                                 rec.fLeaning = frame.fLeaning;
  1142.                                 rec.nPolygons = frame.nPolygonsPerFrame;
  1143.  
  1144.                                 if (frame.numInputEvents > 0)
  1145.                                 {
  1146.                                         for (int j = 0; j < frame.numInputEvents; j++)
  1147.                                         {
  1148.                                                 SInputEvent inputEvent;
  1149.                                                 inputEvent.deviceType = (EInputDeviceType)frame.inputEvents[j].deviceType;
  1150.                                                 inputEvent.modifiers = frame.inputEvents[j].modifiers;
  1151.                                                 inputEvent.state = (EInputState)frame.inputEvents[j].state;
  1152.                                                 inputEvent.keyId = (EKeyId)frame.inputEvents[j].keyId;
  1153.                                                 inputEvent.value = frame.inputEvents[j].value;
  1154.                                                 SInputSymbol* pInputSymbol = pIInput ? pIInput->LookupSymbol(inputEvent.deviceType, 0, inputEvent.keyId) : 0;
  1155.                                                 if (pInputSymbol)
  1156.                                                         inputEvent.keyName = pInputSymbol->name;
  1157.                                                 rec.inputEventsList.push_back(inputEvent);
  1158.                                         }
  1159.                                 }
  1160.  
  1161.                                 AddFrameRecord(rec);
  1162.                         }
  1163.  
  1164.                         delete[]pFrameData;
  1165.                 }
  1166.                 break;
  1167.  
  1168.         case TIMEDEMO_FILE_VERSION_4:
  1169.                 {
  1170.                         float recFixedTimeStep = *(float*)(hdr.reserved);
  1171.                         if (recFixedTimeStep > 0 && recFixedTimeStep < 1000)
  1172.                                 m_demo_fixed_timestep = (uint16)recFixedTimeStep;
  1173.  
  1174.                         char* pFrameData = new char[hdr.nUncompressedDataSze];
  1175.                         if (hdr.nDemoFlags & eTimeDemoCompressed)
  1176.                         {
  1177.                                 char* pCompressedData = new char[hdr.nCompressedDataSize];
  1178.                                 // Read Compressed.
  1179.                                 file.ReadRaw(pCompressedData, hdr.nCompressedDataSize);
  1180.  
  1181.                                 // Uncompress data.
  1182.                                 size_t uncompressedSize = hdr.nUncompressedDataSze;
  1183.                                 GetISystem()->DecompressDataBlock(pCompressedData, hdr.nCompressedDataSize, pFrameData, uncompressedSize);
  1184.                                 CRY_ASSERT(uncompressedSize == hdr.nUncompressedDataSze);
  1185.                                 if (uncompressedSize != hdr.nUncompressedDataSze)
  1186.                                 {
  1187.                                         GameWarning("Corrupted compressed time demo file %s", filename);
  1188.                                         delete[]pCompressedData;
  1189.                                         return false;
  1190.                                 }
  1191.                                 delete[]pCompressedData;
  1192.                         }
  1193.                         else
  1194.                         {
  1195.                                 // Read Uncompressed.
  1196.                                 if (file.ReadRaw(pFrameData, hdr.nUncompressedDataSze) != hdr.nUncompressedDataSze)
  1197.                                 {
  1198.                                         GameWarning("Corrupted time demo file %s", filename);
  1199.                                         return false;
  1200.                                 }
  1201.                         }
  1202.  
  1203.                         CRY_ASSERT(sizeof(STimeDemoFrame_4) * hdr.numFrames == hdr.nUncompressedDataSze);
  1204.                         if (sizeof(STimeDemoFrame_4) * hdr.numFrames != hdr.nUncompressedDataSze)
  1205.                         {
  1206.                                 GameWarning("Corrupted time demo file %s", filename);
  1207.                                 return false;
  1208.                         }
  1209.  
  1210.                         STimeDemoFrame_4* pFileFrame = (STimeDemoFrame_4*)pFrameData;
  1211.                         for (int i = 0; i < hdr.numFrames; i++)
  1212.                         {
  1213.                                 STimeDemoFrame_4& frame = *pFileFrame++;
  1214.                                 frame.SwapEndianThis(); // Swap endian if needed
  1215.                                 FrameRecord rec;
  1216.  
  1217.                                 rec.playerViewRotation = frame.curViewRotation;
  1218.                                 rec.cameraAngles = frame.curCameraAngles;
  1219.                                 rec.playerPosition = frame.curPlayerPosition;
  1220.                                 rec.frameTime = frame.frametime;
  1221.                                 *rec.nActionFlags = *frame.nActionFlags;
  1222.                                 rec.fLeaning = frame.fLeaning;
  1223.                                 rec.nPolygons = frame.nPolygonsPerFrame;
  1224.  
  1225.                                 if (frame.numInputEvents > 0)
  1226.                                 {
  1227.                                         for (int j = 0; j < frame.numInputEvents; j++)
  1228.                                         {
  1229.                                                 SInputEvent inputEvent;
  1230.                                                 inputEvent.deviceType = (EInputDeviceType)frame.inputEvents[j].deviceType;
  1231.                                                 inputEvent.modifiers = frame.inputEvents[j].modifiers;
  1232.                                                 inputEvent.state = (EInputState)frame.inputEvents[j].state;
  1233.                                                 inputEvent.keyId = (EKeyId)frame.inputEvents[j].keyId;
  1234.                                                 inputEvent.value = frame.inputEvents[j].value;
  1235.                                                 SInputSymbol* pInputSymbol = pIInput ? pIInput->LookupSymbol(inputEvent.deviceType, 0, inputEvent.keyId) : 0;
  1236.                                                 if (pInputSymbol)
  1237.                                                         inputEvent.keyName = pInputSymbol->name;
  1238.                                                 rec.inputEventsList.push_back(inputEvent);
  1239.                                         }
  1240.                                 }
  1241.  
  1242.                                 if (frame.numGameEvents > 0)
  1243.                                 {
  1244.                                         for (int j = 0; j < frame.numGameEvents; j++)
  1245.                                                 rec.gameEvents.push_back(frame.gameEvents[j]);
  1246.                                 }
  1247.  
  1248.                                 STimeDemoFrame_4* pAddFrame = &frame;
  1249.                                 while (pAddFrame->bFollow && i < hdr.numFrames - 1)
  1250.                                 {
  1251.                                         ++i;
  1252.                                         pAddFrame = pFileFrame++;
  1253.                                         for (int j = 0; j < pAddFrame->numGameEvents; j++)
  1254.                                                 rec.gameEvents.push_back(pAddFrame->gameEvents[j]);
  1255.                                 }
  1256.  
  1257.                                 AddFrameRecord(rec);
  1258.                         }
  1259.  
  1260.                         delete[]pFrameData;
  1261.                 }
  1262.                 break;
  1263.  
  1264.         case TIMEDEMO_FILE_VERSION_7:
  1265.                 {
  1266.                         float recFixedTimeStep = *(float*)(hdr.reserved);
  1267.  
  1268.                         if (recFixedTimeStep > fixedTimeStepMin && recFixedTimeStep < fixedTimeStepMax)
  1269.                         {
  1270.                                 m_demo_fixed_timestep = (uint16)recFixedTimeStep;
  1271.                         }
  1272.  
  1273.                         std::vector<char> frameData;
  1274.                         frameData.resize(hdr.nUncompressedDataSze);
  1275.  
  1276.                         if (hdr.nDemoFlags & eTimeDemoCompressed)
  1277.                         {
  1278.                                 std::vector<char> compressedData;
  1279.                                 compressedData.resize(hdr.nCompressedDataSize);
  1280.  
  1281.                                 // Read Compressed.
  1282.                                 file.ReadRaw(compressedData.data(), compressedData.size());
  1283.  
  1284.                                 // Uncompress data.
  1285.                                 size_t uncompressedSize = frameData.size();
  1286.                                 GetISystem()->DecompressDataBlock(compressedData.data(), compressedData.size(), frameData.data(), uncompressedSize);
  1287.                                 CRY_ASSERT(uncompressedSize == frameData.size());
  1288.  
  1289.                                 if (uncompressedSize != frameData.size())
  1290.                                 {
  1291.                                         GameWarning("Corrupted compressed time demo file %s", filename);
  1292.                                         return false;
  1293.                                 }
  1294.                         }
  1295.                         else
  1296.                         {
  1297.                                 // Read Uncompressed.
  1298.                                 if (file.ReadRaw(frameData.data(), frameData.size()) != frameData.size())
  1299.                                 {
  1300.                                         GameWarning("Corrupted time demo file %s", filename);
  1301.                                         return false;
  1302.                                 }
  1303.                         }
  1304.  
  1305.                         CRY_ASSERT(sizeof(STimeDemoFrame_7) * hdr.numFrames == hdr.nUncompressedDataSze);
  1306.                         if (sizeof(STimeDemoFrame_7) * hdr.numFrames != hdr.nUncompressedDataSze)
  1307.                         {
  1308.                                 GameWarning("Corrupted time demo file %s", filename);
  1309.                                 return false;
  1310.                         }
  1311.  
  1312.                         STimeDemoFrame_7* pFileFrame = (STimeDemoFrame_7*)(frameData.data());
  1313.  
  1314.                         for (int i = 0; i < hdr.numFrames; ++i)
  1315.                         {
  1316.                                 STimeDemoFrame_7& frame = *pFileFrame++;
  1317.                                 frame.SwapEndianThis(); // Swap endian if needed
  1318.  
  1319.                                 FrameRecord rec;
  1320.                                 rec.playerPosition = frame.curPlayerPosition;
  1321.                                 rec.playerRotation = frame.curPlayerRotation;
  1322.                                 rec.playerViewRotation = frame.curViewRotation;
  1323.                                 rec.hmdPositionOffset = frame.curHmdPositionOffset;
  1324.                                 rec.hmdViewRotation = frame.curHmdViewRotation;
  1325.                                 rec.frameTime = frame.frametime;
  1326.                                 *rec.nActionFlags = *frame.nActionFlags;
  1327.                                 rec.fLeaning = frame.fLeaning;
  1328.                                 rec.nPolygons = frame.nPolygonsPerFrame;
  1329.  
  1330.                                 if (frame.numInputEvents > 0)
  1331.                                 {
  1332.                                         rec.inputEventsList.reserve(frame.numInputEvents);
  1333.  
  1334.                                         for (int j = 0; j < frame.numInputEvents; ++j)
  1335.                                         {
  1336.                                                 SInputEvent inputEvent;
  1337.                                                 inputEvent.deviceType = (EInputDeviceType)frame.inputEvents[j].deviceType;
  1338.                                                 inputEvent.modifiers = frame.inputEvents[j].modifiers;
  1339.                                                 inputEvent.state = (EInputState)frame.inputEvents[j].state;
  1340.                                                 inputEvent.keyId = (EKeyId)frame.inputEvents[j].keyId;
  1341.                                                 inputEvent.value = frame.inputEvents[j].value;
  1342.                                                 SInputSymbol* pInputSymbol = pIInput ? pIInput->LookupSymbol(inputEvent.deviceType, 0, inputEvent.keyId) : 0;
  1343.                                                 if (pInputSymbol)
  1344.                                                 {
  1345.                                                         inputEvent.keyName = pInputSymbol->name;
  1346.                                                 }
  1347.                                                 rec.inputEventsList.push_back(inputEvent);
  1348.                                         }
  1349.                                 }
  1350.  
  1351.                                 if (frame.numGameEvents > 0)
  1352.                                 {
  1353.                                         rec.gameEvents.reserve(frame.numGameEvents);
  1354.  
  1355.                                         for (int j = 0; j < frame.numGameEvents; ++j)
  1356.                                         {
  1357.                                                 rec.gameEvents.push_back(frame.gameEvents[j]);
  1358.                                         }
  1359.                                 }
  1360.  
  1361.                                 STimeDemoFrame_7* pAddFrame = &frame;
  1362.                                 while (pAddFrame->bFollow && i < hdr.numFrames - 1)
  1363.                                 {
  1364.                                         ++i;
  1365.                                         pAddFrame = pFileFrame++;
  1366.                                         rec.gameEvents.reserve(pAddFrame->numGameEvents);
  1367.  
  1368.                                         for (int j = 0; j < pAddFrame->numGameEvents; ++j)
  1369.                                         {
  1370.                                                 rec.gameEvents.push_back(pAddFrame->gameEvents[j]);
  1371.                                         }
  1372.                                 }
  1373.  
  1374.                                 AddFrameRecord(rec);
  1375.                         }
  1376.                 }
  1377.                 break;
  1378.  
  1379.         default:
  1380.                 {
  1381.                         GameWarning("Timedemo: Unknown file version");
  1382.                 }
  1383.                 break;
  1384.         }
  1385.  
  1386.         return true;
  1387. }
  1388.  
  1389. //////////////////////////////////////////////////////////////////////////
  1390. void CTimeDemoRecorder::PreUpdate()
  1391. {
  1392.         if (m_bPlaying && !m_bPaused && !gEnv->pConsole->GetStatus()) // Only when console closed.
  1393.         {
  1394.                 bool bPlaying = PlayFrame();
  1395.                 if (!bPlaying) // No more frames
  1396.                 {
  1397.                         // Stop playing if max runs reached.
  1398.                         LogEndOfLoop();
  1399.                         m_numLoops++;
  1400.  
  1401.                         if (m_numLoops >= m_maxLoops * m_numOrientations)
  1402.                         {
  1403.                                 Play(false);
  1404.                                 m_bDemoFinished = true;
  1405.                         }
  1406.                         else
  1407.                         {
  1408.                                 ResetSessionLoop();
  1409.                         }
  1410.                 }
  1411.         }
  1412. }
  1413.  
  1414. //////////////////////////////////////////////////////////////////////////
  1415. void CTimeDemoRecorder::PostUpdate()
  1416. {
  1417.         if (gEnv->pSystem->IsQuitting())
  1418.         {
  1419.                 return;
  1420.         }
  1421.  
  1422.         if (!m_countDownPlay && !m_bPlaying && m_bDemoFinished)
  1423.         {
  1424.                 if (!m_demoLevels.empty())
  1425.                 {
  1426.                         StartNextChainedLevel();
  1427.                         return;
  1428.                 }
  1429.                 ICVar* pFinishCmd = gEnv->pConsole->GetCVar("demo_finish_cmd");
  1430.                 if (pFinishCmd)
  1431.                 {
  1432.                         const char* const szFinishCmd = pFinishCmd->GetString();
  1433.                         if (szFinishCmd && szFinishCmd[0] != '\0')
  1434.                         {
  1435.                                 gEnv->pConsole->ExecuteString(szFinishCmd);
  1436.                         }
  1437.                 }
  1438.                 if (m_demo_quit)
  1439.                 {
  1440.                         QuitGame();
  1441.                 }
  1442.                 else if (!m_demoEnded)
  1443.                 {
  1444.                         EndDemo();
  1445.                 }
  1446.         }
  1447.  
  1448.         if (m_countDownPlay)
  1449.         {
  1450.                 // to avoid playing demo before game is initialized (when running autotest)
  1451.                 m_countDownPlay--;
  1452.                 if (m_countDownPlay == 0)
  1453.                         Play(true);
  1454.         }
  1455.  
  1456.         ProcessKeysInput();
  1457.  
  1458.         if (!m_bPaused && m_bRecording && !gEnv->pConsole->GetStatus()) // Only when console closed.
  1459.         {
  1460.                 // Reset random number generators seed.
  1461.                 if (!RecordFrame())
  1462.                 {
  1463.                         Record(false);
  1464.                 }
  1465.         }
  1466.  
  1467.         if ((m_bPlaying || m_bRecording) && m_demo_noinfo <= 0)
  1468.                 RenderInfo(1);
  1469. }
  1470.  
  1471. //////////////////////////////////////////////////////////////////////////
  1472. bool CTimeDemoRecorder::RecordFrame()
  1473. {
  1474.         CTimeValue time = GetTime();
  1475.  
  1476.         if (m_bPaused)
  1477.         {
  1478.                 m_lastFrameTime = time;
  1479.                 return true;
  1480.         }
  1481.  
  1482.         GetISystem()->GetRandomGenerator().Seed(0);
  1483.  
  1484.         FrameRecord rec;
  1485.  
  1486.         rec.frameTime = (time - m_lastFrameTime).GetSeconds();
  1487.  
  1488.         IEntity* pPlayerEntity = NULL;
  1489.  
  1490.         IActor* pClientActor = gEnv->pGameFramework->GetClientActor();
  1491.         if (pClientActor)
  1492.         {
  1493.                 pPlayerEntity = pClientActor->GetEntity();
  1494.         }
  1495.  
  1496.         if (pPlayerEntity)
  1497.         {
  1498.                 rec.playerPosition = pPlayerEntity->GetPos();
  1499.                 rec.playerRotation = pPlayerEntity->GetRotation();
  1500.                 rec.playerViewRotation = pClientActor == NULL ? pPlayerEntity->GetRotation() : pClientActor->GetViewRotation();
  1501.         }
  1502.  
  1503.         // Legacy
  1504.         Ang3 cameraAngles = Ang3(GetISystem()->GetViewCamera().GetMatrix());
  1505.         rec.cameraAngles = RAD2DEG(cameraAngles);
  1506.  
  1507.         if (IHmdManager* pHmdManager = gEnv->pSystem->GetHmdManager())
  1508.         {
  1509.                 if (IHmdDevice* pHmdDevice = pHmdManager->GetHmdDevice())
  1510.                 {
  1511.                         const HmdTrackingState& trackingState = pHmdDevice->GetLocalTrackingState();
  1512.  
  1513.                         if (trackingState.CheckStatusFlags(eHmdStatus_IsUsable))
  1514.                         {
  1515.                                 rec.hmdViewRotation = trackingState.pose.orientation;
  1516.                                 rec.hmdPositionOffset = trackingState.pose.position;
  1517.                         }
  1518.                 }
  1519.         }
  1520.         //////////////////////////////////////////////////////////////////////////
  1521.         // Record input events.
  1522.         //////////////////////////////////////////////////////////////////////////
  1523.         rec.inputEventsList = m_currentFrameInputEvents;
  1524.         rec.entityEvents = m_currentFrameEntityEvents;
  1525.         rec.gameEvents = m_currentFrameGameEvents;
  1526.  
  1527.         m_currentFrameInputEvents.clear();
  1528.         m_currentFrameEntityEvents.clear();
  1529.         m_currentFrameGameEvents.clear();
  1530.  
  1531.         //////////////////////////////////////////////////////////////////////////
  1532.  
  1533.         m_totalDemoTime += rec.frameTime;
  1534.  
  1535.         int nPolygons, nShadowVolPolys;
  1536.         gEnv->pRenderer->GetPolyCount(nPolygons, nShadowVolPolys);
  1537.         rec.nPolygons = nPolygons;
  1538.  
  1539.         m_nTotalPolysRecorded += nPolygons;
  1540.  
  1541.         AddFrameRecord(rec);
  1542.  
  1543.         FrameRecords::iterator it = m_records.begin();
  1544.         FrameRecords::iterator it1 = it;
  1545.         ++it1;
  1546.  
  1547.         m_lastFrameTime = GetTime();
  1548.  
  1549.         if (m_demo_save_every_frame)
  1550.         {
  1551.                 // Save after stopping.
  1552.                 string filename = PathUtil::Make(GetCurrentLevelPath(), s_timedemo_file->GetString(), "tmd");
  1553.                 s_pTimeDemoRecorder->Save(filename.c_str());
  1554.         }
  1555.  
  1556.         m_currentFrame++;
  1557.         if (m_currentFrame >= m_demo_max_frames)
  1558.         {
  1559.                 Record(false);
  1560.                 return false;
  1561.         }
  1562.  
  1563.         return true;
  1564. }
  1565.  
  1566. //////////////////////////////////////////////////////////////////////////
  1567. bool CTimeDemoRecorder::PlayFrame()
  1568. {
  1569.         if (m_records.empty()) // can't playback empty records.
  1570.                 return false;
  1571.  
  1572.         CTimeValue time = GetTime();
  1573.         CTimeValue deltaFrameTime = (time - m_lastFrameTime);
  1574.         float frameTime = deltaFrameTime.GetSeconds();
  1575.  
  1576.         if (m_bPaused)
  1577.         {
  1578.                 m_lastFrameTime = time;
  1579.                 return true;
  1580.         }
  1581.  
  1582.         FrameRecord& rec = m_records[m_currentFrame];
  1583.         m_nTotalPolysRecorded += rec.nPolygons;
  1584.  
  1585.         //////////////////////////////////////////////////////////////////////////
  1586.         // Play input events.
  1587.         //////////////////////////////////////////////////////////////////////////
  1588.         if (!rec.inputEventsList.empty())
  1589.         {
  1590.                 //string str;
  1591.                 for (InputEventsList::const_iterator it = rec.inputEventsList.begin(), end = rec.inputEventsList.end(); it != end; ++it)
  1592.                 {
  1593.                         const SInputEvent& inputEvent = *it;
  1594.                         if (gEnv->pInput)
  1595.                                 gEnv->pInput->PostInputEvent(inputEvent);
  1596.                 }
  1597.         }
  1598.         //////////////////////////////////////////////////////////////////////////
  1599.  
  1600.         //////////////////////////////////////////////////////////////////////////
  1601.         // Play back entity events.
  1602.         //////////////////////////////////////////////////////////////////////////
  1603.         {
  1604.                 for (int i = 0; i < rec.entityEvents.size(); i++)
  1605.                 {
  1606.                         PlayBackEntityEvent(rec.entityEvents[i]);
  1607.                 }
  1608.         }
  1609.         //////////////////////////////////////////////////////////////////////////
  1610.  
  1611.         IEntity* pPlayer = NULL;
  1612.         IActor* pClActor = gEnv->pGameFramework->GetClientActor();
  1613.         if (pClActor)
  1614.         {
  1615.                 pPlayer = pClActor->GetEntity();
  1616.         }
  1617.  
  1618.         if (pPlayer)
  1619.         {
  1620.                 if (pPlayer->GetParent() == 0)
  1621.                 {
  1622.                         // Only if player is not linked to anything.
  1623.                         pPlayer->SetPos(rec.playerPosition, ENTITY_XFORM_TIMEDEMO);
  1624.  
  1625.                         int orientationIndex = m_numLoops % m_numOrientations;
  1626.                         float zAngle = ((float)orientationIndex / m_numOrientations) * gf_PI2;
  1627.                         const Quat& rotation = m_demo_use_hmd_rotation == 0 ? rec.playerViewRotation : rec.playerRotation;
  1628.  
  1629.                         Quat adjustedPlayerRotation = Quat::CreateRotationZ(zAngle) * rotation;
  1630.                         CRY_ASSERT(adjustedPlayerRotation.IsValid());
  1631.  
  1632.                         pPlayer->SetRotation(adjustedPlayerRotation, ENTITY_XFORM_TIMEDEMO);
  1633.                 }
  1634.         }
  1635.  
  1636.         m_totalDemoTime += deltaFrameTime;
  1637.  
  1638.         int nPolygons = ComputePolyCount();
  1639.         m_nTotalPolysPlayed += nPolygons;
  1640.  
  1641.         //////////////////////////////////////////////////////////////////////////
  1642.         // Calculate Frame Rates.
  1643.         //////////////////////////////////////////////////////////////////////////
  1644.         // Skip some frames before calculating frame rates.
  1645.         float timeElapsed = (time - m_lastFpsTimeRecorded).GetSeconds();
  1646.         if (timeElapsed > 1 && m_fpsCounter > 0)
  1647.         {
  1648.                 // Skip some frames before recording frame rates.
  1649.                 //if (m_currentFrame > 60)
  1650.                 m_nPolysPerSec = (int)(float(m_nPolysCounter) / timeElapsed);
  1651.                 m_nPolysCounter = 0;
  1652.  
  1653.                 m_fpsCounter = 0;
  1654.                 m_lastFpsTimeRecorded = time;
  1655.         }
  1656.         else
  1657.         {
  1658.                 m_fpsCounter++;
  1659.         }
  1660.  
  1661.         if (m_currentFrame > m_minFPSCounter)
  1662.         {
  1663.                 //m_currFPS = (float)m_fpsCounter / timeElapsed;
  1664.  
  1665.                 m_currFPS = (float)(1.0 / deltaFrameTime.GetSeconds());
  1666.                 m_sumFPS += m_currFPS;
  1667.  
  1668.                 if (m_currFPS > m_maxFPS)
  1669.                 {
  1670.                         m_maxFPS_Frame = m_currentFrame;
  1671.                         m_maxFPS = m_currFPS;
  1672.                 }
  1673.                 if (m_currFPS < m_minFPS)
  1674.                 {
  1675.                         m_minFPS_Frame = m_currentFrame;
  1676.                         m_minFPS = m_currFPS;
  1677.                 }
  1678.         }
  1679.  
  1680.         //////////////////////////////////////////////////////////////////////////
  1681.         // Fill Time Demo Info structure.
  1682.         //////////////////////////////////////////////////////////////////////////
  1683.         if (m_pTimeDemoInfo)
  1684.         {
  1685.                 m_pTimeDemoInfo->pFrames[m_currentFrame].fFrameRate = (float)(1.0 / deltaFrameTime.GetSeconds());
  1686.                 m_pTimeDemoInfo->pFrames[m_currentFrame].nPolysRendered = nPolygons;
  1687.                 m_pTimeDemoInfo->pFrames[m_currentFrame].nDrawCalls = gEnv->pRenderer->GetCurrentNumberOfDrawCalls();
  1688.         }
  1689.         //////////////////////////////////////////////////////////////////////////
  1690.         m_lastFrameTime = GetTime();
  1691.  
  1692.         //////////////////////////////////////////////////////////////////////////
  1693.         //override game time of day
  1694.         //////////////////////////////////////////////////////////////////////////
  1695.         if (0 <= m_demo_time_of_day)
  1696.         {
  1697.                 //force update if time is significantly different from current time
  1698.                 float fTime = gEnv->p3DEngine->GetTimeOfDay()->GetTime();
  1699.                 const float cfSmallDeltaTime = 0.1f;
  1700.  
  1701.                 if ((fTime > m_demo_time_of_day + cfSmallDeltaTime) ||
  1702.                     (fTime < m_demo_time_of_day - cfSmallDeltaTime))
  1703.                 {
  1704.                         gEnv->p3DEngine->GetTimeOfDay()->SetTime((float)m_demo_time_of_day, true);
  1705.                         SetConsoleVar("e_TimeOfDaySpeed", 0);
  1706.                 }
  1707.         }
  1708.         //////////////////////////////////////////////////////////////////////////
  1709.  
  1710.         //////////////////////////////////////////////////////////////////////////
  1711.         if ((m_numLoops == 0) &&
  1712.             ((m_demo_screenshot_frame && m_currentFrame == m_demo_screenshot_frame) ||
  1713.              (m_demo_screenshot_frame < 0) && (m_currentFrame % abs(m_demo_screenshot_frame) == 0)))
  1714.         {
  1715.                 gEnv->pRenderer->ScreenShot();
  1716.         }
  1717.         //////////////////////////////////////////////////////////////////////////
  1718.  
  1719.         ReplayGameState(rec);
  1720.  
  1721.         m_currentFrame++;
  1722.         // Play looped.
  1723.         if (m_currentFrame >= GetNumberOfFrames() || m_currentFrame > m_demo_max_frames)
  1724.         {
  1725.                 return false;
  1726.         }
  1727.  
  1728.         SignalPlayFrame();
  1729.         return true;
  1730. }
  1731.  
  1732. //////////////////////////////////////////////////////////////////////////
  1733. CTimeValue CTimeDemoRecorder::GetTime()
  1734. {
  1735.         // Must be asynchronius time, used for profiling.
  1736.         return gEnv->pTimer->GetAsyncTime();
  1737. }
  1738.  
  1739. //////////////////////////////////////////////////////////////////////////
  1740. int CTimeDemoRecorder::GetNumFrames() const
  1741. {
  1742.         return m_records.size();
  1743. }
  1744.  
  1745. //////////////////////////////////////////////////////////////////////////
  1746. float CTimeDemoRecorder::GetAverageFrameRate() const
  1747. {
  1748.         if (m_currentFrame)
  1749.         {
  1750.                 float aveFrameTime = m_totalDemoTime.GetSeconds() / m_currentFrame;
  1751.                 float aveFrameRate = 1.0f / aveFrameTime;
  1752.                 return aveFrameRate;
  1753.         }
  1754.         return 0.0f;
  1755. }
  1756.  
  1757. //////////////////////////////////////////////////////////////////////////
  1758. float CTimeDemoRecorder::RenderInfo(float y)
  1759. {
  1760.         float retY = 0;
  1761.  
  1762.         if (m_demo_noinfo != 0)
  1763.                 return retY;
  1764.  
  1765.         const char* sInfo = m_bPaused ? " (Paused)" : "";
  1766.  
  1767.         if (m_bRecording)
  1768.         {
  1769.                 // TO DO
  1770.                 float fColor[4] = { 0.7f, 0, 0, 1 };
  1771.                 IRenderAuxText::Draw2dLabel(1, y, 1.3f, fColor, false, "Recording AutoTest%s", sInfo);
  1772.         }
  1773.         else if (m_bPlaying)
  1774.         {
  1775.                 float fColor[4] = { 0, 0.7f, 0, 1 };
  1776.                 IRenderAuxText::Draw2dLabel(1, y, 1.3f, fColor, false, "Playing AutoTest%s - Loop %d of %d, Orientation %d of %d", sInfo, (m_numLoops / m_numOrientations) + 1, m_maxLoops, (m_numLoops % m_numOrientations) + 1, m_numOrientations);
  1777.         }
  1778.  
  1779.         y += 15;
  1780.  
  1781.         if (m_bRecording)
  1782.         {
  1783.                 float fColor[4] = { 1, 0, 0, 1 };
  1784.                 IRenderAuxText::Draw2dLabel(1, y + retY, 1.3f, fColor, false, "TimeDemo%s, Frames: %d", sInfo, m_currentFrame);
  1785.                 retY += 15;
  1786.         }
  1787.         else if (m_bPlaying)
  1788.         {
  1789.                 int numFrames = GetNumFrames();
  1790.                 float fColor[4] = { 0, 1, 0, 1 };
  1791.                 IRenderAuxText::Draw2dLabel(1, y + retY, 1.3f, fColor, false, "TimeDemo%s, Frame %d of %d", sInfo, m_currentFrame, numFrames);
  1792.                 retY += 15;
  1793.  
  1794.                 float aveFrameRate = GetAverageFrameRate();
  1795.                 //float aveFrameRate = m_currentFrame > m_minFPSCounter ? m_sumFPS/(m_currentFrame - m_minFPSCounter) : 0;
  1796.                 //float aveFrameRate = m_sumFPS/(m_currentFrame +1);
  1797.                 float polyRatio = m_nTotalPolysPlayed ? (float)m_nTotalPolysRecorded / m_nTotalPolysPlayed : 0.0f;
  1798.                 //int numFrames = GetNumFrames();
  1799.  
  1800.                 IRenderAuxText::Draw2dLabel(1, y + retY, 1.3f, fColor, false, "TestProfiler%s, Frame %d", sInfo, m_currentFrame);
  1801.                 retY += 15;
  1802.                 IRenderAuxText::Draw2dLabel(1, y + retY, 1.3f, fColor, false, " Last Played Length: %.2fs, FPS: %.2f", m_lastPlayedTotalTime, m_lastAveFrameRate);
  1803.                 retY += 15;
  1804.                 IRenderAuxText::Draw2dLabel(1, y + retY, 1.3f, fColor, false, " Average FPS: %.2f, FPS: %.2f, Polys/Frame: %d", aveFrameRate, m_currFPS, m_nCurrPolys);
  1805.                 retY += 15;
  1806.  
  1807.                 IRenderAuxText::Draw2dLabel(1, y + retY, 1.3f, fColor, false, " Polys Rec/Play Ratio: %.2f", polyRatio);
  1808.                 retY += 15;
  1809.         }
  1810.  
  1811.         if (!m_bPaused && m_demo_gameState && m_fileVersion >= TIMEDEMO_FILE_VERSION_4)
  1812.         {
  1813.                 IGameStateRecorder* pGameStateRecorder = gEnv->pGameFramework->GetIGameplayRecorder()->GetIGameStateRecorder();
  1814.                 if (pGameStateRecorder)
  1815.                         retY += pGameStateRecorder->RenderInfo(y + retY, m_bRecording);
  1816.         }
  1817.  
  1818.         return retY;
  1819. }
  1820.  
  1821. //////////////////////////////////////////////////////////////////////////
  1822. void CTimeDemoRecorder::SetConsoleVar(const char* sVarName, float value)
  1823. {
  1824.         ICVar* pVar = gEnv->pConsole->GetCVar(sVarName);
  1825.         if (pVar)
  1826.                 pVar->Set(value);
  1827. }
  1828.  
  1829. //////////////////////////////////////////////////////////////////////////
  1830. float CTimeDemoRecorder::GetConsoleVar(const char* sVarName)
  1831. {
  1832.         ICVar* pVar = gEnv->pConsole->GetCVar(sVarName);
  1833.         if (pVar)
  1834.                 return pVar->GetFVal();
  1835.         return 0;
  1836. }
  1837.  
  1838. //////////////////////////////////////////////////////////////////////////
  1839. void CTimeDemoRecorder::StartSession()
  1840. {
  1841.         Pause(false);
  1842.  
  1843.         bool bCurrentlyRecording = m_bRecording;
  1844.         m_bRecording = false;
  1845.         if (m_demo_restart_level == 1 && bCurrentlyRecording)
  1846.         {
  1847.                 //QS does not work when playing/recording a timedemo, so pretend we're not...
  1848.                 // Quick save at the begining of the recording, so we restore initial state as good as possible.
  1849.                 CCryAction::GetCryAction()->SaveGame(GetInitSaveFileName(), true, true, eSGR_QuickSave, true);
  1850.         }
  1851.  
  1852.         ResetSessionLoop();
  1853.         m_bRecording = bCurrentlyRecording;
  1854.  
  1855.         m_nTotalPolysPlayed = 0;
  1856.         m_nTotalPolysRecorded = 0;
  1857.  
  1858.         //////////////////////////////////////////////////////////////////////////
  1859.         if (m_bRecording && m_bAIEnabled)
  1860.         {
  1861.                 SaveAllEntitiesState();
  1862.         }
  1863.         //////////////////////////////////////////////////////////////////////////
  1864.  
  1865.         if (gEnv->pMovieSystem)
  1866.                 gEnv->pMovieSystem->StopAllCutScenes();
  1867.  
  1868.         if (m_demo_ai == 0)
  1869.         {
  1870.                 SetConsoleVar("ai_SystemUpdate", 0);
  1871.                 SetConsoleVar("ai_IgnorePlayer", 1);
  1872.                 SetConsoleVar("ai_SoundPerception", 0);
  1873.         }
  1874.         else
  1875.         {
  1876.                 SetConsoleVar("ai_UseCalculationStopperCounter", 1);  // To make AI async time independent.
  1877.         }
  1878.  
  1879.         // No wait for key-press on level load.
  1880.         SetConsoleVar("hud_startPaused", 0);
  1881.         // Not cut-scenes
  1882.         SetConsoleVar("mov_NoCutscenes", 1);
  1883.  
  1884.         // cache console vars - changing them runtime has no effect
  1885.         m_bAIEnabled = m_demo_ai > 0;
  1886.  
  1887.         m_prevGodMode = (int)GetConsoleVar("g_godMode");
  1888.  
  1889.         if (m_demo_gameState && m_fileVersion >= TIMEDEMO_FILE_VERSION_4)
  1890.                 gEnv->pGameFramework->GetIGameplayRecorder()->EnableGameStateRecorder(true, this, m_bRecording);
  1891.  
  1892.         if (m_bPlaying)
  1893.         {
  1894.                 IActor* pClientActor = gEnv->pGameFramework->GetClientActor();
  1895.                 if (pClientActor)
  1896.                 {
  1897.                         pClientActor->EnableTimeDemo(true);
  1898.                 }
  1899.         }
  1900.  
  1901.         if (!m_pTimeDemoInfo)
  1902.         {
  1903.                 m_pTimeDemoInfo = new STimeDemoInfo();
  1904.                 m_pTimeDemoInfo->pFrames = 0;
  1905.         }
  1906.  
  1907.         int size = GetNumberOfFrames();
  1908.         if (m_pTimeDemoInfo && m_pTimeDemoInfo->nFrameCount != size)
  1909.         {
  1910.                 delete[]m_pTimeDemoInfo->pFrames;
  1911.                 STimeDemoInfo* pTD = m_pTimeDemoInfo;
  1912.                 pTD->nFrameCount = size;
  1913.                 pTD->pFrames = new STimeDemoFrameInfo[pTD->nFrameCount];
  1914.         }
  1915.  
  1916.         //////////////////////////////////////////////////////////////////////////
  1917.         // Force player out of the vehicle on start.
  1918.         //////////////////////////////////////////////////////////////////////////
  1919.         // Luc TO DO: remove this
  1920.         gEnv->pConsole->ExecuteString("v_exit_player");
  1921.  
  1922.         m_lastAveFrameRate = 0;
  1923.         m_lastPlayedTotalTime = 0;
  1924.         m_totalDemoTime.SetMilliSeconds(0);
  1925.  
  1926.         // Register to frame profiler.
  1927.  
  1928.         // remember old profiling settings
  1929.         m_bEnabledProfiling = gEnv->pFrameProfileSystem->IsEnabled();
  1930.         m_bVisibleProfiling = gEnv->pFrameProfileSystem->IsVisible();
  1931.  
  1932.         if (m_demo_profile)
  1933.         {
  1934.                 gEnv->pFrameProfileSystem->Enable(true, gEnv->pFrameProfileSystem->IsVisible());
  1935.         }
  1936.         gEnv->pFrameProfileSystem->AddPeaksListener(this);
  1937.  
  1938.         // Profile
  1939.         m_oldPeakTolerance = GetConsoleVar("profile_peak");
  1940.         SetConsoleVar("profile_peak", 50);
  1941.  
  1942.         m_fixedTimeStep = GetConsoleVar("t_FixedStep");
  1943.         if (m_demo_fixed_timestep > 0)
  1944.                 SetConsoleVar("t_FixedStep", 1.0f / (float)m_demo_fixed_timestep);
  1945.  
  1946.         if (m_demo_vtune)
  1947.                 GetISystem()->GetIProfilingSystem()->VTuneResume();
  1948.  
  1949.         m_lastFrameTime = GetTime();
  1950. }
  1951.  
  1952. //////////////////////////////////////////////////////////////////////////
  1953. void CTimeDemoRecorder::StopSession()
  1954. {
  1955.         if (m_demo_vtune)
  1956.         {
  1957.                 GetISystem()->GetIProfilingSystem()->VTunePause();
  1958.         }
  1959.  
  1960.         // Set old time step.
  1961.         SetConsoleVar("t_FixedStep", m_fixedTimeStep);
  1962.  
  1963.         if (m_demo_ai == 0)
  1964.         {
  1965.                 SetConsoleVar("ai_SystemUpdate", 1);
  1966.                 SetConsoleVar("ai_IgnorePlayer", 0);
  1967.                 SetConsoleVar("ai_SoundPerception", 1);
  1968.         }
  1969.         else
  1970.         {
  1971.                 SetConsoleVar("ai_UseCalculationStopperCounter", 0);  // To make AI async time independent.
  1972.         }
  1973.         SetConsoleVar("mov_NoCutscenes", 0);
  1974.  
  1975.         IActor* pClientActor = gEnv->pGameFramework->GetClientActor();
  1976.         if (pClientActor)
  1977.                 pClientActor->EnableTimeDemo(false);
  1978.  
  1979.         gEnv->pGameFramework->GetIGameplayRecorder()->EnableGameStateRecorder(false, this, false);
  1980.  
  1981.         // Profile.
  1982.         SetConsoleVar("profile_peak", m_oldPeakTolerance);
  1983.         gEnv->pFrameProfileSystem->RemovePeaksListener(this);
  1984.  
  1985.         if (m_demo_profile)
  1986.         {
  1987.                 gEnv->pFrameProfileSystem->Enable(m_bEnabledProfiling, m_bVisibleProfiling);
  1988.         }
  1989.         m_lastPlayedTotalTime = m_totalDemoTime.GetSeconds();
  1990. }
  1991.  
  1992. //////////////////////////////////////////////////////////////////////////
  1993. void CTimeDemoRecorder::ResetSessionLoop()
  1994. {
  1995.         if (m_demo_restart_level != 0 && m_bPlaying)
  1996.         {
  1997.                 switch (m_demo_restart_level)
  1998.                 {
  1999.                 case 1:
  2000.                         // Quick load at the begining of the playback, so we restore initial state as good as possible.
  2001.                         if (gEnv->pGameFramework)
  2002.                                 gEnv->pGameFramework->LoadGame(GetInitSaveFileName());//, true, true);
  2003.  
  2004.                         break;
  2005.  
  2006.                 case 2:
  2007.                 default:
  2008.                         //load save made at start of level
  2009.                         CCryAction::GetCryAction()->LoadGame(CCryAction::GetCryAction()->GetStartLevelSaveGameName());//, true);
  2010.                         break;
  2011.                 }
  2012.  
  2013.         }
  2014.         // Reset random number generators seed.
  2015.         GetISystem()->GetRandomGenerator().Seed(0);
  2016.  
  2017.         m_totalDemoTime.SetMilliSeconds(0);
  2018.         m_currentFrame = 0;
  2019.  
  2020.         if (gEnv->pStatoscope)
  2021.         {
  2022.                 CryStackStringT<char, 64> loopStr;
  2023.                 loopStr.Format("Loop %d Orientation %d", m_numLoops / m_numOrientations, m_numLoops % m_numOrientations);
  2024.                 gEnv->pStatoscope->AddUserMarker("TimeDemo", loopStr.c_str());
  2025.         }
  2026. }
  2027.  
  2028. //////////////////////////////////////////////////////////////////////////
  2029. void CTimeDemoRecorder::EraseLogFile()
  2030. {
  2031.         string filename = PathUtil::Make("%USER%/TestResults", PathUtil::ReplaceExtension(CTimeDemoRecorder::s_timedemo_file->GetString(), "log"));
  2032.         gEnv->pCryPak->RemoveFile(filename);
  2033.         gEnv->pCryPak->RemoveFile("./AutoTestFinished.log");
  2034. }
  2035.  
  2036. //////////////////////////////////////////////////////////////////////////
  2037. void CTimeDemoRecorder::LogInfo(const char* format, ...)
  2038. {
  2039.         CDebugAllowFileAccess ignoreInvalidFileAccess;
  2040.  
  2041.         va_list ArgList;
  2042.         char szBuffer[1024];
  2043.  
  2044.         va_start(ArgList, format);
  2045.         cry_vsprintf(szBuffer, format, ArgList);
  2046.         va_end(ArgList);
  2047.  
  2048.         va_start(ArgList, format);
  2049.         gEnv->pLog->LogV(IMiniLog::eMessage, format, ArgList);
  2050.         va_end(ArgList);
  2051.  
  2052.         gEnv->pLog->Log("%s", szBuffer);
  2053.  
  2054.         string filename = PathUtil::Make("%USER%/TestResults", PathUtil::ReplaceExtension(CTimeDemoRecorder::s_timedemo_file->GetString(), "log"));
  2055.         FILE* hFile = fxopen(filename.c_str(), "at");
  2056.         if (hFile)
  2057.         {
  2058.                 // Write the string to the file and close it
  2059.                 fprintf(hFile, "%s\n", szBuffer);
  2060.                 fclose(hFile);
  2061.         }
  2062. }
  2063.  
  2064. //////////////////////////////////////////////////////////////////////////
  2065. bool CTimeDemoRecorder::OnInputEvent(const SInputEvent& event)
  2066. {
  2067.         if ((event.deviceType == eIDT_Keyboard) && event.keyId == eKI_Tilde)
  2068.         {
  2069.                 return false;
  2070.         }
  2071.         if (event.deviceType != eIDT_Unknown)
  2072.         {
  2073.                 m_currentFrameInputEvents.push_back(event);
  2074.         }
  2075.         return false;
  2076. }
  2077.  
  2078. //////////////////////////////////////////////////////////////////////////
  2079. void CTimeDemoRecorder::LogEndOfLoop()
  2080. {
  2081.         m_lastPlayedTotalTime = m_totalDemoTime.GetSeconds();
  2082.         m_lastAveFrameRate = GetAverageFrameRate();
  2083.  
  2084.         if (m_pTimeDemoInfo)
  2085.         {
  2086.                 STimeDemoInfo* pTD = m_pTimeDemoInfo;
  2087.                 pTD->lastPlayedTotalTime = m_lastPlayedTotalTime;
  2088.                 pTD->lastAveFrameRate = m_lastAveFrameRate;
  2089.                 pTD->minFPS = m_minFPS;
  2090.                 pTD->maxFPS = m_maxFPS;
  2091.                 pTD->minFPS_Frame = m_minFPS_Frame;
  2092.                 pTD->maxFPS_Frame = m_maxFPS_Frame;
  2093.                 pTD->nTotalPolysRecorded = m_nTotalPolysRecorded;
  2094.                 pTD->nTotalPolysPlayed = m_nTotalPolysPlayed;
  2095.                 GetISystem()->GetITestSystem()->SetTimeDemoInfo(m_pTimeDemoInfo);
  2096.         }
  2097.  
  2098.         int numFrames = GetNumberOfFrames();//m_records.size();
  2099.         LogInfo(" Run Finished.");
  2100.         LogInfo("    Play Time: %.2fs, Average FPS: %.2f", m_lastPlayedTotalTime, m_lastAveFrameRate);
  2101.         LogInfo("    Min FPS: %.2f at frame %d, Max FPS: %.2f at frame %d", m_minFPS, m_minFPS_Frame, m_maxFPS, m_maxFPS_Frame);
  2102.         if (m_lastPlayedTotalTime * (float)numFrames > 0.f)
  2103.                 LogInfo("    Average Tri/Sec: %d, Tri/Frame: %d", (int)(m_nTotalPolysPlayed / m_lastPlayedTotalTime), m_nTotalPolysPlayed / numFrames);
  2104.         if (m_nTotalPolysPlayed)
  2105.                 LogInfo("    Recorded/Played Tris ratio: %.2f", (float)m_nTotalPolysRecorded / m_nTotalPolysPlayed);
  2106.  
  2107.         IMemoryManager::SProcessMemInfo meminfo;
  2108.         if (GetISystem()->GetIMemoryManager()->GetProcessMemInfo(meminfo))
  2109.         {
  2110.                 int MB = 1024 * 1024;
  2111.                 LogInfo("    Memory Usage: WorkingSet=%" PRIu64 "Mb, PageFile=%" PRIu64 "Mb, PageFaults=%" PRIu64, meminfo.WorkingSetSize / MB, meminfo.PagefileUsage / MB, meminfo.PageFaultCount);
  2112.         }
  2113. }
  2114.  
  2115. void CTimeDemoRecorder::GetMemoryStatistics(ICrySizer* s) const
  2116. {
  2117.         SIZER_SUBCOMPONENT_NAME(s, "TimeDemoRecorder");
  2118.         s->Add(*this);
  2119.         s->AddObject(m_records);
  2120.         s->AddObject(m_currentFrameInputEvents);
  2121.         s->AddObject(m_currentFrameEntityEvents);
  2122.         s->AddObject(m_currentFrameGameEvents);
  2123. }
  2124.  
  2125. bool CTimeDemoRecorder::OnBeforeSpawn(SEntitySpawnParams& params)
  2126. {
  2127.         return true;
  2128. }
  2129.  
  2130. //////////////////////////////////////////////////////////////////////////
  2131. void CTimeDemoRecorder::OnSpawn(IEntity* pEntity, SEntitySpawnParams& params)
  2132. {
  2133. }
  2134.  
  2135. //////////////////////////////////////////////////////////////////////////
  2136. bool CTimeDemoRecorder::OnRemove(IEntity* pEntity)
  2137. {
  2138.         return true;
  2139. }
  2140.  
  2141. //////////////////////////////////////////////////////////////////////////
  2142. void CTimeDemoRecorder::OnReused(IEntity* pEntity, SEntitySpawnParams& params)
  2143. {
  2144. }
  2145.  
  2146. //////////////////////////////////////////////////////////////////////////
  2147. void CTimeDemoRecorder::OnEvent(IEntity* pEntity, SEntityEvent& event)
  2148. {
  2149.         if (m_bRecording)
  2150.         {
  2151.                 // Record entity event for this frame.
  2152.                 EntityGUID guid = pEntity->GetGuid();
  2153.                 if (!guid)
  2154.                         return;
  2155.  
  2156.                 // Record entity event for this frame.
  2157.                 switch (event.event)
  2158.                 {
  2159.                 // Events to save.
  2160.                 case ENTITY_EVENT_XFORM:
  2161.                 case ENTITY_EVENT_HIDE:
  2162.                 case ENTITY_EVENT_UNHIDE:
  2163.                 case ENTITY_EVENT_ATTACH:
  2164.                 case ENTITY_EVENT_DETACH:
  2165.                 case ENTITY_EVENT_DETACH_THIS:
  2166.                 case ENTITY_EVENT_ENABLE_PHYSICS:
  2167.                 case ENTITY_EVENT_ENTER_SCRIPT_STATE:
  2168.                         {
  2169.                                 EntityEventRecord rec;
  2170.                                 memset(&rec, 0, sizeof(rec));
  2171.                                 rec.entityId = pEntity->GetId();
  2172.                                 rec.guid = guid;
  2173.                                 rec.eventType = event.event;
  2174.                                 rec.nParam[0] = event.nParam[0];
  2175.                                 rec.nParam[1] = event.nParam[1];
  2176.                                 rec.nParam[2] = event.nParam[2];
  2177.                                 rec.nParam[3] = event.nParam[3];
  2178.                                 rec.pos = pEntity->GetPos();
  2179.                                 rec.q = pEntity->GetRotation();
  2180.                                 m_currentFrameEntityEvents.push_back(rec);
  2181.                         }
  2182.                         break;
  2183.  
  2184.                 // Skip all other events.
  2185.                 default:
  2186.                         break;
  2187.                 }
  2188.         }
  2189. }
  2190.  
  2191. //////////////////////////////////////////////////////////////////////////
  2192. void CTimeDemoRecorder::PlayBackEntityEvent(const EntityEventRecord& rec)
  2193. {
  2194.         EntityId entityId = gEnv->pEntitySystem->FindEntityByGuid(rec.guid);
  2195.         IEntity* pEntity = gEnv->pEntitySystem->GetEntity(entityId);
  2196.         if (!pEntity)
  2197.                 return;
  2198.  
  2199.         switch (rec.eventType)
  2200.         {
  2201.         // Events to save.
  2202.         case ENTITY_EVENT_XFORM:
  2203.                 pEntity->SetPosRotScale(rec.pos, rec.q, pEntity->GetScale(), ENTITY_XFORM_TIMEDEMO);
  2204.                 break;
  2205.         case ENTITY_EVENT_HIDE:
  2206.                 pEntity->Hide(true);
  2207.                 break;
  2208.         case ENTITY_EVENT_UNHIDE:
  2209.                 pEntity->Hide(false);
  2210.                 break;
  2211.         case ENTITY_EVENT_ATTACH:
  2212.                 {
  2213.                         IEntity* pChild = (IEntity*)gEnv->pEntitySystem->GetEntity((EntityId)rec.nParam[0]); // Get Child entity.
  2214.                         if (pChild)
  2215.                                 pEntity->AttachChild(pChild);
  2216.                 }
  2217.                 break;
  2218.         case ENTITY_EVENT_DETACH:
  2219.                 break;
  2220.         case ENTITY_EVENT_DETACH_THIS:
  2221.                 pEntity->DetachThis(0, ENTITY_XFORM_TIMEDEMO);
  2222.                 break;
  2223.         case ENTITY_EVENT_ENABLE_PHYSICS:
  2224.                 if (rec.nParam[0] == 0)
  2225.                         pEntity->EnablePhysics(false);
  2226.                 else
  2227.                         pEntity->EnablePhysics(true);
  2228.                 break;
  2229.         case ENTITY_EVENT_ENTER_SCRIPT_STATE:
  2230.                 {
  2231.                         IEntityScriptComponent* pScriptProxy = (IEntityScriptComponent*)pEntity->GetProxy(ENTITY_PROXY_SCRIPT);
  2232.                         if (pScriptProxy)
  2233.                         {
  2234.                                 pScriptProxy->GotoStateId((int)rec.nParam[0]);
  2235.                         }
  2236.                 }
  2237.                 break;
  2238.         }
  2239. }
  2240.  
  2241. //////////////////////////////////////////////////////////////////////////
  2242. void CTimeDemoRecorder::SaveAllEntitiesState()
  2243. {
  2244.         m_firstFrameEntityState.clear();
  2245.         // Record all objects positions.
  2246.         IEntity* pEntity;
  2247.         IEntityItPtr pEntityIter = gEnv->pEntitySystem->GetEntityIterator();
  2248.         while (pEntity = pEntityIter->Next())
  2249.         {
  2250.                 EntityGUID guid = pEntity->GetGuid();
  2251.                 if (guid)
  2252.                 {
  2253.                         EntityEventRecord rec;
  2254.                         memset(&rec, 0, sizeof(rec));
  2255.                         rec.entityId = pEntity->GetId();
  2256.                         rec.guid = guid;
  2257.                         rec.eventType = ENTITY_EVENT_RESET;
  2258.                         rec.pos = pEntity->GetPos();
  2259.                         rec.q = pEntity->GetRotation();
  2260.                         rec.flags |= (pEntity->IsHidden()) ? EntityEventRecord::HIDDEN : 0;
  2261.                         m_firstFrameEntityState.push_back(rec);
  2262.                 }
  2263.         }
  2264. }
  2265.  
  2266. //////////////////////////////////////////////////////////////////////////
  2267. void CTimeDemoRecorder::RestoreAllEntitiesState()
  2268. {
  2269.         for (int i = 0; i < m_firstFrameEntityState.size(); i++)
  2270.         {
  2271.                 EntityEventRecord& rec = m_firstFrameEntityState[i];
  2272.                 if (rec.eventType == ENTITY_EVENT_RESET)
  2273.                 {
  2274.                         EntityId entityId = gEnv->pEntitySystem->FindEntityByGuid(rec.guid);
  2275.                         IEntity* pEntity = gEnv->pEntitySystem->GetEntity(entityId);
  2276.                         if (!pEntity)
  2277.                                 continue;
  2278.  
  2279.                         pEntity->Hide((rec.flags & EntityEventRecord::HIDDEN) != 0);
  2280.                         pEntity->SetPosRotScale(rec.pos, rec.q, pEntity->GetScale(), ENTITY_XFORM_TIMEDEMO);
  2281.                 }
  2282.         }
  2283.  
  2284. }
  2285.  
  2286. ///////////////////////////////////////////////////////////////////////////////
  2287. void CTimeDemoRecorder::ParseParams(XmlNodeRef baseNode)
  2288. {
  2289.  
  2290. }
  2291.  
  2292. ///////////////////////////////////////////////////////////////////////////////
  2293. void CTimeDemoRecorder::SetVariable(const char* name, const char* szValue)
  2294. {
  2295.  
  2296. }
  2297.  
  2298. ///////////////////////////////////////////////////////////////////////////////
  2299. void CTimeDemoRecorder::SetVariable(const char* name, float value)
  2300. {
  2301.  
  2302. }
  2303.  
  2304. ///////////////////////////////////////////////////////////////////////////////
  2305. int CTimeDemoRecorder::GetNumberOfFrames()
  2306. {
  2307.         return m_records.size();
  2308. }
  2309.  
  2310. ///////////////////////////////////////////////////////////////////////////////
  2311. void CTimeDemoRecorder::OnGameplayEvent(IEntity* pEntity, const GameplayEvent& event)
  2312. {
  2313.         if (IsRecording())
  2314.         {
  2315.                 STimeDemoGameEvent ge(pEntity, event);
  2316.                 m_currentFrameGameEvents.push_back(ge);
  2317.         }
  2318. }
  2319.  
  2320. //////////////////////////////////////////////////////////////////////////
  2321. void CTimeDemoRecorder::OnFrameProfilerPeak(CFrameProfiler* pProfiler, float fPeakTime)
  2322. {
  2323.         if (m_bPlaying && !m_bPaused)
  2324.         {
  2325.                 LogInfo("    -Peak at Frame %d, %.2fms : %s (count: %d)", m_currentFrame, fPeakTime, pProfiler->m_name, pProfiler->m_count);
  2326.         }
  2327. }
  2328.  
  2329. //////////////////////////////////////////////////////////////////////////
  2330. int CTimeDemoRecorder::ComputePolyCount()
  2331. {
  2332.         int nPolygons, nShadowVolPolys;
  2333.         gEnv->pRenderer->GetPolyCount(nPolygons, nShadowVolPolys);
  2334.         m_nPolysCounter += nPolygons;
  2335.         m_nCurrPolys = nPolygons;
  2336.         if (nPolygons > m_nMaxPolys)
  2337.                 m_nMaxPolys = nPolygons;
  2338.         if (nPolygons < m_nMinPolys)
  2339.                 m_nMinPolys = nPolygons;
  2340.         return nPolygons;
  2341. }
  2342.  
  2343. //////////////////////////////////////////////////////////////////////////
  2344. void CTimeDemoRecorder::StartChainDemo(const char* levelsListFilename, bool bAutoLoadChainConfig)
  2345. {
  2346.         if (bAutoLoadChainConfig)
  2347.         {
  2348.                 gEnv->pConsole->ExecuteString("exec AutoTestChain.cfg");
  2349.         }
  2350.         m_bChainloadingDemo = true;
  2351.         EraseLogFile();
  2352.         m_demoLevels.clear();
  2353.         if (levelsListFilename && *levelsListFilename)
  2354.         {
  2355.                 // Open file with list of levels for autotest.
  2356.                 // This is used only for development so doesn`t need to use CryPak!
  2357.                 FILE* f = fxopen(levelsListFilename, "rt");
  2358.                 if (f)
  2359.                 {
  2360.                         while (!feof(f))
  2361.                         {
  2362.                                 char str[512];
  2363.                                 if (fgets(str, sizeof(str), f))
  2364.                                 {
  2365.                                         string level = str;
  2366.                                         level.Trim();
  2367.                                         if (level.size())
  2368.                                         {
  2369.                                                 SChainDemoLevel lvl;
  2370.                                                 lvl.level = level;
  2371.                                                 lvl.time = 0;
  2372.                                                 lvl.bSuccess = false;
  2373.                                                 lvl.bRun = false;
  2374.                                                 m_demoLevels.push_back(lvl);
  2375.                                         }
  2376.                                 }
  2377.                         }
  2378.                         fclose(f);
  2379.                 }
  2380.                 else
  2381.                 {
  2382.                         CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_ERROR, "Failed to find chainload file: %s", levelsListFilename);
  2383.                 }
  2384.         }
  2385.  
  2386.         if (!m_demoLevels.empty())
  2387.         {
  2388.                 if (IsRecording())
  2389.                         Record(false);
  2390.                 else if (IsPlaying())
  2391.                         Play(false);
  2392.  
  2393.                 m_nCurrentDemoLevel = 0;
  2394.                 StartNextChainedLevel();
  2395.         }
  2396.         else
  2397.         {
  2398.                 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_ERROR, "No levels found for chainload in: %s", levelsListFilename);
  2399.         }
  2400. }
  2401.  
  2402. void CTimeDemoRecorder::StartDemoLevel(const char** levelNames, int levelCount)
  2403. {
  2404.         m_bChainloadingDemo = true;
  2405.         EraseLogFile();
  2406.         m_demoLevels.clear();
  2407.  
  2408.         if (levelNames && levelCount > 0)
  2409.         {
  2410.                 for (int i = 0; i < levelCount; ++i)
  2411.                 {
  2412.                         SChainDemoLevel lvl;
  2413.                         lvl.level = levelNames[i];
  2414.                         lvl.time = 0;
  2415.                         lvl.bSuccess = false;
  2416.                         lvl.bRun = false;
  2417.                         m_demoLevels.push_back(lvl);
  2418.                 }
  2419.         }
  2420.  
  2421.         if (!m_demoLevels.empty())
  2422.         {
  2423.                 if (IsRecording())
  2424.                         Record(false);
  2425.                 else if (IsPlaying())
  2426.                         Play(false);
  2427.  
  2428.                 m_nCurrentDemoLevel = 0;
  2429.                 StartNextChainedLevel();
  2430.         }
  2431.         else
  2432.         {
  2433.                 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_ERROR, "demo_StartDemoLevel: No level(s) specified.");
  2434.         }
  2435. }
  2436.  
  2437. //////////////////////////////////////////////////////////////////////////
  2438. void CTimeDemoRecorder::StartNextChainedLevel()
  2439. {
  2440.         if (!m_demoLevels.empty())
  2441.         {
  2442.                 float tcurr = GetISystem()->GetITimer()->GetAsyncTime().GetSeconds();
  2443.                 if (m_nCurrentDemoLevel - 1 >= 0 && m_nCurrentDemoLevel - 1 < m_demoLevels.size())
  2444.                 {
  2445.                         m_demoLevels[m_nCurrentDemoLevel - 1].bSuccess = true;
  2446.                         m_demoLevels[m_nCurrentDemoLevel - 1].bRun = true;
  2447.                         m_demoLevels[m_nCurrentDemoLevel - 1].time = tcurr - m_lastChainDemoTime;
  2448.                 }
  2449.                 m_lastChainDemoTime = tcurr;
  2450.  
  2451.                 SaveChainloadingJUnitResults();
  2452.  
  2453.                 // This support loading level/playing time demo, then loading next level, etc...
  2454.                 if (m_nCurrentDemoLevel < m_demoLevels.size())
  2455.                 {
  2456.                         CryStackStringT<char, 256> mapCmd("map ");
  2457.                         mapCmd += m_demoLevels[m_nCurrentDemoLevel].level;
  2458.                         gEnv->pConsole->ExecuteString(mapCmd);
  2459.                         StartDemoDelayed(50);
  2460.                         m_nCurrentDemoLevel++;
  2461.                         return;
  2462.                 }
  2463.         }
  2464.         ICVar* pFinishCmd = gEnv->pConsole->GetCVar("demo_finish_cmd");
  2465.         if (pFinishCmd)
  2466.         {
  2467.                 const char* const szFinishCmd = pFinishCmd->GetString();
  2468.                 if (szFinishCmd && szFinishCmd[0] != '\0')
  2469.                 {
  2470.                         gEnv->pConsole->ExecuteString(szFinishCmd);
  2471.                 }
  2472.         }
  2473.         if (m_demo_quit)
  2474.         {
  2475.                 // If No more chained levels. quit.
  2476.                 QuitGame();
  2477.         }
  2478.         else if (!m_demoEnded)
  2479.         {
  2480.                 EndDemo();
  2481.         }
  2482. }
  2483.  
  2484. //////////////////////////////////////////////////////////////////////////
  2485. string CTimeDemoRecorder::GetCurrentLevelName()
  2486. {
  2487.         return gEnv->pGameFramework->GetLevelName();
  2488. }
  2489.  
  2490. //////////////////////////////////////////////////////////////////////////
  2491. string CTimeDemoRecorder::GetInitSaveFileName()
  2492. {
  2493.         string level = GetCurrentLevelName();
  2494.         string str = "autotest_init_";
  2495.         str += level;
  2496.         str += CRY_SAVEGAME_FILE_EXT;
  2497.         return str;
  2498. }
  2499.  
  2500. //////////////////////////////////////////////////////////////////////////
  2501. void CTimeDemoRecorder::SaveChainloadingJUnitResults()
  2502. {
  2503.         XmlNodeRef testsuit = GetISystem()->CreateXmlNode("testsuite");
  2504.         testsuit->setAttr("name", "ChainLoading");
  2505.         for (int i = 0; i < (int)m_demoLevels.size(); i++)
  2506.         {
  2507.                 int nSeconds = static_cast<int>(m_demoLevels[i].time);
  2508.                 XmlNodeRef testcase = testsuit->newChild("testcase");
  2509.                 testcase->setAttr("name", m_demoLevels[i].level.c_str());
  2510.                 testcase->setAttr("time", nSeconds);
  2511.                 if (!m_demoLevels[i].bSuccess)
  2512.                 {
  2513.                         XmlNodeRef failure = testcase->newChild("failure");
  2514.                         if (!m_demoLevels[i].bRun)
  2515.                                 failure->setAttr("type", "Not Run");
  2516.                         else
  2517.                                 failure->setAttr("type", "Failed");
  2518.                 }
  2519.         }
  2520.  
  2521.         gEnv->pCryPak->MakeDir("%USER%/TestResults");
  2522.         testsuit->saveToFile("%USER%/TestResults/ChainLoadingJUnit.xml");
  2523. }
  2524.  
  2525. //////////////////////////////////////////////////////////////////////////
  2526. void CTimeDemoRecorder::EndDemo()
  2527. {
  2528.         m_bDemoFinished = true;
  2529.         m_demoEnded = true;
  2530.  
  2531.         if (!gEnv->IsEditor())
  2532.         {
  2533.                 CCryAction::GetCryAction()->EndGameContext();
  2534.         }
  2535.  
  2536. #if CAPTURE_REPLAY_LOG
  2537.         if (m_finish_replaysizer)
  2538.                 CryGetIMemReplay()->AddSizerTree("TimeDemoSizers");
  2539.         if (m_finish_replaystop)
  2540.                 CryGetIMemReplay()->Stop();
  2541. #endif
  2542.  
  2543.         CryLogAlways("Testing Successfully Finished, Quiting...");
  2544. }
  2545.  
  2546. //////////////////////////////////////////////////////////////////////////
  2547. void CTimeDemoRecorder::QuitGame()
  2548. {
  2549.         CryLogAlways("Testing Successfully Finished, Quiting...");
  2550.  
  2551.         m_bDemoFinished = true;
  2552.         GetISystem()->Quit();
  2553. }
  2554.  
  2555. //////////////////////////////////////////////////////////////////////////
  2556. void CTimeDemoRecorder::ProcessKeysInput()
  2557. {
  2558. #if CRY_PLATFORM_WINDOWS
  2559.         if (!gEnv->IsDedicated() && gEnv->pSystem->IsDevMode())
  2560.         {
  2561.                 // Check if special development keys where pressed.
  2562.                 bool bAlt = ((CryGetAsyncKeyState(VK_LMENU) & (1 << 15)) != 0) || (CryGetAsyncKeyState(VK_RMENU) & (1 << 15)) != 0;
  2563.                 bool bCtrl = (CryGetAsyncKeyState(VK_CONTROL) & (1 << 15)) != 0;
  2564.                 bool bShift = (CryGetAsyncKeyState(VK_SHIFT) & (1 << 15)) != 0;
  2565.  
  2566.                 bool bCancel = CryGetAsyncKeyState(VK_CANCEL) & 1;
  2567.                 bool bTimeDemoKey = CryGetAsyncKeyState(VK_SNAPSHOT) & 1;
  2568.  
  2569.                 if (bCancel)
  2570.                 {
  2571.                         if (IsRecording())
  2572.                         {
  2573.                                 // stop all test modules
  2574.                                 Record(false);
  2575.                                 return;
  2576.                         }
  2577.                         // Toggle start/stop of demo recording.
  2578.                         if (IsPlaying())
  2579.                         {
  2580.                                 // Stop playing.
  2581.                                 Play(false);
  2582.                                 return;
  2583.                         }
  2584.                 }
  2585.  
  2586.                 //////////////////////////////////////////////////////////////////////////
  2587.                 // Time demo on/off
  2588.                 //////////////////////////////////////////////////////////////////////////
  2589.                 if ((bCtrl) && bTimeDemoKey)
  2590.                 {
  2591.                         if (!IsRecording())
  2592.                         {
  2593.                                 // Start record.
  2594.                                 Record(true);
  2595.                         }
  2596.                 }
  2597.                 if (bShift && bTimeDemoKey)
  2598.                 {
  2599.                         if (!IsPlaying())
  2600.                         {
  2601.                                 // Load and start playing.
  2602.                                 Play(true);
  2603.                         }
  2604.                 }
  2605.         }
  2606. #endif
  2607.  
  2608.         bool bPaused = false;
  2609.         if (m_bRecording || m_bPlaying)
  2610.         {
  2611.                 bPaused = gEnv->pConsole->IsOpened();
  2612.  
  2613.                 if (!bPaused && m_demo_scroll_pause != 0 && gEnv->pInput)
  2614.                 {
  2615.                         static TKeyName scrollKey("scrolllock");
  2616.                         bPaused = gEnv->pInput->InputState(scrollKey, eIS_Down);
  2617.                 }
  2618.  
  2619.                 if (bPaused != m_bPaused)
  2620.                         Pause(bPaused);
  2621.         }
  2622. }
  2623.  
  2624. //////////////////////////////////////////////////////////////////////////
  2625. void CTimeDemoRecorder::ReplayGameState(FrameRecord& rec)
  2626. {
  2627.         //////////////////////////////////////////////////////////////////////////
  2628.         // Game state
  2629.         IGameStateRecorder* pGameStateRecorder = gEnv->pGameFramework->GetIGameplayRecorder()->GetIGameStateRecorder();
  2630.         if (pGameStateRecorder && m_fileVersion >= TIMEDEMO_FILE_VERSION_4 && m_demo_gameState)
  2631.         {
  2632.                 int n = rec.gameEvents.size();
  2633.                 for (int i = 0; i < n; i++)
  2634.                 {
  2635.                         STimeDemoGameEvent& gameEvent = rec.gameEvents[i];
  2636.                         //IEntity * pEntity = gEnv->pEntitySystem->GetEntity(gameEvent.id);
  2637.                         IEntity* pEntity = gEnv->pEntitySystem->FindEntityByName(gameEvent.entityName);
  2638.                         if (pEntity)
  2639.                         {
  2640.                                 GameplayEvent event;
  2641.                                 event.event = gameEvent.gameEventType;
  2642.                                 event.value = gameEvent.value;
  2643.                                 event.extra = (void*)(EXPAND_PTR)(gameEvent.extra);
  2644.  
  2645.                                 if (gameEvent.description.size())
  2646.                                         event.description = gameEvent.description.c_str();
  2647.  
  2648.                                 if (gameEvent.description2.size())
  2649.                                         event.extra = (void*)gameEvent.description2.c_str();
  2650.  
  2651.                                 pGameStateRecorder->OnRecordedGameplayEvent(pEntity, event, m_currentFrame);
  2652.                         }
  2653.                 }
  2654.         }
  2655. }
  2656.  
  2657. //////////////////////////////////////////////////////////////////////////
  2658. void CTimeDemoRecorder::StartDemoDelayed(int nFrames)
  2659. {
  2660.         EraseLogFile();
  2661.         m_countDownPlay = nFrames;
  2662. }
  2663.  
  2664. //////////////////////////////////////////////////////////////////////////
  2665. void CTimeDemoRecorder::RegisterListener(ITimeDemoListener* pListener)
  2666. {
  2667.         m_listeners.Add(pListener);
  2668. }
  2669.  
  2670. //////////////////////////////////////////////////////////////////////////
  2671. void CTimeDemoRecorder::UnregisterListener(ITimeDemoListener* pListener)
  2672. {
  2673.         m_listeners.Remove(pListener);
  2674. }
  2675.  
  2676. //////////////////////////////////////////////////////////////////////////
  2677. void CTimeDemoRecorder::GetCurrentFrameRecord(STimeDemoFrameRecord& externalRecord) const
  2678. {
  2679.         const FrameRecord& record = m_records[m_currentFrame];
  2680.  
  2681.         externalRecord.playerPosition = record.playerPosition;
  2682.         externalRecord.playerRotation = record.playerRotation;
  2683.         externalRecord.playerViewRotation = record.playerViewRotation;
  2684.         externalRecord.hmdPositionOffset = record.hmdPositionOffset;
  2685.         externalRecord.hmdViewRotation = record.hmdViewRotation;
  2686. }
  2687.  
  2688. //////////////////////////////////////////////////////////////////////////
  2689. void CTimeDemoRecorder::SignalPlayback(bool bEnable)
  2690. {
  2691.         for (TTimeDemoListeners::Notifier notifier(m_listeners); notifier.IsValid(); notifier.Next())
  2692.         {
  2693.                 notifier->OnPlayback(bEnable);
  2694.         }
  2695. }
  2696.  
  2697. //////////////////////////////////////////////////////////////////////////
  2698. void CTimeDemoRecorder::SignalRecording(bool bEnable)
  2699. {
  2700.         for (TTimeDemoListeners::Notifier notifier(m_listeners); notifier.IsValid(); notifier.Next())
  2701.         {
  2702.                 notifier->OnRecord(bEnable);
  2703.         }
  2704. }
  2705.  
  2706. //////////////////////////////////////////////////////////////////////////
  2707. void CTimeDemoRecorder::SignalPlayFrame()
  2708. {
  2709.         for (TTimeDemoListeners::Notifier notifier(m_listeners); notifier.IsValid(); notifier.Next())
  2710.         {
  2711.                 notifier->OnPlayFrame();
  2712.         }
  2713. }
  2714.  
downloadTimeDemoRecorder.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top