source-engine/game/shared/vscript_shared.cpp
2023-10-03 17:23:56 +03:00

269 lines
5.6 KiB
C++

//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "vscript_shared.h"
#include "icommandline.h"
#include "tier1/utlbuffer.h"
#include "tier1/fmtstr.h"
#include "filesystem.h"
#include "characterset.h"
#include "isaverestore.h"
#include "gamerules.h"
IScriptVM * g_pScriptVM;
extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_VScript, "VScript", LCF_CONSOLE_ONLY, LS_WARNING );
// #define VMPROFILE 1
#ifdef VMPROFILE
#define VMPROF_START float debugStartTime = Plat_FloatTime();
#define VMPROF_SHOW( funcname, funcdesc ) DevMsg("***VSCRIPT PROFILE***: %s %s: %6.4f milliseconds\n", (##funcname), (##funcdesc), (Plat_FloatTime() - debugStartTime)*1000.0 );
#else // !VMPROFILE
#define VMPROF_START
#define VMPROF_SHOW
#endif // VMPROFILE
HSCRIPT VScriptCompileScript( const char *pszScriptName, bool bWarnMissing )
{
if ( !g_pScriptVM )
{
return NULL;
}
static const char *pszExtensions[] =
{
"", // SL_NONE
".gm", // SL_GAMEMONKEY
".nut", // SL_SQUIRREL
".lua", // SL_LUA
".py", // SL_PYTHON
};
const char *pszVMExtension = pszExtensions[g_pScriptVM->GetLanguage()];
const char *pszIncomingExtension = V_strrchr( pszScriptName , '.' );
if ( pszIncomingExtension && V_strcmp( pszIncomingExtension, pszVMExtension ) != 0 )
{
Log_Warning( LOG_VScript, "Script file type does not match VM type\n" );
return NULL;
}
CFmtStr scriptPath;
if ( pszIncomingExtension )
{
scriptPath.sprintf( "scripts/vscripts/%s", pszScriptName );
}
else
{
scriptPath.sprintf( "scripts/vscripts/%s%s", pszScriptName, pszVMExtension );
}
const char *pBase;
CUtlBuffer bufferScript;
if ( g_pScriptVM->GetLanguage() == SL_PYTHON )
{
// python auto-loads raw or precompiled modules - don't load data here
pBase = NULL;
}
else
{
bool bResult = filesystem->ReadFile( scriptPath, "GAME", bufferScript );
if( !bResult )
{
Log_Warning( LOG_VScript, "Script not found (%s) \n", scriptPath.operator const char *() );
Assert( "Error running script" );
}
pBase = (const char *) bufferScript.Base();
if ( !pBase || !*pBase )
{
return NULL;
}
}
const char *pszFilename = V_strrchr( scriptPath, '/' );
pszFilename++;
HSCRIPT hScript = g_pScriptVM->CompileScript( pBase, pszFilename );
if ( !hScript )
{
Log_Warning( LOG_VScript, "FAILED to compile and execute script file named %s\n", scriptPath.operator const char *() );
Assert( "Error running script" );
}
return hScript;
}
static int g_ScriptServerRunScriptDepth;
bool VScriptRunScript( const char *pszScriptName, HSCRIPT hScope, bool bWarnMissing )
{
if ( !g_pScriptVM )
{
return false;
}
if ( !pszScriptName || !*pszScriptName )
{
Log_Warning( LOG_VScript, "Cannot run script: NULL script name\n" );
return false;
}
// Prevent infinite recursion in VM
if ( g_ScriptServerRunScriptDepth > 16 )
{
Log_Warning( LOG_VScript, "IncludeScript stack overflow\n" );
return false;
}
g_ScriptServerRunScriptDepth++;
HSCRIPT hScript = VScriptCompileScript( pszScriptName, bWarnMissing );
bool bSuccess = false;
if ( hScript )
{
#ifdef GAME_DLL
if ( gpGlobals->maxClients == 1 )
{
CBaseEntity *pPlayer = UTIL_GetLocalPlayer();
if ( pPlayer )
{
g_pScriptVM->SetValue( "player", pPlayer->GetScriptInstance() );
}
}
#endif
bSuccess = ( g_pScriptVM->Run( hScript, hScope ) != SCRIPT_ERROR );
if ( !bSuccess )
{
Log_Warning( LOG_VScript, "Error running script named %s\n", pszScriptName );
Assert( "Error running script" );
}
}
g_ScriptServerRunScriptDepth--;
return bSuccess;
}
#ifdef CLIENT_DLL
CON_COMMAND( script_client, "Run the text as a script" )
#else
CON_COMMAND( script, "Run the text as a script" )
#endif
{
if ( !*args[1] )
{
Log_Warning( LOG_VScript, "No function name specified\n" );
return;
}
if ( !g_pScriptVM )
{
Log_Warning( LOG_VScript, "Scripting disabled or no server running\n" );
return;
}
const char *pszScript = args.GetCommandString();
#ifdef CLIENT_DLL
pszScript += 13;
#else
pszScript += 6;
#endif
while ( *pszScript == ' ' )
{
pszScript++;
}
if ( !*pszScript )
{
return;
}
if ( *pszScript != '\"' )
{
g_pScriptVM->Run( pszScript );
}
else
{
pszScript++;
const char *pszEndQuote = pszScript;
while ( *pszEndQuote != '\"' )
{
pszEndQuote++;
}
if ( !*pszEndQuote )
{
return;
}
*((char *)pszEndQuote) = 0;
g_pScriptVM->Run( pszScript );
*((char *)pszEndQuote) = '\"';
}
}
CON_COMMAND_SHARED( script_execute, "Run a vscript file" )
{
if ( !*args[1] )
{
Log_Warning( LOG_VScript, "No script specified\n" );
return;
}
if ( !g_pScriptVM )
{
Log_Warning( LOG_VScript, "Scripting disabled or no server running\n" );
return;
}
VScriptRunScript( args[1], true );
}
CON_COMMAND_SHARED( script_debug, "Connect the vscript VM to the script debugger" )
{
if ( !g_pScriptVM )
{
Log_Warning( LOG_VScript, "Scripting disabled or no server running\n" );
return;
}
g_pScriptVM->ConnectDebugger();
}
CON_COMMAND_SHARED( script_help, "Output help for script functions, optionally with a search string" )
{
if ( !g_pScriptVM )
{
Log_Warning( LOG_VScript, "Scripting disabled or no server running\n" );
return;
}
const char *pszArg1 = "*";
if ( *args[1] )
{
pszArg1 = args[1];
}
g_pScriptVM->Run( CFmtStr( "PrintHelp( \"%s\" );", pszArg1 ) );
}
CON_COMMAND_SHARED( script_dump_all, "Dump the state of the VM to the console" )
{
if ( !g_pScriptVM )
{
Log_Warning( LOG_VScript, "Scripting disabled or no server running\n" );
return;
}
g_pScriptVM->DumpState();
}