//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "client_pch.h" #include #include #include "cl_demoaction.h" #include "cl_demoactionmanager.h" #include "cl_demouipanel.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" using namespace vgui; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- class CDemoActionManager : public IDemoActionManager { public: CDemoActionManager(); ~CDemoActionManager(); // Public interface public: virtual void Init( void ); virtual void Shutdown( void ); virtual void StartPlaying( char const *demfilename ); virtual void StopPlaying(); virtual void Update( bool newframe, int demotick, float demotime ); virtual void SaveToBuffer( CUtlBuffer& buf ); virtual void SaveToFile( void ); virtual char const *GetCurrentDemoFile( void ); virtual int GetActionCount( void ); virtual CBaseDemoAction *GetAction( int index ); virtual void AddAction( CBaseDemoAction *action ); virtual void RemoveAction( CBaseDemoAction *action ); virtual bool IsDirty( void ) const; virtual void SetDirty( bool dirty ); virtual void ReloadFromDisk( void ); virtual void DispatchEvents(); virtual void InsertFireEvent( CBaseDemoAction *action ); virtual bool OverrideView( democmdinfo_t& info, int tick ); private: void OnVDMLoaded( char const *demfilename ); void ClearAll(); CUtlVector< CBaseDemoAction * > m_ActionStack; CUtlVector< CBaseDemoAction * > m_PendingFireActionStack; int m_nPrevTick; float m_flPrevTime; bool m_bDirty; char m_szCurrentFile[ MAX_OSPATH ]; long m_lFileTime; }; static CDemoActionManager g_DemoActionManager; IDemoActionManager *demoaction = ( IDemoActionManager * )&g_DemoActionManager; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CDemoActionManager::CDemoActionManager() { m_nPrevTick = 0; m_flPrevTime = 0.0f; m_szCurrentFile[ 0 ] = 0; m_bDirty = false; m_lFileTime = -1; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CDemoActionManager::~CDemoActionManager() { } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CDemoActionManager::Init( void ) { } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CDemoActionManager::Shutdown( void ) { StopPlaying(); ClearAll(); m_ActionStack.Purge(); m_PendingFireActionStack.Purge(); } //----------------------------------------------------------------------------- // Purpose: Reload without saving //----------------------------------------------------------------------------- void CDemoActionManager::ReloadFromDisk( void ) { char metafile[ 512 ]; Q_StripExtension( m_szCurrentFile, metafile, sizeof( metafile ) ); Q_DefaultExtension( metafile, ".vdm", sizeof( metafile ) ); ClearAll(); //const char *buffer = NULL; //int sz = 0; //buffer = (const char *)COM_LoadFile( metafile, 5, &sz ); // if ( buffer ) // { m_lFileTime = g_pFileSystem->GetFileTime( metafile ); KeyValues *kv = new KeyValues( metafile ); Assert( kv ); if ( kv ) { if ( kv->LoadFromFile( g_pFullFileSystem, metafile ) ) { // Iterate over all metaclasses... KeyValues* pIter = kv->GetFirstSubKey(); while( pIter ) { char factorytouse[ 512 ]; Q_strncpy( factorytouse, pIter->GetName(), sizeof( factorytouse ) ); // New format is to put numbers in here if ( atoi( factorytouse ) > 0 ) { Q_strncpy( factorytouse, pIter->GetString( "factory", "" ), sizeof( factorytouse ) ); } CBaseDemoAction *action = CBaseDemoAction::CreateDemoAction( CBaseDemoAction::TypeForName( factorytouse ) ); if ( action ) { if ( !action->Init( pIter ) ) { delete action; } else { m_ActionStack.AddToTail( action ); } } pIter = pIter->GetNextKey(); } } else { SaveToFile(); } } // } // else // { // This will save out an empty .vdm of the proper name // SaveToFile(); // } OnVDMLoaded( m_szCurrentFile ); m_bDirty = false; } //----------------------------------------------------------------------------- // Purpose: // Input : *demfilename - //----------------------------------------------------------------------------- void CDemoActionManager::StartPlaying( char const *demfilename ) { Assert( demfilename ); // Clear anything currently pending StopPlaying(); bool changedfile = Q_strcasecmp( demfilename, m_szCurrentFile ) != 0 ? true : false; Q_strncpy( m_szCurrentFile, demfilename, sizeof( m_szCurrentFile ) ); char metafile[ 512 ]; Q_StripExtension( demfilename, metafile, sizeof( metafile ) ); Q_DefaultExtension( metafile, ".vdm", sizeof( metafile ) ); long filetime = g_pFileSystem->GetFileTime( metafile ); // If didn't change file and the timestamps are the same, don't transition to new .vdm if ( !changedfile && ( m_lFileTime == filetime ) ) { return; } if ( m_bDirty ) { SaveToFile(); } ReloadFromDisk(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CDemoActionManager::ClearAll() { m_PendingFireActionStack.RemoveAll(); while ( m_ActionStack.Count() > 0 ) { CBaseDemoAction *a = m_ActionStack[ 0 ]; delete a; m_ActionStack.Remove( 0 ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CDemoActionManager::StopPlaying() { int count = m_ActionStack.Count(); for ( int i = 0; i < count; i++ ) { CBaseDemoAction *a = m_ActionStack[ i ]; a->Reset(); } // Reset counters m_nPrevTick = 0; m_flPrevTime = 0.0f; m_PendingFireActionStack.RemoveAll(); } //----------------------------------------------------------------------------- // Purpose: // Input : demoframe - // demotime - //----------------------------------------------------------------------------- void CDemoActionManager::Update( bool newframe, int demotick, float demotime ) { // Nothing to do? int count = m_ActionStack.Count(); if ( count <= 0 ) return; // Setup timing context DemoActionTimingContext ctx; ctx.prevtick = m_nPrevTick; ctx.curtick = demotick; ctx.prevtime = m_flPrevTime; ctx.curtime = demotime; int i; for ( i = 0; i < count; i++ ) { CBaseDemoAction *action = m_ActionStack[ i ]; Assert( action ); if ( !action ) continue; action->Update( ctx ); } m_nPrevTick = demotick; m_flPrevTime = demotime; } //----------------------------------------------------------------------------- // Purpose: // Input : buf - //----------------------------------------------------------------------------- void CDemoActionManager::SaveToBuffer( CUtlBuffer& buf ) { buf.Printf( "demoactions\n" ); buf.Printf( "{\n" ); int count = m_ActionStack.Count(); int i; for ( i = 0; i < count; i++ ) { CBaseDemoAction *action = m_ActionStack[ i ]; Assert( action ); if ( !action ) continue; action->SaveToBuffer( 1, i + 1, buf ); } buf.Printf( "}\n" ); } //----------------------------------------------------------------------------- // Purpose: // Input : *demfilename - //----------------------------------------------------------------------------- void CDemoActionManager::SaveToFile( void ) { // Nothing loaded if ( m_szCurrentFile[ 0 ] == 0 ) return; // It's not dirty if ( !m_bDirty ) return; char metafile[ 512 ]; Q_StripExtension( m_szCurrentFile, metafile, sizeof( metafile ) ); Q_DefaultExtension( metafile, ".vdm", sizeof( metafile ) ); // Save data CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); SaveToBuffer( buf ); // Write to file FileHandle_t fh; fh = g_pFileSystem->Open( metafile, "w" ); if ( fh != FILESYSTEM_INVALID_HANDLE ) { g_pFileSystem->Write( buf.Base(), buf.TellPut(), fh ); g_pFileSystem->Close( fh ); } m_bDirty = false; // Make sure filetime is up to date m_lFileTime = g_pFileSystem->GetFileTime( metafile ); } //----------------------------------------------------------------------------- // Purpose: // Input : *demfilename - //----------------------------------------------------------------------------- void CDemoActionManager::OnVDMLoaded( char const *demfilename ) { // Notify UI? #if !defined (LINUX) if ( g_pDemoUI ) { g_pDemoUI->OnVDMChanged(); } //if ( g_pDemoUI2 ) //{ // g_pDemoUI2->OnVDMChanged(); //} #endif } char const *CDemoActionManager::GetCurrentDemoFile( void ) { return m_szCurrentFile; } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CDemoActionManager::GetActionCount( void ) { int count = m_ActionStack.Count(); return count; } //----------------------------------------------------------------------------- // Purpose: // Input : index - // Output : CBaseDemoAction //----------------------------------------------------------------------------- CBaseDemoAction *CDemoActionManager::GetAction( int index ) { int count = m_ActionStack.Count(); if ( index < 0 || index >= count ) return NULL; return m_ActionStack[ index ]; } //----------------------------------------------------------------------------- // Purpose: // Input : *action - //----------------------------------------------------------------------------- void CDemoActionManager::AddAction( CBaseDemoAction *action ) { m_bDirty = true; Assert( action ); m_ActionStack.AddToTail( action ); } //----------------------------------------------------------------------------- // Purpose: // Input : *action - //----------------------------------------------------------------------------- void CDemoActionManager::RemoveAction( CBaseDemoAction *action ) { Assert( action ); m_bDirty = true; m_ActionStack.FindAndRemove( action ); delete action; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CDemoActionManager::IsDirty( void ) const { return m_bDirty; } //----------------------------------------------------------------------------- // Purpose: // Input : dirty - //----------------------------------------------------------------------------- void CDemoActionManager::SetDirty( bool dirty ) { m_bDirty = true; } //----------------------------------------------------------------------------- // Purpose: // Input : *action - //----------------------------------------------------------------------------- void CDemoActionManager::InsertFireEvent( CBaseDemoAction *action ) { // BUGBUG: Sometimes this can get called multiple times for the same event before DispatchEvents() is called. Why? // If that gets fixed, remove this hack. if ( m_PendingFireActionStack.Find(action) >= 0 ) return; m_PendingFireActionStack.AddToTail( action ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CDemoActionManager::DispatchEvents() { int c = m_PendingFireActionStack.Count(); int i; for ( i = 0; i < c; i++ ) { CBaseDemoAction *action = m_PendingFireActionStack[ i ]; Assert( action ); action->FireAction(); action->SetActionFired( true ); } m_PendingFireActionStack.RemoveAll(); } bool CDemoActionManager::OverrideView( democmdinfo_t& info, int tick ) { // override view return false; }