//========== 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(); }