Added experimental static/global VScript hooks not tied to any particular class, starting with the integration of OnSave/OnRestore

This commit is contained in:
Blixibon 2021-06-28 23:51:24 -05:00
parent ea7d1afa08
commit 29075a2c90
5 changed files with 260 additions and 219 deletions

View File

@ -835,6 +835,9 @@ static void FireGameEventLocal( const char* szEvent, HSCRIPT hTable )
} }
#endif // !CLIENT_DLL #endif // !CLIENT_DLL
static ScriptHook_t g_Hook_OnSave;
static ScriptHook_t g_Hook_OnRestore;
//============================================================================= //=============================================================================
// Save/Restore Utility // Save/Restore Utility
// Based on L4D2 API // Based on L4D2 API
@ -852,6 +855,9 @@ public: // IGameSystem
{ {
if ( g_pScriptVM ) if ( g_pScriptVM )
{ {
g_Hook_OnSave.Call( NULL, NULL, NULL );
// Legacy hook
HSCRIPT hFunc = g_pScriptVM->LookupFunction( "OnSave" ); HSCRIPT hFunc = g_pScriptVM->LookupFunction( "OnSave" );
if ( hFunc ) if ( hFunc )
{ {
@ -870,6 +876,9 @@ public: // IGameSystem
{ {
if ( g_pScriptVM ) if ( g_pScriptVM )
{ {
g_Hook_OnRestore.Call( NULL, NULL, NULL );
// Legacy hook
HSCRIPT hFunc = g_pScriptVM->LookupFunction( "OnRestore" ); HSCRIPT hFunc = g_pScriptVM->LookupFunction( "OnRestore" );
if ( hFunc ) if ( hFunc )
{ {
@ -3033,6 +3042,8 @@ void RegisterScriptSingletons()
ScriptRegisterFunctionNamed( g_pScriptVM, CScriptSaveRestoreUtil::SaveTable, "SaveTable", "Store a table with primitive values that will persist across level transitions and save loads." ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptSaveRestoreUtil::SaveTable, "SaveTable", "Store a table with primitive values that will persist across level transitions and save loads." );
ScriptRegisterFunctionNamed( g_pScriptVM, CScriptSaveRestoreUtil::RestoreTable, "RestoreTable", "Retrieves a table from storage. Write into input table." ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptSaveRestoreUtil::RestoreTable, "RestoreTable", "Retrieves a table from storage. Write into input table." );
ScriptRegisterFunctionNamed( g_pScriptVM, CScriptSaveRestoreUtil::ClearSavedTable, "ClearSavedTable", "Removes the table with the given context." ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptSaveRestoreUtil::ClearSavedTable, "ClearSavedTable", "Removes the table with the given context." );
ScriptRegisterSimpleHook( g_pScriptVM, g_Hook_OnSave, "OnSave", FIELD_VOID, "Called when the game is saved." );
ScriptRegisterSimpleHook( g_pScriptVM, g_Hook_OnRestore, "OnRestore", FIELD_VOID, "Called when the game is restored." );
ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::FileWrite, "StringToFile", "Stores the string into the file" ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::FileWrite, "StringToFile", "Stores the string into the file" );
ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::FileRead, "FileToString", "Returns the string from the file, null if no file or file is too big." ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::FileRead, "FileToString", "Returns the string from the file, null if no file or file is too big." );
ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::KeyValuesWrite, "KeyValuesToFile", "Stores the CScriptKeyValues into the file" ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::KeyValuesWrite, "KeyValuesToFile", "Stores the CScriptKeyValues into the file" );

View File

@ -755,6 +755,23 @@ static inline int ToConstantVariant(int value)
pDesc->m_Hooks.AddToTail(pHook); \ pDesc->m_Hooks.AddToTail(pHook); \
} }
// Static hooks (or "global" hooks) are not tied to specific classes
#define END_SCRIPTHOOK_STATIC( pVM ) \
pVM->RegisterHook( pHook ); \
}
#define ScriptRegisterSimpleHook( pVM, hook, hookName, returnType, description ) \
if (!hook.m_bDefined) \
{ \
ScriptHook_t *pHook = &hook; \
pHook->m_desc.m_pszScriptName = hookName; pHook->m_desc.m_pszFunction = #hook; pHook->m_desc.m_ReturnType = returnType; pHook->m_desc.m_pszDescription = description; \
pVM->RegisterHook( pHook ); \
}
#define ScriptRegisterConstant( pVM, constant, description ) ScriptRegisterConstantNamed( pVM, constant, #constant, description )
#define ScriptRegisterConstantNamed( pVM, constant, scriptName, description ) do { static ScriptConstantBinding_t binding; binding.m_pszScriptName = scriptName; binding.m_pszDescription = description; binding.m_data = ToConstantVariant(constant); pVM->RegisterConstant( &binding ); } while (0)
#define DEFINE_MEMBERVAR( varName, returnType, description ) \ #define DEFINE_MEMBERVAR( varName, returnType, description ) \
do { ScriptMemberDesc_t *pBinding = &((pDesc)->m_Members[(pDesc)->m_Members.AddToTail()]); pBinding->m_pszScriptName = varName; pBinding->m_pszDescription = description; pBinding->m_ReturnType = returnType; } while (0); do { ScriptMemberDesc_t *pBinding = &((pDesc)->m_Members[(pDesc)->m_Members.AddToTail()]); pBinding->m_pszScriptName = varName; pBinding->m_pszDescription = description; pBinding->m_ReturnType = returnType; } while (0);
#endif #endif

View File

@ -43,6 +43,9 @@ extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
extern int vscript_token; extern int vscript_token;
int vscript_token_hack = vscript_token; int vscript_token_hack = vscript_token;
// HACKHACK: VScript library relies on developer convar existing
ConVar developer( "developer", "1", 0, "Set developer message level." ); // developer mode
HSCRIPT VScriptCompileScript( const char *pszScriptName, bool bWarnMissing ) HSCRIPT VScriptCompileScript( const char *pszScriptName, bool bWarnMissing )
{ {
if ( !g_pScriptVM ) if ( !g_pScriptVM )

View File

@ -2350,7 +2350,11 @@ ScriptStatus_t SquirrelVM::ExecuteFunction(HSCRIPT hFunction, ScriptVariant_t* p
bool SquirrelVM::ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) bool SquirrelVM::ScopeIsHooked( HSCRIPT hScope, const char *pszEventName )
{ {
Assert( hScope && hScope != INVALID_HSCRIPT ); // For now, assume null scope (which is used for global hooks) is always hooked
if (!hScope)
return true;
Assert(hScope != INVALID_HSCRIPT);
sq_pushroottable(vm_); sq_pushroottable(vm_);
sq_pushstring(vm_, "Hooks", -1); sq_pushstring(vm_, "Hooks", -1);
@ -2375,7 +2379,7 @@ bool SquirrelVM::ScopeIsHooked( HSCRIPT hScope, const char *pszEventName )
HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope, bool &bLegacy) HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope, bool &bLegacy)
{ {
HSCRIPT hFunc = LookupFunction( pszEventName, hScope ); HSCRIPT hFunc = hScope ? LookupFunction( pszEventName, hScope ) : nullptr;
if (hFunc) if (hFunc)
{ {
bLegacy = true; bLegacy = true;
@ -2421,7 +2425,11 @@ ScriptStatus_t SquirrelVM::ExecuteHookFunction(const char *pszEventName, HSCRIPT
// TODO: Run in hook scope // TODO: Run in hook scope
sq_pushroottable(vm_); sq_pushroottable(vm_);
if (hScope)
sq_pushobject(vm_, *((HSQOBJECT*)hScope)); sq_pushobject(vm_, *((HSQOBJECT*)hScope));
else
sq_pushnull(vm_); // global hook
sq_pushstring(vm_, pszEventName, -1); sq_pushstring(vm_, pszEventName, -1);
for (int i = 0; i < nArgs; ++i) for (int i = 0; i < nArgs; ++i)

View File

@ -122,8 +122,6 @@ class CSimpleCallChainer
chain = null; chain = null;
} }
local developer = (delete developer)()
//--------------------------------------------------------- //---------------------------------------------------------
// Hook handler // Hook handler
//--------------------------------------------------------- //---------------------------------------------------------
@ -199,7 +197,26 @@ Hooks <-
{ {
local firstReturn = null local firstReturn = null
if ( scope in s_List ) if ( scope == null )
{
// null scope = global hook; call all scopes
vargv.insert(0,this)
foreach ( t in s_List )
{
if ( event in t )
{
foreach( context, callback in t[event] )
{
//printf( "(%.4f) Calling hook '%s' of context '%s' in static iteration\n", Time(), event, context )
local curReturn = callback.acall(vargv)
if (firstReturn == null)
firstReturn = curReturn
}
}
}
}
else if ( scope in s_List )
{ {
local t = s_List[scope] local t = s_List[scope]
if ( event in t ) if ( event in t )
@ -236,22 +253,16 @@ Hooks <-
//--------------------------------------------------------- //---------------------------------------------------------
__Documentation <- {} __Documentation <- {}
local DocumentedFuncs local developer = (delete developer)()
local DocumentedClasses
local DocumentedEnums
local DocumentedConsts
local DocumentedHooks
local DocumentedMembers
if (developer) if (developer)
{ {
DocumentedFuncs = {} local DocumentedFuncs = {}
DocumentedClasses = {} local DocumentedClasses = {}
DocumentedEnums = {} local DocumentedEnums = {}
DocumentedConsts = {} local DocumentedConsts = {}
DocumentedHooks = {} local DocumentedHooks = {}
DocumentedMembers = {} local DocumentedMembers = {}
}
local function AddAliasedToTable(name, signature, description, table) local function AddAliasedToTable(name, signature, description, table)
{ {
@ -271,9 +282,6 @@ local function AddAliasedToTable(name, signature, description, table)
function __Documentation::RegisterHelp(name, signature, description) function __Documentation::RegisterHelp(name, signature, description)
{ {
if ( !developer )
return
if (description.len() && description[0] == '#') if (description.len() && description[0] == '#')
{ {
AddAliasedToTable(name, signature, description, DocumentedFuncs) AddAliasedToTable(name, signature, description, DocumentedFuncs)
@ -286,25 +294,16 @@ function __Documentation::RegisterHelp(name, signature, description)
function __Documentation::RegisterClassHelp(name, baseclass, description) function __Documentation::RegisterClassHelp(name, baseclass, description)
{ {
if ( !developer )
return
DocumentedClasses[name] <- [baseclass, description]; DocumentedClasses[name] <- [baseclass, description];
} }
function __Documentation::RegisterEnumHelp(name, num_elements, description) function __Documentation::RegisterEnumHelp(name, num_elements, description)
{ {
if ( !developer )
return
DocumentedEnums[name] <- [num_elements, description]; DocumentedEnums[name] <- [num_elements, description];
} }
function __Documentation::RegisterConstHelp(name, signature, description) function __Documentation::RegisterConstHelp(name, signature, description)
{ {
if ( !developer )
return
if (description.len() && description[0] == '#') if (description.len() && description[0] == '#')
{ {
AddAliasedToTable(name, signature, description, DocumentedConsts) AddAliasedToTable(name, signature, description, DocumentedConsts)
@ -317,17 +316,11 @@ function __Documentation::RegisterConstHelp(name, signature, description)
function __Documentation::RegisterHookHelp(name, signature, description) function __Documentation::RegisterHookHelp(name, signature, description)
{ {
if ( !developer )
return
DocumentedHooks[name] <- [signature, description]; DocumentedHooks[name] <- [signature, description];
} }
function __Documentation::RegisterMemberHelp(name, signature, description) function __Documentation::RegisterMemberHelp(name, signature, description)
{ {
if ( !developer )
return
DocumentedMembers[name] <- [signature, description]; DocumentedMembers[name] <- [signature, description];
} }
@ -457,12 +450,6 @@ local function PrintMatchesInDocList(pattern, list, printfunc)
function __Documentation::PrintHelp(pattern = "*") function __Documentation::PrintHelp(pattern = "*")
{ {
if ( !developer )
{
printdocl("Documentation is not enabled. To enable documentation, restart the server with the 'developer' cvar set to 1 or higher.");
return
}
local patternLower = pattern.tolower(); local patternLower = pattern.tolower();
// Have a specific order // Have a specific order
@ -478,6 +465,21 @@ function __Documentation::PrintHelp(pattern = "*")
printdocl("Pattern " + pattern + " not found"); printdocl("Pattern " + pattern + " not found");
} }
} }
}
else
{
__Documentation.RegisterHelp <-
__Documentation.RegisterClassHelp <-
__Documentation.RegisterEnumHelp <-
__Documentation.RegisterConstHelp <-
__Documentation.RegisterHookHelp <-
__Documentation.RegisterMemberHelp <- dummy
function __Documentation::PrintHelp( pattern = null )
{
printcl(200, 224, 255, "Documentation is not enabled. To enable documentation, restart the server with the 'developer' cvar set to 1 or higher.");
}
}
// Vector documentation // Vector documentation
__Documentation.RegisterClassHelp( "Vector", "", "Basic 3-float Vector class." ); __Documentation.RegisterClassHelp( "Vector", "", "Basic 3-float Vector class." );