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
273 lines
7.0 KiB
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "serverdemo_system.h" |
|
#include "serverdemo_types.h" |
|
#include "vstdlib/IKeyValuesSystem.h" |
|
#include "tier1/circularbuffer.h" |
|
#include "toolutils/enginetools_int.h" |
|
#include "toolframework/itoolframework.h" |
|
#include "toolframework/iserverenginetools.h" |
|
#include "serverdemo.h" |
|
|
|
//------------------------------------------------------------------------------------------------------------------------ |
|
|
|
bool g_bAllowServerDemoWrite = true; |
|
|
|
//------------------------------------------------------------------------------------------------------------------------ |
|
|
|
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." ); |
|
|
|
//------------------------------------------------------------------------------------------------------------------------ |
|
|
|
class CServerDemoSystem : public IServerDemoSystem // Implementation |
|
{ |
|
public: |
|
CServerDemoSystem(); |
|
|
|
bool Init(); |
|
void Shutdown(); |
|
|
|
virtual void WriteDemoToDiskForClient( int iClient, char const* pFilename ); |
|
|
|
virtual void PostRecordingMessage( KeyValues* pMsg ); |
|
|
|
virtual void Think(); |
|
|
|
virtual void OnInitLevel( char const* pMapName ); |
|
virtual void OnShutdownLevel(); |
|
|
|
bool CreateDemo( char const* pMapName ); |
|
void FreeDemo(); |
|
|
|
CServerDemo* m_pDemo; |
|
float m_flLastEntRecordTime; |
|
int m_nLastRecordSecond; |
|
int m_nFrameCount; |
|
}; |
|
|
|
//------------------------------------------------------------------------------------------------------------------------ |
|
|
|
CServerDemoSystem::CServerDemoSystem() |
|
{ |
|
Init(); |
|
} |
|
|
|
bool CServerDemoSystem::Init() |
|
{ |
|
m_pDemo = NULL; |
|
m_flLastEntRecordTime = 0.0f; |
|
m_nFrameCount = 0; |
|
m_nLastRecordSecond = 0; |
|
return true; |
|
} |
|
|
|
void CServerDemoSystem::Shutdown() |
|
{ |
|
if ( !m_pDemo ) |
|
return; |
|
|
|
FreeDemo(); |
|
} |
|
|
|
void CServerDemoSystem::FreeDemo() |
|
{ |
|
delete m_pDemo; |
|
m_pDemo = NULL; |
|
} |
|
|
|
bool CServerDemoSystem::CreateDemo( char const* pMapName ) |
|
{ |
|
m_pDemo = new CServerDemo(); |
|
if ( !m_pDemo ) |
|
return false; |
|
|
|
return m_pDemo->Init( pMapName, gpGlobals->curtime ); |
|
} |
|
|
|
void CServerDemoSystem::PostRecordingMessage( KeyValues* pMsg ) |
|
{ |
|
if ( !m_pDemo ) |
|
return; |
|
|
|
m_pDemo->PostRecordingMessage( pMsg, gpGlobals->curtime ); |
|
} |
|
|
|
void CServerDemoSystem::Think() |
|
{ |
|
if ( !g_bAllowServerDemoWrite ) |
|
return; |
|
|
|
if ( !m_pDemo || !m_pDemo->m_pBuffer ) |
|
return; |
|
|
|
// Write how much of buffer has been used |
|
engine->Con_NPrintf( 0, "%% circular buffer used: %2f", (float)(m_pDemo->m_pBuffer->GetSize() - m_pDemo->m_pBuffer->GetWriteAvailable()) / m_pDemo->m_pBuffer->GetSize() ); |
|
|
|
// Write entities? |
|
float flRecordRate = MAX( 20.0f, MIN( 60.0f, sv_demo_entity_record_rate.GetFloat() ) ); |
|
if ( gpGlobals->curtime - m_flLastEntRecordTime < 1.0f/flRecordRate ) |
|
return; |
|
|
|
int const iCurSecond = (int)gpGlobals->curtime; |
|
if ( iCurSecond != m_nLastRecordSecond ) |
|
{ |
|
// DevMsg( "%d: frames record: %d\n", m_lastRecordSecond, m_frameCount ); |
|
|
|
m_nLastRecordSecond = iCurSecond; |
|
m_nFrameCount = 0; |
|
} |
|
else |
|
{ |
|
++m_nFrameCount; |
|
} |
|
|
|
for ( CBaseEntity *pEntity = gEntList.FirstEnt(); pEntity != NULL; pEntity = gEntList.NextEnt(pEntity) ) |
|
{ |
|
if ( !pEntity ) |
|
continue; |
|
|
|
KeyValues* pMsg = new KeyValues( "entity" ); |
|
|
|
// Store server demo ptr |
|
pMsg->SetPtr( "serverdemo", m_pDemo ); |
|
|
|
// Fill msg with state data - only post message if state changed |
|
if ( pEntity->GetDemoRecordingState( pMsg ) ) |
|
{ |
|
ServerDemoPacket_BaseEntity* pBaseEntPacket = (ServerDemoPacket_BaseEntity*)pMsg->GetPtr( "baseentity" ); |
|
if ( pBaseEntPacket ) |
|
{ |
|
matrix3x4_t m; |
|
AngleMatrix( pEntity->GetAbsAngles(), pEntity->GetAbsOrigin(), m ); |
|
|
|
ServerDemoPacket_BaseAnimating* pBaseAnimatingPacket = (ServerDemoPacket_BaseAnimating*)pMsg->GetPtr( "baseanimating" ); |
|
ServerDemoPacket_BaseAnimatingOverlay* pBaseAnimatingPacketOverlay = (ServerDemoPacket_BaseAnimatingOverlay*)pMsg->GetPtr( "baseanimatingoverlay" ); |
|
|
|
if ( ( pBaseEntPacket->m_fModified != 0 ) || |
|
( pBaseAnimatingPacket && pBaseAnimatingPacket->m_fModified ) || |
|
( pBaseAnimatingPacketOverlay && pBaseAnimatingPacketOverlay->m_fModified ) ) |
|
{ |
|
debugoverlay->AddCoordFrameOverlay( m, 25 ); |
|
pBaseEntPacket->AddTextOverlaysForModifiedFields( pEntity->GetAbsOrigin() ); |
|
|
|
// Add BaseAnimatin text |
|
if ( pBaseAnimatingPacket ) |
|
{ |
|
pBaseAnimatingPacket->AddTextOverlaysForModifiedFields( pEntity->GetAbsOrigin() ); |
|
} |
|
|
|
// Add BaseAnimatinOverlay text |
|
if ( pBaseAnimatingPacketOverlay ) |
|
{ |
|
pBaseAnimatingPacketOverlay->AddTextOverlaysForModifiedFields( pEntity->GetAbsOrigin() ); |
|
} |
|
} |
|
} |
|
|
|
// Post a message to the demo system |
|
g_pServerDemoSystem->PostRecordingMessage( pMsg ); |
|
|
|
// No longer first frame |
|
pEntity->m_bFirstRecordingFrame = false; |
|
} |
|
|
|
pMsg->deleteThis(); |
|
} |
|
|
|
// Stamp record time |
|
m_flLastEntRecordTime = gpGlobals->curtime; |
|
} |
|
|
|
void CServerDemoSystem::WriteDemoToDiskForClient( int iClient, char const* pFilename ) |
|
{ |
|
// TODO: Send the circular buffer to SFM for save to file |
|
if ( !serverenginetools->SFM_WriteServerDemoFile( pFilename, m_pDemo ) ) |
|
{ |
|
Warning( "Failed to write server demo file, %s\n", pFilename ); |
|
} |
|
} |
|
|
|
void CServerDemoSystem::OnInitLevel( char const* pMapName ) |
|
{ |
|
g_bAllowServerDemoWrite = true; |
|
|
|
FreeDemo(); |
|
|
|
Init(); |
|
|
|
if ( !CreateDemo( pMapName ) ) |
|
{ |
|
Warning( "Failed to create server demo\n" ); |
|
FreeDemo(); |
|
} |
|
} |
|
|
|
void CServerDemoSystem::OnShutdownLevel() |
|
{ |
|
g_bAllowServerDemoWrite = false; |
|
|
|
FreeDemo(); |
|
} |
|
|
|
//------------------------------------------------------------------------------------------------------------------------ |
|
|
|
IServerDemoSystem* g_pServerDemoSystem = NULL; |
|
static CServerDemoSystem g_serverDemoSystem; |
|
|
|
//------------------------------------------------------------------------------------------------------------------------ |
|
|
|
bool ServerDemoSystem_Init() |
|
{ |
|
Assert( !g_pServerDemoSystem ); |
|
|
|
// Setup the interface |
|
g_pServerDemoSystem = &g_serverDemoSystem; |
|
|
|
// Init system |
|
return g_serverDemoSystem.Init(); // TODO: Should be passed in or accessed from command line, etc. |
|
} |
|
|
|
void ServerDemoSystem_Shutdown() |
|
{ |
|
if ( g_pServerDemoSystem ) |
|
{ |
|
g_serverDemoSystem.Shutdown(); |
|
} |
|
} |
|
|
|
//------------------------------------------------------------------------------------------------------------------------ |
|
|
|
CON_COMMAND( dump_server_demo, "dump_sever_demo <filename>" ) |
|
{ |
|
if ( !g_bAllowServerDemoWrite ) |
|
{ |
|
DevMsg( "Server demo not allowed now.\n" ); |
|
return; |
|
} |
|
|
|
if ( args.ArgC() != 2 ) |
|
{ |
|
DevMsg( "Please specify an output filename.\n" ); |
|
return; |
|
} |
|
|
|
if ( !g_pServerDemoSystem ) |
|
{ |
|
DevMsg( "Server demo system not initialized!\n" ); |
|
return; |
|
} |
|
|
|
g_bAllowServerDemoWrite = false; |
|
|
|
// Use dummy client id for now. |
|
g_pServerDemoSystem->WriteDemoToDiskForClient( -1, args[1] ); |
|
|
|
g_bAllowServerDemoWrite = true; |
|
} |
|
|
|
//------------------------------------------------------------------------------------------------------------------------
|
|
|