mirror of
https://github.com/mapbase-source/source-sdk-2013.git
synced 2024-12-27 15:25:30 +03:00
Merge pull request #121 from mapbase-source/feature/vscript/hook-handler-prototype-1
Flexible hook handler
This commit is contained in:
commit
0f2b08f238
@ -862,6 +862,15 @@ public:
|
|||||||
//--------------------------------------------------------
|
//--------------------------------------------------------
|
||||||
virtual ScriptStatus_t ExecuteFunction( HSCRIPT hFunction, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) = 0;
|
virtual ScriptStatus_t ExecuteFunction( HSCRIPT hFunction, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) = 0;
|
||||||
|
|
||||||
|
#ifdef MAPBASE_VSCRIPT
|
||||||
|
//--------------------------------------------------------
|
||||||
|
// Hooks
|
||||||
|
//--------------------------------------------------------
|
||||||
|
virtual bool ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) = 0;
|
||||||
|
virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope, bool &bLegacy ) = 0;
|
||||||
|
virtual ScriptStatus_t ExecuteHookFunction( const char *pszEventName, HSCRIPT hFunction, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------
|
//--------------------------------------------------------
|
||||||
// External functions
|
// External functions
|
||||||
//--------------------------------------------------------
|
//--------------------------------------------------------
|
||||||
@ -882,6 +891,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
|
||||||
|
|
||||||
//--------------------------------------------------------
|
//--------------------------------------------------------
|
||||||
@ -1589,12 +1603,13 @@ struct ScriptHook_t
|
|||||||
|
|
||||||
// Cached for when CanRunInScope() is called before Call()
|
// Cached for when CanRunInScope() is called before Call()
|
||||||
HSCRIPT m_hFunc;
|
HSCRIPT m_hFunc;
|
||||||
|
bool m_bLegacy;
|
||||||
|
|
||||||
// Checks if there's a function of this name which would run in this scope
|
// Checks if there's a function of this name which would run in this scope
|
||||||
HSCRIPT CanRunInScope( HSCRIPT hScope )
|
HSCRIPT CanRunInScope( HSCRIPT hScope )
|
||||||
{
|
{
|
||||||
extern IScriptVM *g_pScriptVM;
|
extern IScriptVM *g_pScriptVM;
|
||||||
m_hFunc = g_pScriptVM->LookupFunction( m_desc.m_pszScriptName, hScope );
|
m_hFunc = g_pScriptVM->LookupHookFunction( m_desc.m_pszScriptName, hScope, m_bLegacy );
|
||||||
return m_hFunc;
|
return m_hFunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1618,7 +1633,8 @@ struct ScriptHook_t
|
|||||||
// Make sure we have a function in this scope
|
// Make sure we have a function in this scope
|
||||||
if (!m_hFunc && !CanRunInScope(hScope))
|
if (!m_hFunc && !CanRunInScope(hScope))
|
||||||
return false;
|
return false;
|
||||||
else
|
// Legacy
|
||||||
|
else if (m_bLegacy)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_desc.m_Parameters.Count(); i++)
|
for (int i = 0; i < m_desc.m_Parameters.Count(); i++)
|
||||||
{
|
{
|
||||||
@ -1639,6 +1655,15 @@ struct ScriptHook_t
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// New Hook System
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_pScriptVM->ExecuteHookFunction( m_desc.m_pszScriptName, m_hFunc, pArgs, m_desc.m_Parameters.Count(), pReturn, hScope, true );
|
||||||
|
if (bRelease)
|
||||||
|
g_pScriptVM->ReleaseFunction( m_hFunc );
|
||||||
|
m_hFunc = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -185,6 +185,13 @@ public:
|
|||||||
//--------------------------------------------------------
|
//--------------------------------------------------------
|
||||||
virtual ScriptStatus_t ExecuteFunction(HSCRIPT hFunction, ScriptVariant_t* pArgs, int nArgs, ScriptVariant_t* pReturn, HSCRIPT hScope, bool bWait) override;
|
virtual ScriptStatus_t ExecuteFunction(HSCRIPT hFunction, ScriptVariant_t* pArgs, int nArgs, ScriptVariant_t* pReturn, HSCRIPT hScope, bool bWait) override;
|
||||||
|
|
||||||
|
//--------------------------------------------------------
|
||||||
|
// Hooks
|
||||||
|
//--------------------------------------------------------
|
||||||
|
virtual bool ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) override;
|
||||||
|
virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope, bool &bLegacy ) override;
|
||||||
|
virtual ScriptStatus_t ExecuteHookFunction( const char *pszEventName, HSCRIPT hFunction, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) override;
|
||||||
|
|
||||||
//--------------------------------------------------------
|
//--------------------------------------------------------
|
||||||
// External functions
|
// External functions
|
||||||
//--------------------------------------------------------
|
//--------------------------------------------------------
|
||||||
@ -204,6 +211,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.
|
||||||
@ -2336,6 +2348,110 @@ ScriptStatus_t SquirrelVM::ExecuteFunction(HSCRIPT hFunction, ScriptVariant_t* p
|
|||||||
return SCRIPT_DONE;
|
return SCRIPT_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SquirrelVM::ScopeIsHooked( HSCRIPT hScope, const char *pszEventName )
|
||||||
|
{
|
||||||
|
Assert( hScope && hScope != INVALID_HSCRIPT );
|
||||||
|
|
||||||
|
sq_pushroottable(vm_);
|
||||||
|
sq_pushstring(vm_, "Hooks", -1);
|
||||||
|
sq_get(vm_, -2);
|
||||||
|
sq_pushstring(vm_, "ScopeHookedToEvent", -1);
|
||||||
|
sq_get(vm_, -2);
|
||||||
|
sq_push(vm_, -2);
|
||||||
|
sq_pushobject(vm_, *((HSQOBJECT*)hScope));
|
||||||
|
sq_pushstring(vm_, pszEventName, -1);
|
||||||
|
sq_call(vm_, 3, SQTrue, SQTrue);
|
||||||
|
|
||||||
|
SQBool val;
|
||||||
|
if (SQ_FAILED(sq_getbool(vm_, -1, &val)))
|
||||||
|
{
|
||||||
|
sq_pop(vm_, 3);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sq_pop(vm_, 3);
|
||||||
|
return val ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope, bool &bLegacy)
|
||||||
|
{
|
||||||
|
HSCRIPT hFunc = LookupFunction( pszEventName, hScope );
|
||||||
|
if (hFunc)
|
||||||
|
{
|
||||||
|
bLegacy = true;
|
||||||
|
return hFunc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bLegacy = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ScopeIsHooked(hScope, pszEventName))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
sq_pushroottable(vm_);
|
||||||
|
sq_pushstring(vm_, "Hooks", -1);
|
||||||
|
sq_get(vm_, -2);
|
||||||
|
sq_pushstring(vm_, "Call", -1);
|
||||||
|
sq_get(vm_, -2);
|
||||||
|
|
||||||
|
HSQOBJECT obj;
|
||||||
|
sq_resetobject(&obj);
|
||||||
|
sq_getstackobj(vm_, -1, &obj);
|
||||||
|
sq_addref(vm_, &obj);
|
||||||
|
sq_pop(vm_, 2);
|
||||||
|
|
||||||
|
HSQOBJECT* pObj = new HSQOBJECT;
|
||||||
|
*pObj = obj;
|
||||||
|
return (HSCRIPT)pObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptStatus_t SquirrelVM::ExecuteHookFunction(const char *pszEventName, HSCRIPT hFunction, ScriptVariant_t* pArgs, int nArgs, ScriptVariant_t* pReturn, HSCRIPT hScope, bool bWait)
|
||||||
|
{
|
||||||
|
SquirrelSafeCheck safeCheck(vm_);
|
||||||
|
if (!hFunction)
|
||||||
|
return SCRIPT_ERROR;
|
||||||
|
|
||||||
|
if (hFunction == INVALID_HSCRIPT)
|
||||||
|
return SCRIPT_ERROR;
|
||||||
|
|
||||||
|
HSQOBJECT* pFunc = (HSQOBJECT*)hFunction;
|
||||||
|
sq_pushobject(vm_, *pFunc);
|
||||||
|
|
||||||
|
// TODO: Run in hook scope
|
||||||
|
sq_pushroottable(vm_);
|
||||||
|
|
||||||
|
sq_pushobject(vm_, *((HSQOBJECT*)hScope));
|
||||||
|
sq_pushstring(vm_, pszEventName, -1);
|
||||||
|
|
||||||
|
for (int i = 0; i < nArgs; ++i)
|
||||||
|
{
|
||||||
|
PushVariant(vm_, pArgs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasReturn = pReturn != nullptr;
|
||||||
|
|
||||||
|
if (SQ_FAILED(sq_call(vm_, nArgs + 3, hasReturn, SQTrue)))
|
||||||
|
{
|
||||||
|
sq_pop(vm_, 1);
|
||||||
|
return SCRIPT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasReturn)
|
||||||
|
{
|
||||||
|
if (!getVariant(vm_, -1, *pReturn))
|
||||||
|
{
|
||||||
|
sq_pop(vm_, 1);
|
||||||
|
return SCRIPT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
sq_pop(vm_, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
sq_pop(vm_, 1);
|
||||||
|
return SCRIPT_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
void SquirrelVM::RegisterFunction(ScriptFunctionBinding_t* pScriptFunction)
|
void SquirrelVM::RegisterFunction(ScriptFunctionBinding_t* pScriptFunction)
|
||||||
{
|
{
|
||||||
SquirrelSafeCheck safeCheck(vm_);
|
SquirrelSafeCheck safeCheck(vm_);
|
||||||
@ -2587,6 +2703,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_);
|
||||||
|
@ -124,6 +124,116 @@ class CSimpleCallChainer
|
|||||||
|
|
||||||
local developer = (delete developer)()
|
local developer = (delete developer)()
|
||||||
|
|
||||||
|
//---------------------------------------------------------
|
||||||
|
// Hook handler
|
||||||
|
//---------------------------------------------------------
|
||||||
|
local s_List = {}
|
||||||
|
|
||||||
|
Hooks <-
|
||||||
|
{
|
||||||
|
// table, string, closure, string
|
||||||
|
function Add( scope, event, callback, context )
|
||||||
|
{
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
function Remove( context, event = null )
|
||||||
|
{
|
||||||
|
if ( event )
|
||||||
|
{
|
||||||
|
foreach( k,scope in s_List )
|
||||||
|
{
|
||||||
|
if ( event in scope )
|
||||||
|
{
|
||||||
|
local t = scope[event]
|
||||||
|
if ( context in t )
|
||||||
|
{
|
||||||
|
delete t[context]
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup?
|
||||||
|
if ( !t.len() )
|
||||||
|
delete scope[event]
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup?
|
||||||
|
if ( !scope.len() )
|
||||||
|
delete s_List[k]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach( k,scope in s_List )
|
||||||
|
{
|
||||||
|
foreach( kk,ev in scope )
|
||||||
|
{
|
||||||
|
if ( context in ev )
|
||||||
|
{
|
||||||
|
delete ev[context]
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup?
|
||||||
|
if ( !ev.len() )
|
||||||
|
delete scope[kk]
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup?
|
||||||
|
if ( !scope.len() )
|
||||||
|
delete s_List[k]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Call( scope, event, ... )
|
||||||
|
{
|
||||||
|
local firstReturn = null
|
||||||
|
|
||||||
|
if ( scope in s_List )
|
||||||
|
{
|
||||||
|
local t = s_List[scope]
|
||||||
|
if ( event in t )
|
||||||
|
{
|
||||||
|
vargv.insert(0,scope)
|
||||||
|
foreach( context, callback in t[event] )
|
||||||
|
{
|
||||||
|
//printf( "(%.4f) Calling hook '%s' of context '%s'\n", Time(), event, context )
|
||||||
|
|
||||||
|
local curReturn = callback.acall(vargv)
|
||||||
|
if (firstReturn == null)
|
||||||
|
firstReturn = curReturn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return firstReturn
|
||||||
|
}
|
||||||
|
|
||||||
|
function ScopeHookedToEvent( scope, event )
|
||||||
|
{
|
||||||
|
if ( scope in s_List )
|
||||||
|
{
|
||||||
|
if (event in s_List[scope])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------
|
||||||
|
// Documentation
|
||||||
|
//---------------------------------------------------------
|
||||||
__Documentation <- {}
|
__Documentation <- {}
|
||||||
|
|
||||||
local DocumentedFuncs
|
local DocumentedFuncs
|
||||||
|
Loading…
Reference in New Issue
Block a user