Revisited hook handler based on suggestions and new information

This commit is contained in:
Blixibon 2021-05-09 11:34:38 -05:00
parent 38be2ca932
commit c37f8eefb7
3 changed files with 107 additions and 68 deletions

View File

@ -889,6 +889,11 @@ public:
// External enums // External enums
//-------------------------------------------------------- //--------------------------------------------------------
virtual void RegisterEnum( ScriptEnumDesc_t *pEnumDesc ) = 0; virtual void RegisterEnum( ScriptEnumDesc_t *pEnumDesc ) = 0;
//--------------------------------------------------------
// External hooks
//--------------------------------------------------------
virtual void RegisterHook( ScriptHook_t *pHookDesc ) = 0;
#endif #endif
//-------------------------------------------------------- //--------------------------------------------------------

View File

@ -187,6 +187,11 @@ public:
// External enums // External enums
//-------------------------------------------------------- //--------------------------------------------------------
virtual void RegisterEnum(ScriptEnumDesc_t *pEnumDesc) override; virtual void RegisterEnum(ScriptEnumDesc_t *pEnumDesc) override;
//--------------------------------------------------------
// External hooks
//--------------------------------------------------------
virtual void RegisterHook(ScriptHook_t *pHookDesc) override;
//-------------------------------------------------------- //--------------------------------------------------------
// External instances. Note class will be auto-registered. // External instances. Note class will be auto-registered.
@ -2299,7 +2304,7 @@ HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope,
sq_pushroottable(vm_); sq_pushroottable(vm_);
sq_pushstring(vm_, "Hooks", -1); sq_pushstring(vm_, "Hooks", -1);
sq_get(vm_, -2); sq_get(vm_, -2);
sq_pushstring(vm_, "CallHooks", -1); sq_pushstring(vm_, "Call", -1);
sq_get(vm_, -2); sq_get(vm_, -2);
HSQOBJECT obj; HSQOBJECT obj;
@ -2328,8 +2333,8 @@ ScriptStatus_t SquirrelVM::ExecuteHookFunction(const char *pszEventName, HSCRIPT
// TODO: Run in hook scope // TODO: Run in hook scope
sq_pushroottable(vm_); sq_pushroottable(vm_);
sq_pushstring(vm_, pszEventName, -1);
sq_pushobject(vm_, *((HSQOBJECT*)hScope)); sq_pushobject(vm_, *((HSQOBJECT*)hScope));
sq_pushstring(vm_, pszEventName, -1);
for (int i = 0; i < nArgs; ++i) for (int i = 0; i < nArgs; ++i)
{ {
@ -2602,6 +2607,17 @@ void SquirrelVM::RegisterEnum(ScriptEnumDesc_t* pEnumDesc)
RegisterEnumDocumentation(vm_, 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) HSCRIPT SquirrelVM::RegisterInstance(ScriptClassDesc_t* pDesc, void* pInstance, bool bAllowDestruct)
{ {
SquirrelSafeCheck safeCheck(vm_); SquirrelSafeCheck safeCheck(vm_);

View File

@ -125,89 +125,107 @@ class CSimpleCallChainer
//--------------------------------------------------------- //---------------------------------------------------------
// Hook handler // Hook handler
//--------------------------------------------------------- //---------------------------------------------------------
Hooks <- { Registered = {} } local s_List = {}
function Hooks::Add( scope, event, func, name ) Hooks <-
{ {
Hooks.Registered[name] <- [event, scope, func]; // table, string, closure, string
} function Add( scope, event, callback, context )
function Hooks::Remove( name )
{
Hooks.Registered.rawdelete(name);
}
function Hooks::ScopeHookedToEvent( scope, event )
{
//printl("Running ScopeHookedToEvent()")
foreach (elem in Hooks.Registered)
{ {
if (elem[1] == scope && elem[0] == event) if ( typeof callback != "function" )
return true 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, ...) function Remove( context, event = null )
{
//printl("vargv.len() = " + vargv.len())
switch (vargv.len())
{ {
case 0: if ( event )
foreach (elem in Hooks.Registered) {
foreach( k,scope in s_List )
{ {
if (elem[0] == event && elem[1] == scope) if ( event in scope )
return elem[2]() {
} local t = scope[event]
break; if ( context in t )
{
delete t[context]
}
case 1: // cleanup?
foreach (elem in Hooks.Registered) if ( !t.len() )
{ delete scope[event]
if (elem[0] == event && elem[1] == scope) }
return elem[2](vargv[0])
}
break;
case 2: // cleanup?
foreach (elem in Hooks.Registered) if ( !scope.len() )
{ delete s_List[k]
if (elem[0] == event && elem[1] == scope)
return elem[2](vargv[0], vargv[1])
} }
break; }
else
{
foreach( k,scope in s_List )
{
foreach( kk,ev in scope )
{
if ( context in ev )
{
delete ev[context]
}
case 3: // cleanup?
foreach (elem in Hooks.Registered) if ( !ev.len() )
{ delete scope[kk]
if (elem[0] == event && elem[1] == scope) }
return elem[2](vargv[0], vargv[1], vargv[2])
}
break;
case 4: // cleanup?
foreach (elem in Hooks.Registered) if ( !scope.len() )
{ delete s_List[k]
if (elem[0] == event && elem[1] == scope)
return elem[2](vargv[0], vargv[1], vargv[2], vargv[3])
} }
break; }
}
case 5: function Call( scope, event, ... )
foreach (elem in Hooks.Registered) {
{ local firstReturn = null
if (elem[0] == event && elem[1] == scope)
return elem[2](vargv[0], vargv[1], vargv[2], vargv[3], vargv[4])
}
break;
case 6: if ( scope in s_List )
foreach (elem in Hooks.Registered) {
local t = s_List[scope]
if ( event in t )
{ {
if (elem[0] == event && elem[1] == scope) foreach( context, callback in t[event] )
return elem[2](vargv[0], vargv[1], vargv[2], vargv[3], vargv[4], vargv[5]) {
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
} }
} }