//========== Copyright (c) 2008, Valve Corporation, All rights reserved. ======== // // Purpose: // //============================================================================= #include "cbase.h" #include "vscript_client.h" #include "icommandline.h" #include "tier1/utlbuffer.h" #include "tier1/fmtstr.h" #include "filesystem.h" #include "characterset.h" #include "isaverestore.h" #include "gamerules.h" #include "vscript_client_nut.h" #if defined ( PORTAL2 ) #include "usermessages.h" #include "hud_macros.h" #endif extern IScriptManager *scriptmanager; extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * ); // #define VMPROFILE 1 #ifdef VMPROFILE #define VMPROF_START double 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 //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- static float Time() { return gpGlobals->curtime; } static const char *GetMapName() { return engine->GetLevelName(); } static const char *DoUniqueString( const char *pszBase ) { static char szBuf[512]; g_pScriptVM->GenerateUniqueKey( pszBase, szBuf, ARRAYSIZE(szBuf) ); return szBuf; } bool DoIncludeScript( const char *pszScript, HSCRIPT hScope ) { if ( !VScriptRunScript( pszScript, hScope, true ) ) { g_pScriptVM->RaiseException( CFmtStr( "Failed to include script \"%s\"", ( pszScript ) ? pszScript : "unknown" ) ); return false; } return true; } int GetDeveloperLevel() { return developer.GetInt(); } bool VScriptClientInit() { VMPROF_START if( scriptmanager != NULL ) { ScriptLanguage_t scriptLanguage = SL_DEFAULT; char const *pszScriptLanguage; if ( CommandLine()->CheckParm( "-scriptlang", &pszScriptLanguage ) ) { if( !Q_stricmp(pszScriptLanguage, "gamemonkey") ) { scriptLanguage = SL_GAMEMONKEY; } else if( !Q_stricmp(pszScriptLanguage, "squirrel") ) { scriptLanguage = SL_SQUIRREL; } else if( !Q_stricmp(pszScriptLanguage, "python") ) { scriptLanguage = SL_PYTHON; } else { DevWarning("-scriptlang does not recognize a language named '%s'. virtual machine did NOT start.\n", pszScriptLanguage ); scriptLanguage = SL_NONE; } } if( scriptLanguage != SL_NONE ) { if ( g_pScriptVM == NULL ) g_pScriptVM = scriptmanager->CreateVM( scriptLanguage ); if( g_pScriptVM ) { Log_Msg( LOG_VScript, "VSCRIPT: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() ); ScriptRegisterFunction( g_pScriptVM, GetMapName, "Get the name of the map."); ScriptRegisterFunction( g_pScriptVM, Time, "Get the current server time" ); ScriptRegisterFunction( g_pScriptVM, DoIncludeScript, "Execute a script (internal)" ); ScriptRegisterFunction( g_pScriptVM, GetDeveloperLevel, "Gets the level of 'develoer'" ); if ( GameRules() ) { GameRules()->RegisterScriptFunctions(); } //g_pScriptVM->RegisterInstance( &g_ScriptEntityIterator, "Entities" ); if ( scriptLanguage == SL_SQUIRREL ) { g_pScriptVM->Run( g_Script_vscript_client ); } VScriptRunScript( "mapspawn", false ); VMPROF_SHOW( pszScriptLanguage, "virtual machine startup" ); return true; } else { DevWarning("VM Did not start!\n"); } } } else { Log_Msg( LOG_VScript, "\nVSCRIPT: Scripting is disabled.\n" ); } g_pScriptVM = NULL; return false; } void VScriptClientTerm() { if( g_pScriptVM != NULL ) { if( g_pScriptVM ) { scriptmanager->DestroyVM( g_pScriptVM ); g_pScriptVM = NULL; } } } class CVScriptGameSystem : public CAutoGameSystemPerFrame { public: // Inherited from IAutoServerSystem virtual void LevelInitPreEntity( void ) { // Note: we may need script VM garbage collection at this point in the future. Currently, VM does not persist // across level boundaries. GC is not necessary because our scripts are supposed to never create circular references // and everything else is handled with ref counting. For the case of bugs creating circular references, the plan is to add // diagnostics that detects such loops and warns the developer. m_bAllowEntityCreationInScripts = true; VScriptClientInit(); } virtual void LevelInitPostEntity( void ) { m_bAllowEntityCreationInScripts = false; } virtual void LevelShutdownPostEntity( void ) { VScriptClientTerm(); } virtual void FrameUpdatePostEntityThink() { if ( g_pScriptVM ) g_pScriptVM->Frame( gpGlobals->frametime ); } bool m_bAllowEntityCreationInScripts; }; CVScriptGameSystem g_VScriptGameSystem; bool IsEntityCreationAllowedInScripts( void ) { return g_VScriptGameSystem.m_bAllowEntityCreationInScripts; } #if defined ( PORTAL2 ) void __MsgFunc_SetMixLayerTriggerFactor( bf_read &msg ) { char buf[MAX_PATH]; msg.ReadString( buf, ARRAYSIZE( buf ), false ); int iLayerID = engine->GetMixLayerIndex( buf ); if ( iLayerID < 0 ) { Warning( "Invalid mix layer passed to SetMixLayerTriggerFactor: '%s'\n", buf ); return; } msg.ReadString( buf, ARRAYSIZE( buf ), false ); int iGroupID = engine->GetMixGroupIndex( buf ); if ( iGroupID < 0 ) { Warning( "Invalid mix group passed to SetMixLayerTriggerFactor: '%s'\n", buf ); return; } engine->SetMixLayerTriggerFactor( iLayerID, iGroupID, msg.ReadFloat() ); } class CSetMixLayerTriggerHelper : public CAutoGameSystem { virtual bool Init() { for( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i ) { ACTIVE_SPLITSCREEN_PLAYER_GUARD( i ); HOOK_MESSAGE( SetMixLayerTriggerFactor ); } return true; } }; static CSetMixLayerTriggerHelper g_SetMixLayerTriggerHelper; #endif