From c37f8eefb7546d0486472b7d042b703844f4a208 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 9 May 2021 11:34:38 -0500 Subject: [PATCH] Revisited hook handler based on suggestions and new information --- sp/src/public/vscript/ivscript.h | 5 + sp/src/vscript/vscript_squirrel.cpp | 20 +++- sp/src/vscript/vscript_squirrel.nut | 150 ++++++++++++++++------------ 3 files changed, 107 insertions(+), 68 deletions(-) diff --git a/sp/src/public/vscript/ivscript.h b/sp/src/public/vscript/ivscript.h index a1f24ce6..9db7c106 100644 --- a/sp/src/public/vscript/ivscript.h +++ b/sp/src/public/vscript/ivscript.h @@ -889,6 +889,11 @@ public: // External enums //-------------------------------------------------------- virtual void RegisterEnum( ScriptEnumDesc_t *pEnumDesc ) = 0; + + //-------------------------------------------------------- + // External hooks + //-------------------------------------------------------- + virtual void RegisterHook( ScriptHook_t *pHookDesc ) = 0; #endif //-------------------------------------------------------- diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index cde074f0..a1ba928b 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -187,6 +187,11 @@ public: // External enums //-------------------------------------------------------- virtual void RegisterEnum(ScriptEnumDesc_t *pEnumDesc) override; + + //-------------------------------------------------------- + // External hooks + //-------------------------------------------------------- + virtual void RegisterHook(ScriptHook_t *pHookDesc) override; //-------------------------------------------------------- // External instances. Note class will be auto-registered. @@ -2299,7 +2304,7 @@ HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope, sq_pushroottable(vm_); sq_pushstring(vm_, "Hooks", -1); sq_get(vm_, -2); - sq_pushstring(vm_, "CallHooks", -1); + sq_pushstring(vm_, "Call", -1); sq_get(vm_, -2); HSQOBJECT obj; @@ -2328,8 +2333,8 @@ ScriptStatus_t SquirrelVM::ExecuteHookFunction(const char *pszEventName, HSCRIPT // TODO: Run in hook scope sq_pushroottable(vm_); - sq_pushstring(vm_, pszEventName, -1); sq_pushobject(vm_, *((HSQOBJECT*)hScope)); + sq_pushstring(vm_, pszEventName, -1); for (int i = 0; i < nArgs; ++i) { @@ -2602,6 +2607,17 @@ void SquirrelVM::RegisterEnum(ScriptEnumDesc_t* pEnumDesc) RegisterEnumDocumentation(vm_, pEnumDesc); } +void SquirrelVM::RegisterHook(ScriptHook_t* pHookDesc) +{ + SquirrelSafeCheck safeCheck(vm_); + Assert(pHookDesc); + + if (!pHookDesc) + return; + + RegisterHookDocumentation(vm_, pHookDesc, pHookDesc->m_desc, nullptr); +} + HSCRIPT SquirrelVM::RegisterInstance(ScriptClassDesc_t* pDesc, void* pInstance, bool bAllowDestruct) { SquirrelSafeCheck safeCheck(vm_); diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index 0c48bb87..8fa8fb58 100644 --- a/sp/src/vscript/vscript_squirrel.nut +++ b/sp/src/vscript/vscript_squirrel.nut @@ -125,89 +125,107 @@ class CSimpleCallChainer //--------------------------------------------------------- // Hook handler //--------------------------------------------------------- -Hooks <- { Registered = {} } +local s_List = {} -function Hooks::Add( scope, event, func, name ) +Hooks <- { - Hooks.Registered[name] <- [event, scope, func]; -} - -function Hooks::Remove( name ) -{ - Hooks.Registered.rawdelete(name); -} - -function Hooks::ScopeHookedToEvent( scope, event ) -{ - //printl("Running ScopeHookedToEvent()") - foreach (elem in Hooks.Registered) + // table, string, closure, string + function Add( scope, event, callback, context ) { - if (elem[1] == scope && elem[0] == event) - return true + if ( typeof callback != "function" ) + throw "invalid callback param" + + if ( !(scope in s_List) ) + s_List[scope] <- {} + + local t = s_List[scope] + + if ( !(event in t) ) + t[event] <- {} + + t[event][context] <- callback } - return false -} -function Hooks::CallHooks(event, scope, ...) -{ - //printl("vargv.len() = " + vargv.len()) - switch (vargv.len()) + function Remove( context, event = null ) { - case 0: - foreach (elem in Hooks.Registered) + if ( event ) + { + foreach( k,scope in s_List ) { - if (elem[0] == event && elem[1] == scope) - return elem[2]() - } - break; + if ( event in scope ) + { + local t = scope[event] + if ( context in t ) + { + delete t[context] + } - case 1: - foreach (elem in Hooks.Registered) - { - if (elem[0] == event && elem[1] == scope) - return elem[2](vargv[0]) - } - break; + // cleanup? + if ( !t.len() ) + delete scope[event] + } - case 2: - foreach (elem in Hooks.Registered) - { - if (elem[0] == event && elem[1] == scope) - return elem[2](vargv[0], vargv[1]) + // cleanup? + if ( !scope.len() ) + delete s_List[k] } - break; + } + else + { + foreach( k,scope in s_List ) + { + foreach( kk,ev in scope ) + { + if ( context in ev ) + { + delete ev[context] + } - case 3: - foreach (elem in Hooks.Registered) - { - if (elem[0] == event && elem[1] == scope) - return elem[2](vargv[0], vargv[1], vargv[2]) - } - break; + // cleanup? + if ( !ev.len() ) + delete scope[kk] + } - case 4: - foreach (elem in Hooks.Registered) - { - if (elem[0] == event && elem[1] == scope) - return elem[2](vargv[0], vargv[1], vargv[2], vargv[3]) + // cleanup? + if ( !scope.len() ) + delete s_List[k] } - break; + } + } - case 5: - foreach (elem in Hooks.Registered) - { - if (elem[0] == event && elem[1] == scope) - return elem[2](vargv[0], vargv[1], vargv[2], vargv[3], vargv[4]) - } - break; + function Call( scope, event, ... ) + { + local firstReturn = null - case 6: - foreach (elem in Hooks.Registered) + if ( scope in s_List ) + { + local t = s_List[scope] + if ( event in t ) { - if (elem[0] == event && elem[1] == scope) - return elem[2](vargv[0], vargv[1], vargv[2], vargv[3], vargv[4], vargv[5]) + foreach( context, callback in t[event] ) + { + printf( "(%.4f) Calling hook '%s' of context '%s'\n", Time(), event, context ) + vargv.insert(0,scope) + + local curReturn = callback.acall(vargv) + if (firstReturn == null) + firstReturn = curReturn + } } - break; + } + + return firstReturn + } + + function ScopeHookedToEvent( scope, event ) + { + if ( scope in s_List ) + { + if (event in s_List[scope]) + return true + } + + return false } }