Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

273 lines
7.0 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "serverdemo_system.h"
  8. #include "serverdemo_types.h"
  9. #include "vstdlib/IKeyValuesSystem.h"
  10. #include "tier1/circularbuffer.h"
  11. #include "toolutils/enginetools_int.h"
  12. #include "toolframework/itoolframework.h"
  13. #include "toolframework/iserverenginetools.h"
  14. #include "serverdemo.h"
  15. //------------------------------------------------------------------------------------------------------------------------
  16. bool g_bAllowServerDemoWrite = true;
  17. //------------------------------------------------------------------------------------------------------------------------
  18. ConVar sv_demo_entity_record_rate( "sv_demo_entity_record_rate", "30", FCVAR_GAMEDLL | FCVAR_SPONLY | FCVAR_CHEAT, "Set the server demo record rate for entities." );
  19. //------------------------------------------------------------------------------------------------------------------------
  20. class CServerDemoSystem : public IServerDemoSystem // Implementation
  21. {
  22. public:
  23. CServerDemoSystem();
  24. bool Init();
  25. void Shutdown();
  26. virtual void WriteDemoToDiskForClient( int iClient, char const* pFilename );
  27. virtual void PostRecordingMessage( KeyValues* pMsg );
  28. virtual void Think();
  29. virtual void OnInitLevel( char const* pMapName );
  30. virtual void OnShutdownLevel();
  31. bool CreateDemo( char const* pMapName );
  32. void FreeDemo();
  33. CServerDemo* m_pDemo;
  34. float m_flLastEntRecordTime;
  35. int m_nLastRecordSecond;
  36. int m_nFrameCount;
  37. };
  38. //------------------------------------------------------------------------------------------------------------------------
  39. CServerDemoSystem::CServerDemoSystem()
  40. {
  41. Init();
  42. }
  43. bool CServerDemoSystem::Init()
  44. {
  45. m_pDemo = NULL;
  46. m_flLastEntRecordTime = 0.0f;
  47. m_nFrameCount = 0;
  48. m_nLastRecordSecond = 0;
  49. return true;
  50. }
  51. void CServerDemoSystem::Shutdown()
  52. {
  53. if ( !m_pDemo )
  54. return;
  55. FreeDemo();
  56. }
  57. void CServerDemoSystem::FreeDemo()
  58. {
  59. delete m_pDemo;
  60. m_pDemo = NULL;
  61. }
  62. bool CServerDemoSystem::CreateDemo( char const* pMapName )
  63. {
  64. m_pDemo = new CServerDemo();
  65. if ( !m_pDemo )
  66. return false;
  67. return m_pDemo->Init( pMapName, gpGlobals->curtime );
  68. }
  69. void CServerDemoSystem::PostRecordingMessage( KeyValues* pMsg )
  70. {
  71. if ( !m_pDemo )
  72. return;
  73. m_pDemo->PostRecordingMessage( pMsg, gpGlobals->curtime );
  74. }
  75. void CServerDemoSystem::Think()
  76. {
  77. if ( !g_bAllowServerDemoWrite )
  78. return;
  79. if ( !m_pDemo || !m_pDemo->m_pBuffer )
  80. return;
  81. // Write how much of buffer has been used
  82. engine->Con_NPrintf( 0, "%% circular buffer used: %2f", (float)(m_pDemo->m_pBuffer->GetSize() - m_pDemo->m_pBuffer->GetWriteAvailable()) / m_pDemo->m_pBuffer->GetSize() );
  83. // Write entities?
  84. float flRecordRate = MAX( 20.0f, MIN( 60.0f, sv_demo_entity_record_rate.GetFloat() ) );
  85. if ( gpGlobals->curtime - m_flLastEntRecordTime < 1.0f/flRecordRate )
  86. return;
  87. int const iCurSecond = (int)gpGlobals->curtime;
  88. if ( iCurSecond != m_nLastRecordSecond )
  89. {
  90. // DevMsg( "%d: frames record: %d\n", m_lastRecordSecond, m_frameCount );
  91. m_nLastRecordSecond = iCurSecond;
  92. m_nFrameCount = 0;
  93. }
  94. else
  95. {
  96. ++m_nFrameCount;
  97. }
  98. for ( CBaseEntity *pEntity = gEntList.FirstEnt(); pEntity != NULL; pEntity = gEntList.NextEnt(pEntity) )
  99. {
  100. if ( !pEntity )
  101. continue;
  102. KeyValues* pMsg = new KeyValues( "entity" );
  103. // Store server demo ptr
  104. pMsg->SetPtr( "serverdemo", m_pDemo );
  105. // Fill msg with state data - only post message if state changed
  106. if ( pEntity->GetDemoRecordingState( pMsg ) )
  107. {
  108. ServerDemoPacket_BaseEntity* pBaseEntPacket = (ServerDemoPacket_BaseEntity*)pMsg->GetPtr( "baseentity" );
  109. if ( pBaseEntPacket )
  110. {
  111. matrix3x4_t m;
  112. AngleMatrix( pEntity->GetAbsAngles(), pEntity->GetAbsOrigin(), m );
  113. ServerDemoPacket_BaseAnimating* pBaseAnimatingPacket = (ServerDemoPacket_BaseAnimating*)pMsg->GetPtr( "baseanimating" );
  114. ServerDemoPacket_BaseAnimatingOverlay* pBaseAnimatingPacketOverlay = (ServerDemoPacket_BaseAnimatingOverlay*)pMsg->GetPtr( "baseanimatingoverlay" );
  115. if ( ( pBaseEntPacket->m_fModified != 0 ) ||
  116. ( pBaseAnimatingPacket && pBaseAnimatingPacket->m_fModified ) ||
  117. ( pBaseAnimatingPacketOverlay && pBaseAnimatingPacketOverlay->m_fModified ) )
  118. {
  119. debugoverlay->AddCoordFrameOverlay( m, 25 );
  120. pBaseEntPacket->AddTextOverlaysForModifiedFields( pEntity->GetAbsOrigin() );
  121. // Add BaseAnimatin text
  122. if ( pBaseAnimatingPacket )
  123. {
  124. pBaseAnimatingPacket->AddTextOverlaysForModifiedFields( pEntity->GetAbsOrigin() );
  125. }
  126. // Add BaseAnimatinOverlay text
  127. if ( pBaseAnimatingPacketOverlay )
  128. {
  129. pBaseAnimatingPacketOverlay->AddTextOverlaysForModifiedFields( pEntity->GetAbsOrigin() );
  130. }
  131. }
  132. }
  133. // Post a message to the demo system
  134. g_pServerDemoSystem->PostRecordingMessage( pMsg );
  135. // No longer first frame
  136. pEntity->m_bFirstRecordingFrame = false;
  137. }
  138. pMsg->deleteThis();
  139. }
  140. // Stamp record time
  141. m_flLastEntRecordTime = gpGlobals->curtime;
  142. }
  143. void CServerDemoSystem::WriteDemoToDiskForClient( int iClient, char const* pFilename )
  144. {
  145. // TODO: Send the circular buffer to SFM for save to file
  146. if ( !serverenginetools->SFM_WriteServerDemoFile( pFilename, m_pDemo ) )
  147. {
  148. Warning( "Failed to write server demo file, %s\n", pFilename );
  149. }
  150. }
  151. void CServerDemoSystem::OnInitLevel( char const* pMapName )
  152. {
  153. g_bAllowServerDemoWrite = true;
  154. FreeDemo();
  155. Init();
  156. if ( !CreateDemo( pMapName ) )
  157. {
  158. Warning( "Failed to create server demo\n" );
  159. FreeDemo();
  160. }
  161. }
  162. void CServerDemoSystem::OnShutdownLevel()
  163. {
  164. g_bAllowServerDemoWrite = false;
  165. FreeDemo();
  166. }
  167. //------------------------------------------------------------------------------------------------------------------------
  168. IServerDemoSystem* g_pServerDemoSystem = NULL;
  169. static CServerDemoSystem g_serverDemoSystem;
  170. //------------------------------------------------------------------------------------------------------------------------
  171. bool ServerDemoSystem_Init()
  172. {
  173. Assert( !g_pServerDemoSystem );
  174. // Setup the interface
  175. g_pServerDemoSystem = &g_serverDemoSystem;
  176. // Init system
  177. return g_serverDemoSystem.Init(); // TODO: Should be passed in or accessed from command line, etc.
  178. }
  179. void ServerDemoSystem_Shutdown()
  180. {
  181. if ( g_pServerDemoSystem )
  182. {
  183. g_serverDemoSystem.Shutdown();
  184. }
  185. }
  186. //------------------------------------------------------------------------------------------------------------------------
  187. CON_COMMAND( dump_server_demo, "dump_sever_demo <filename>" )
  188. {
  189. if ( !g_bAllowServerDemoWrite )
  190. {
  191. DevMsg( "Server demo not allowed now.\n" );
  192. return;
  193. }
  194. if ( args.ArgC() != 2 )
  195. {
  196. DevMsg( "Please specify an output filename.\n" );
  197. return;
  198. }
  199. if ( !g_pServerDemoSystem )
  200. {
  201. DevMsg( "Server demo system not initialized!\n" );
  202. return;
  203. }
  204. g_bAllowServerDemoWrite = false;
  205. // Use dummy client id for now.
  206. g_pServerDemoSystem->WriteDemoToDiskForClient( -1, args[1] );
  207. g_bAllowServerDemoWrite = true;
  208. }
  209. //------------------------------------------------------------------------------------------------------------------------