summaryrefslogtreecommitdiff
path: root/engine/testscriptmgr.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/testscriptmgr.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'engine/testscriptmgr.cpp')
-rw-r--r--engine/testscriptmgr.cpp423
1 files changed, 423 insertions, 0 deletions
diff --git a/engine/testscriptmgr.cpp b/engine/testscriptmgr.cpp
new file mode 100644
index 0000000..c94ed1b
--- /dev/null
+++ b/engine/testscriptmgr.cpp
@@ -0,0 +1,423 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+
+#include "tier0/platform.h"
+#include "sys.h"
+#include "testscriptmgr.h"
+#include "tier0/dbg.h"
+#include "filesystem_engine.h"
+#include "tier1/strtools.h"
+#include "cmd.h"
+#include "convar.h"
+#include "vstdlib/random.h"
+#include <stdlib.h>
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+CTestScriptMgr g_TestScriptMgr;
+
+ConVar testscript_debug( "testscript_debug", "0", 0, "Debug test scripts." );
+
+#ifdef _DEBUG
+// --------------------------------------------------------------------------------------------------- //
+// Global console commands the test script manager implements.
+// --------------------------------------------------------------------------------------------------- //
+CON_COMMAND_EXTERN( Test_Wait, Test_Wait, "" )
+{
+ if ( args.ArgC() < 2 )
+ {
+ Error( "Test_Wait: requires seconds parameter." );
+ return;
+ }
+
+ float flSeconds = atof( args[ 1 ] );
+ GetTestScriptMgr()->SetWaitTime( flSeconds );
+}
+
+CON_COMMAND_EXTERN( Test_RunFrame, Test_RunFrame, "" )
+{
+ GetTestScriptMgr()->SetWaitCheckPoint( "frame_end" );
+}
+
+CON_COMMAND_EXTERN( Test_WaitForCheckPoint, Test_WaitForCheckPoint, "" )
+{
+ if ( args.ArgC() < 2 )
+ {
+ Error( "Test_WaitForCheckPoint <checkpoint name> [once]: requires checkpoint name." );
+ return;
+ }
+
+ bool bOnce = ( args.ArgC() >= 3 && Q_stricmp( args[2], "once" ) == 0 );
+ GetTestScriptMgr()->SetWaitCheckPoint( args[ 1 ], bOnce );
+}
+
+CON_COMMAND_EXTERN( Test_StartLoop, Test_StartLoop, "Test_StartLoop <loop name> - Denote the start of a loop. Really just defines a named point you can jump to." )
+{
+ if ( args.ArgC() < 2 )
+ {
+ Error( "Test_StartLoop: requires a loop name." );
+ return;
+ }
+
+ GetTestScriptMgr()->StartLoop( args[ 1 ] );
+}
+
+CON_COMMAND_EXTERN( Test_LoopCount, Test_LoopCount, "Test_LoopCount <loop name> <count> - loop back to the specified loop start point the specified # of times." )
+{
+ if ( args.ArgC() < 3 )
+ {
+ Error( "Test_LoopCount: requires a loop name and number of times to loop." );
+ return;
+ }
+
+ GetTestScriptMgr()->LoopCount( args[ 1 ], atoi( args[ 2 ] ) );
+}
+
+CON_COMMAND_EXTERN( Test_Loop, Test_Loop, "Test_Loop <loop name> - loop back to the specified loop start point unconditionally." )
+{
+ if ( args.ArgC() < 2 )
+ {
+ Error( "Test_Loop: requires a loop name." );
+ return;
+ }
+
+ GetTestScriptMgr()->LoopCount( args[ 1 ], -1 );
+}
+
+CON_COMMAND_EXTERN( Test_LoopForNumSeconds, Test_LoopForNumSeconds, "Test_LoopForNumSeconds <loop name> <time> - loop back to the specified start point for the specified # of seconds." )
+{
+ if ( args.ArgC() < 3 )
+ {
+ Error( "Test_LoopLoopForNumSeconds: requires a loop name and number of seconds to loop." );
+ return;
+ }
+
+ GetTestScriptMgr()->LoopForNumSeconds( args[ 1 ], atof( args[ 2 ] ) );
+}
+
+CON_COMMAND( Test_RandomChance, "Test_RandomChance <percent chance, 0-100> <token1> <token2...> - Roll the dice and maybe run the command following the percentage chance." )
+{
+ if ( args.ArgC() < 3 )
+ {
+ Error( "Test_RandomChance: requires percentage chance parameter (0-100) followed by command to execute." );
+ }
+
+ float flPercent = atof( args[ 1 ] );
+ if ( RandomFloat( 0, 100 ) < flPercent )
+ {
+ char newString[1024];
+ newString[0] = 0;
+
+ for ( int i=2; i < args.ArgC(); i++ )
+ {
+ Q_strncat( newString, args[ i ], sizeof( newString ), COPY_ALL_CHARACTERS );
+ Q_strncat( newString, " ", sizeof( newString ), COPY_ALL_CHARACTERS );
+ }
+
+ Cbuf_InsertText( newString );
+ }
+}
+
+
+CON_COMMAND( Test_SendKey, "" )
+{
+ if ( args.ArgC() < 2 )
+ {
+ Error( "Test_SendKey: requires key to send." );
+ }
+ Sys_TestSendKey( args[1] );
+}
+
+CON_COMMAND( Test_StartScript, "Start a test script running.." )
+{
+ if ( args.ArgC() < 2 )
+ {
+ Warning( "Test_StartScript: requires filename of script to start (file must be under testscripts directory).\n" );
+ }
+
+ if ( !GetTestScriptMgr()->StartTestScript( args[1] ) )
+ Warning( "Error starting testscript '%s'\n", args[1] );
+}
+#endif
+
+// --------------------------------------------------------------------------------------------------- //
+// CTestScriptMgr implementation.
+// --------------------------------------------------------------------------------------------------- //
+CTestScriptMgr::CTestScriptMgr()
+{
+ m_hFile = FILESYSTEM_INVALID_HANDLE;
+ m_NextCheckPoint[0] = 0;
+ m_WaitUntil = Sys_FloatTime();
+}
+
+
+CTestScriptMgr::~CTestScriptMgr()
+{
+ Term();
+}
+
+
+bool CTestScriptMgr::StartTestScript( const char *pFilename )
+{
+ Term();
+
+ char fullName[512];
+ Q_snprintf( fullName, sizeof( fullName ), "testscripts\\%s", pFilename );
+
+ m_hFile = g_pFileSystem->Open( fullName, "rt" );
+ if ( m_hFile == FILESYSTEM_INVALID_HANDLE )
+ return false;
+
+ RunCommands();
+ return true;
+}
+
+
+void CTestScriptMgr::Term()
+{
+ if ( m_hFile != FILESYSTEM_INVALID_HANDLE )
+ {
+ g_pFileSystem->Close( m_hFile );
+ m_hFile = FILESYSTEM_INVALID_HANDLE;
+ }
+}
+
+
+bool CTestScriptMgr::IsInitted() const
+{
+ return m_hFile != FILESYSTEM_INVALID_HANDLE;
+}
+
+
+void CTestScriptMgr::CheckPoint( const char *pName )
+{
+ if ( !IsInitted() || IsTimerWaiting() )
+ return;
+
+ if ( testscript_debug.GetInt() )
+ {
+ if ( stricmp( pName, "frame_end" ) != 0 )
+ {
+ Msg( "TESTSCRIPT: CheckPoint -> '%s'.\n", pName );
+ }
+ }
+
+ m_CheckPointsHit.Insert( pName, 0 ); // Remember that we hit this checkpoint.
+
+ if ( m_NextCheckPoint[0] )
+ {
+ if ( Q_stricmp( m_NextCheckPoint, pName ) != 0 )
+ {
+ // This isn't the checkpoint you're looking for.
+ return;
+ }
+ }
+
+ // Either the timer expired, or we hit the checkpoint we were waiting for. Run some more commands.
+ m_NextCheckPoint[0] = 0;
+ RunCommands();
+}
+
+
+void CTestScriptMgr::RunCommands()
+{
+ Assert( IsInitted() );
+
+ while ( !IsTimerWaiting() && !IsCheckPointWaiting() )
+ {
+ // Parse out the next command.
+ char curCommand[512];
+ int iCurPos = 0;
+
+ bool bInSlash = false;
+ while ( 1 )
+ {
+ g_pFileSystem->Read( &curCommand[iCurPos], 1, m_hFile );
+ if ( curCommand[iCurPos] == '/' )
+ {
+ if ( bInSlash )
+ {
+ // Ok, the rest of this line is a comment.
+ char tempVal = !'\n';
+ while ( tempVal != '\n' && !g_pFileSystem->EndOfFile( m_hFile ) )
+ {
+ g_pFileSystem->Read( &tempVal, 1, m_hFile );
+ }
+
+ --iCurPos;
+ break;
+ }
+ else
+ {
+ bInSlash = true;
+ }
+ }
+ else
+ {
+ bInSlash = false;
+
+ if ( curCommand[iCurPos] == ';' || curCommand[iCurPos] == '\n' || g_pFileSystem->EndOfFile( m_hFile ) )
+ {
+ // End of this command.
+ break;
+ }
+ }
+
+ ++iCurPos;
+ }
+
+ curCommand[iCurPos] = 0;
+
+ // Did we hit the end of the file?
+ if ( curCommand[0] == 0 )
+ {
+ if ( g_pFileSystem->EndOfFile( m_hFile ) )
+ {
+ Term();
+ break;
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ Cbuf_AddText( curCommand );
+ Cbuf_Execute();
+ }
+}
+
+
+bool CTestScriptMgr::IsTimerWaiting() const
+{
+ if ( Sys_FloatTime() < m_WaitUntil )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+bool CTestScriptMgr::IsCheckPointWaiting() const
+{
+ return m_NextCheckPoint[0] != 0;
+}
+
+
+void CTestScriptMgr::SetWaitTime( float flSeconds )
+{
+ m_WaitUntil = Sys_FloatTime() + flSeconds;
+}
+
+
+CLoopInfo* CTestScriptMgr::FindLoop( const char *pLoopName )
+{
+ FOR_EACH_LL( m_Loops, i )
+ {
+ if ( Q_stricmp( pLoopName, m_Loops[i]->m_Name ) == 0 )
+ return m_Loops[i];
+ }
+ return NULL;
+}
+
+
+void CTestScriptMgr::StartLoop( const char *pLoopName )
+{
+ ErrorIfNotInitted();
+
+ if ( FindLoop( pLoopName ) )
+ {
+ Error( "CTestScriptMgr::StartLoop( %s ): loop already exists.", pLoopName );
+ }
+
+ CLoopInfo *pLoop = new CLoopInfo;
+ Q_strncpy( pLoop->m_Name, pLoopName, sizeof( pLoop->m_Name ) );
+ pLoop->m_nCount = 0;
+ pLoop->m_flStartTime = Sys_FloatTime();
+ pLoop->m_iNextCommandPos = g_pFileSystem->Tell( m_hFile );
+ pLoop->m_ListIndex = m_Loops.AddToTail( pLoop );
+}
+
+
+void CTestScriptMgr::LoopCount( const char *pLoopName, int nTimes )
+{
+ ErrorIfNotInitted();
+
+ CLoopInfo *pLoop = FindLoop( pLoopName );
+ if ( !pLoop )
+ {
+ Error( "CTestScriptMgr::LoopCount( %s ): no loop with this name exists.", pLoopName );
+ }
+
+ ++pLoop->m_nCount;
+ if ( pLoop->m_nCount < nTimes || nTimes == -1 )
+ {
+ g_pFileSystem->Seek( m_hFile, pLoop->m_iNextCommandPos, FILESYSTEM_SEEK_HEAD );
+ }
+ else
+ {
+ m_Loops.Remove( pLoop->m_ListIndex );
+ delete pLoop;
+ }
+}
+
+
+void CTestScriptMgr::LoopForNumSeconds( const char *pLoopName, double nSeconds )
+{
+ ErrorIfNotInitted();
+
+ CLoopInfo *pLoop = FindLoop( pLoopName );
+ if ( !pLoop )
+ {
+ Error( "CTestScriptMgr::LoopForNumSeconds( %s ): no loop with this name exists.", pLoopName );
+ }
+
+ if ( Sys_FloatTime() - pLoop->m_flStartTime < nSeconds )
+ {
+ g_pFileSystem->Seek( m_hFile, pLoop->m_iNextCommandPos, FILESYSTEM_SEEK_HEAD );
+ }
+ else
+ {
+ m_Loops.Remove( pLoop->m_ListIndex );
+ delete pLoop;
+ }
+}
+
+
+void CTestScriptMgr::ErrorIfNotInitted()
+{
+ if ( !IsInitted() )
+ {
+ Error( "CTestScriptMgr: not initialized." );
+ }
+}
+
+
+void CTestScriptMgr::SetWaitCheckPoint( const char *pCheckPointName, bool bOnce )
+{
+ if ( testscript_debug.GetInt() )
+ {
+ if ( stricmp( pCheckPointName, "frame_end" ) != 0 )
+ {
+ Msg( "TESTSCRIPT: waiting for checkpoint '%s'%s\n", pCheckPointName, bOnce ? " (once)." : "." );
+ }
+ }
+
+ // Don't wait on this checkpoint if we alereayd
+ if ( bOnce && m_CheckPointsHit.Find( pCheckPointName ) != m_CheckPointsHit.InvalidIndex() )
+ return;
+
+ Q_strncpy( m_NextCheckPoint, pCheckPointName, sizeof( m_NextCheckPoint ) );
+}