Implement CScriptHookManager

This commit is contained in:
samisalreadytaken 2022-07-18 23:58:29 +03:00
parent 22f0b2c3cc
commit 6e6bb4d639
7 changed files with 349 additions and 87 deletions

View File

@ -114,7 +114,7 @@ public:
void OnEntityCreated( CBaseEntity *pEntity ) void OnEntityCreated( CBaseEntity *pEntity )
{ {
if ( g_pScriptVM ) if ( g_pScriptVM && GetScriptHookManager().IsEventHooked( "OnEntityCreated" ) )
{ {
// entity // entity
ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) };
@ -124,7 +124,7 @@ public:
void OnEntityDeleted( CBaseEntity *pEntity ) void OnEntityDeleted( CBaseEntity *pEntity )
{ {
if ( g_pScriptVM ) if ( g_pScriptVM && GetScriptHookManager().IsEventHooked( "OnEntityDeleted" ) )
{ {
// entity // entity
ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) };
@ -645,6 +645,11 @@ bool VScriptClientInit()
#else #else
Log( "VSCRIPT: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() ); Log( "VSCRIPT: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() );
#endif #endif
#ifdef MAPBASE_VSCRIPT
GetScriptHookManager().OnInit();
#endif
ScriptRegisterFunction( g_pScriptVM, GetMapName, "Get the name of the map."); ScriptRegisterFunction( g_pScriptVM, GetMapName, "Get the name of the map.");
ScriptRegisterFunction( g_pScriptVM, Time, "Get the current server time" ); ScriptRegisterFunction( g_pScriptVM, Time, "Get the current server time" );
ScriptRegisterFunction( g_pScriptVM, DoUniqueString, SCRIPT_ALIAS( "UniqueString", "Generate a string guaranteed to be unique across the life of the script VM, with an optional root string." ) ); ScriptRegisterFunction( g_pScriptVM, DoUniqueString, SCRIPT_ALIAS( "UniqueString", "Generate a string guaranteed to be unique across the life of the script VM, with an optional root string." ) );
@ -770,6 +775,8 @@ public:
{ {
#ifdef MAPBASE_VSCRIPT #ifdef MAPBASE_VSCRIPT
g_ScriptNetMsg->LevelShutdownPreVM(); g_ScriptNetMsg->LevelShutdownPreVM();
GetScriptHookManager().OnShutdown();
#endif #endif
VScriptClientTerm(); VScriptClientTerm();
} }

View File

@ -154,7 +154,7 @@ public:
void OnEntityCreated( CBaseEntity *pEntity ) void OnEntityCreated( CBaseEntity *pEntity )
{ {
if ( g_pScriptVM ) if ( g_pScriptVM && GetScriptHookManager().IsEventHooked( "OnEntityCreated" ) )
{ {
// entity // entity
ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) };
@ -164,7 +164,7 @@ public:
void OnEntitySpawned( CBaseEntity *pEntity ) void OnEntitySpawned( CBaseEntity *pEntity )
{ {
if ( g_pScriptVM ) if ( g_pScriptVM && GetScriptHookManager().IsEventHooked( "OnEntitySpawned" ) )
{ {
// entity // entity
ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) };
@ -174,7 +174,7 @@ public:
void OnEntityDeleted( CBaseEntity *pEntity ) void OnEntityDeleted( CBaseEntity *pEntity )
{ {
if ( g_pScriptVM ) if ( g_pScriptVM && GetScriptHookManager().IsEventHooked( "OnEntityDeleted" ) )
{ {
// entity // entity
ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) };
@ -600,6 +600,10 @@ bool VScriptServerInit()
Log( "VSCRIPT: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() ); Log( "VSCRIPT: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() );
#endif #endif
#ifdef MAPBASE_VSCRIPT
GetScriptHookManager().OnInit();
#endif
#ifdef MAPBASE_VSCRIPT #ifdef MAPBASE_VSCRIPT
// MULTIPLAYER // MULTIPLAYER
// ScriptRegisterFunctionNamed( g_pScriptVM, UTIL_PlayerByIndex, "GetPlayerByIndex", "PlayerInstanceFromIndex" ); // ScriptRegisterFunctionNamed( g_pScriptVM, UTIL_PlayerByIndex, "GetPlayerByIndex", "PlayerInstanceFromIndex" );
@ -836,6 +840,8 @@ public:
{ {
#ifdef MAPBASE_VSCRIPT #ifdef MAPBASE_VSCRIPT
g_ScriptNetMsg->LevelShutdownPreVM(); g_ScriptNetMsg->LevelShutdownPreVM();
GetScriptHookManager().OnShutdown();
#endif #endif
VScriptServerTerm(); VScriptServerTerm();
} }

View File

@ -872,7 +872,8 @@ public: // IGameSystem
{ {
if ( g_pScriptVM ) if ( g_pScriptVM )
{ {
g_Hook_OnSave.Call( NULL, NULL, NULL ); if ( GetScriptHookManager().IsEventHooked( "OnSave" ) )
g_Hook_OnSave.Call( NULL, NULL, NULL );
// Legacy hook // Legacy hook
HSCRIPT hFunc = g_pScriptVM->LookupFunction( "OnSave" ); HSCRIPT hFunc = g_pScriptVM->LookupFunction( "OnSave" );
@ -893,7 +894,8 @@ public: // IGameSystem
{ {
if ( g_pScriptVM ) if ( g_pScriptVM )
{ {
g_Hook_OnRestore.Call( NULL, NULL, NULL ); if ( GetScriptHookManager().IsEventHooked( "OnRestore" ) )
g_Hook_OnRestore.Call( NULL, NULL, NULL );
// Legacy hook // Legacy hook
HSCRIPT hFunc = g_pScriptVM->LookupFunction( "OnRestore" ); HSCRIPT hFunc = g_pScriptVM->LookupFunction( "OnRestore" );

View File

@ -451,6 +451,10 @@ public:
} }
m_InstanceMap.Purge(); m_InstanceMap.Purge();
#ifdef MAPBASE_VSCRIPT
GetScriptHookManager().OnRestore();
#endif
#if defined(MAPBASE_VSCRIPT) && defined(CLIENT_DLL) #if defined(MAPBASE_VSCRIPT) && defined(CLIENT_DLL)
VScriptSaveRestoreUtil_OnVMRestore(); VScriptSaveRestoreUtil_OnVMRestore();
#endif #endif

View File

@ -98,6 +98,9 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "utlmap.h"
#include "utlvector.h"
#include "platform.h" #include "platform.h"
#include "datamap.h" #include "datamap.h"
#include "appframework/IAppSystem.h" #include "appframework/IAppSystem.h"
@ -137,6 +140,8 @@ class KeyValues;
// This has been moved up a bit for IScriptManager // This has been moved up a bit for IScriptManager
DECLARE_POINTER_HANDLE( HSCRIPT ); DECLARE_POINTER_HANDLE( HSCRIPT );
#define INVALID_HSCRIPT ((HSCRIPT)-1) #define INVALID_HSCRIPT ((HSCRIPT)-1)
typedef unsigned int HScriptRaw;
#endif #endif
enum ScriptLanguage_t enum ScriptLanguage_t
@ -885,8 +890,9 @@ public:
//-------------------------------------------------------- //--------------------------------------------------------
// Hooks // Hooks
//-------------------------------------------------------- //--------------------------------------------------------
virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope ) = 0; // Persistent unique identifier for an HSCRIPT variable
virtual ScriptStatus_t ExecuteHookFunction( HSCRIPT hFunction, const char *pszEventName, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) = 0; virtual HScriptRaw HScriptToRaw( HSCRIPT val ) = 0;
virtual ScriptStatus_t ExecuteHookFunction( const char *pszEventName, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) = 0;
#endif #endif
//-------------------------------------------------------- //--------------------------------------------------------
@ -1586,6 +1592,291 @@ typedef CScriptScopeT<> CScriptScope;
#define VScriptAddEnumToRoot( enumVal ) g_pScriptVM->SetValue( #enumVal, (int)enumVal ) #define VScriptAddEnumToRoot( enumVal ) g_pScriptVM->SetValue( #enumVal, (int)enumVal )
#ifdef MAPBASE_VSCRIPT #ifdef MAPBASE_VSCRIPT
//
// Map pointer iteration
//
#define FOR_EACH_MAP_PTR( mapName, iteratorName ) \
for ( int iteratorName = (mapName)->FirstInorder(); (mapName)->IsUtlMap && iteratorName != (mapName)->InvalidIndex(); iteratorName = (mapName)->NextInorder( iteratorName ) )
#define FOR_EACH_MAP_PTR_FAST( mapName, iteratorName ) \
for ( int iteratorName = 0; (mapName)->IsUtlMap && iteratorName < (mapName)->MaxElement(); ++iteratorName ) if ( !(mapName)->IsValidIndex( iteratorName ) ) continue; else
#define FOR_EACH_VEC_PTR( vecName, iteratorName ) \
for ( int iteratorName = 0; iteratorName < (vecName)->Count(); iteratorName++ )
//-----------------------------------------------------------------------------
//
// Keeps track of which events and scopes are hooked without polling this from the script VM on each request.
// Local cache is updated each time there is a change to script hooks: on Add, on Remove, on game restore
//
//-----------------------------------------------------------------------------
class CScriptHookManager
{
private:
typedef CUtlVector< char* > contextmap_t;
typedef CUtlMap< HScriptRaw, contextmap_t* > scopemap_t;
typedef CUtlMap< char*, scopemap_t* > hookmap_t;
HSCRIPT m_hfnHookFunc;
// { [string event], { [HSCRIPT scope], { [string context], [HSCRIPT callback] } } }
hookmap_t m_HookList;
public:
CScriptHookManager() : m_HookList( DefLessFunc(char*) ), m_hfnHookFunc(NULL)
{
}
HSCRIPT GetHookFunction()
{
return m_hfnHookFunc;
}
// For global hooks
bool IsEventHooked( const char *szEvent )
{
return m_HookList.Find( const_cast< char* >( szEvent ) ) != m_HookList.InvalidIndex();
}
bool IsEventHookedInScope( const char *szEvent, HSCRIPT hScope )
{
extern IScriptVM *g_pScriptVM;
Assert( hScope );
int eventIdx = m_HookList.Find( const_cast< char* >( szEvent ) );
if ( eventIdx == m_HookList.InvalidIndex() )
return false;
scopemap_t *scopeMap = m_HookList.Element( eventIdx );
return scopeMap->Find( g_pScriptVM->HScriptToRaw( hScope ) ) != scopeMap->InvalidIndex();
}
static void __UpdateScriptHooks( HSCRIPT hooksList )
{
extern CScriptHookManager &GetScriptHookManager();
GetScriptHookManager().Update( hooksList );
}
//
// On VM init, registers script func and caches the hook func.
//
void OnInit()
{
extern IScriptVM *g_pScriptVM;
ScriptRegisterFunctionNamed( g_pScriptVM, __UpdateScriptHooks, "__UpdateScriptHooks", SCRIPT_HIDE );
ScriptVariant_t hHooks;
g_pScriptVM->GetValue( "Hooks", &hHooks );
Assert( hHooks.m_type == FIELD_HSCRIPT );
if ( hHooks.m_type == FIELD_HSCRIPT )
{
m_hfnHookFunc = g_pScriptVM->LookupFunction( "Call", hHooks );
}
Clear();
}
//
// On VM shutdown, clear the cache.
// Not exactly necessary, as the cache will be cleared on VM init next time.
//
void OnShutdown()
{
extern IScriptVM *g_pScriptVM;
if ( m_hfnHookFunc )
g_pScriptVM->ReleaseFunction( m_hfnHookFunc );
m_hfnHookFunc = NULL;
Clear();
}
//
// On VM restore, update local cache.
//
void OnRestore()
{
extern IScriptVM *g_pScriptVM;
ScriptVariant_t hHooks;
g_pScriptVM->GetValue( "Hooks", &hHooks );
if ( hHooks.m_type == FIELD_HSCRIPT )
{
// Existing m_hfnHookFunc is invalid
m_hfnHookFunc = g_pScriptVM->LookupFunction( "Call", hHooks );
HSCRIPT func = g_pScriptVM->LookupFunction( "__UpdateHooks", hHooks );
g_pScriptVM->Call( func );
g_pScriptVM->ReleaseFunction( func );
g_pScriptVM->ReleaseValue( hHooks );
}
}
//
// Clear local cache.
//
void Clear()
{
if ( m_HookList.Count() )
{
FOR_EACH_MAP_FAST( m_HookList, i )
{
scopemap_t *scopeMap = m_HookList.Element(i);
FOR_EACH_MAP_PTR_FAST( scopeMap, j )
{
contextmap_t *contextMap = scopeMap->Element(j);
contextMap->PurgeAndDeleteElements();
}
char *szEvent = m_HookList.Key(i);
free( szEvent );
scopeMap->PurgeAndDeleteElements();
}
m_HookList.PurgeAndDeleteElements();
}
}
//
// Called from script, update local cache.
//
void Update( HSCRIPT hooksList )
{
extern IScriptVM *g_pScriptVM;
// Rebuild from scratch
Clear();
{
ScriptVariant_t varEvent, varScopeMap;
int it = -1;
while ( ( it = g_pScriptVM->GetKeyValue( hooksList, it, &varEvent, &varScopeMap ) ) != -1 )
{
// types are checked in script
Assert( varEvent.m_type == FIELD_CSTRING );
Assert( varScopeMap.m_type == FIELD_HSCRIPT );
scopemap_t *scopeMap;
int eventIdx = m_HookList.Find( const_cast< char* >( varEvent.m_pszString ) );
if ( eventIdx != m_HookList.InvalidIndex() )
{
scopeMap = m_HookList.Element( eventIdx );
}
else
{
scopeMap = new scopemap_t( DefLessFunc(HScriptRaw) );
m_HookList.Insert( strdup( varEvent.m_pszString ), scopeMap );
}
ScriptVariant_t varScope, varContextMap;
int it2 = -1;
while ( ( it2 = g_pScriptVM->GetKeyValue( varScopeMap, it2, &varScope, &varContextMap ) ) != -1 )
{
Assert( varScope.m_type == FIELD_HSCRIPT );
Assert( varContextMap.m_type == FIELD_HSCRIPT);
contextmap_t *contextMap;
int scopeIdx = scopeMap->Find( g_pScriptVM->HScriptToRaw( varScope.m_hScript ) );
if ( scopeIdx != scopeMap->InvalidIndex() )
{
contextMap = scopeMap->Element( scopeIdx );
}
else
{
contextMap = new contextmap_t();
scopeMap->Insert( g_pScriptVM->HScriptToRaw( varScope.m_hScript ), contextMap );
}
ScriptVariant_t varContext, varCallback;
int it3 = -1;
while ( ( it3 = g_pScriptVM->GetKeyValue( varContextMap, it3, &varContext, &varCallback ) ) != -1 )
{
Assert( varContext.m_type == FIELD_CSTRING );
Assert( varCallback.m_type == FIELD_HSCRIPT );
bool skip = false;
FOR_EACH_VEC_PTR( contextMap, k )
{
char *szContext = contextMap->Element(k);
if ( V_strcmp( szContext, varContext.m_pszString ) == 0 )
{
skip = true;
break;
}
}
if ( !skip )
contextMap->AddToTail( strdup( varContext.m_pszString ) );
g_pScriptVM->ReleaseValue( varContext );
g_pScriptVM->ReleaseValue( varCallback );
}
g_pScriptVM->ReleaseValue( varScope );
g_pScriptVM->ReleaseValue( varContextMap );
}
g_pScriptVM->ReleaseValue( varEvent );
g_pScriptVM->ReleaseValue( varScopeMap );
}
}
}
#ifdef _DEBUG
void Dump()
{
extern IScriptVM *g_pScriptVM;
FOR_EACH_MAP( m_HookList, i )
{
scopemap_t *scopeMap = m_HookList.Element(i);
char *szEvent = m_HookList.Key(i);
Msg( "%s [%x]\n", szEvent, (void*)scopeMap );
Msg( "{\n" );
FOR_EACH_MAP_PTR( scopeMap, j )
{
HScriptRaw hScope = scopeMap->Key(j);
contextmap_t *contextMap = scopeMap->Element(j);
Msg( "\t(0x%X) [%x]\n", hScope, (void*)contextMap );
Msg( "\t{\n" );
FOR_EACH_VEC_PTR( contextMap, k )
{
char *szContext = contextMap->Element(k);
Msg( "\t\t%-.50s\n", szContext );
}
Msg( "\t}\n" );
}
Msg( "}\n" );
}
}
#endif
};
inline CScriptHookManager &GetScriptHookManager()
{
static CScriptHookManager g_ScriptHookManager;
return g_ScriptHookManager;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Function bindings allow script functions to run C++ functions. // Function bindings allow script functions to run C++ functions.
// Hooks allow C++ functions to run script functions. // Hooks allow C++ functions to run script functions.
@ -1610,10 +1901,8 @@ struct ScriptHook_t
// Only valid between CanRunInScope() and Call() // Only valid between CanRunInScope() and Call()
HSCRIPT m_hFunc; HSCRIPT m_hFunc;
bool m_bLegacy;
ScriptHook_t() : ScriptHook_t() :
m_bLegacy(false),
m_hFunc(NULL) m_hFunc(NULL)
{ {
} }
@ -1633,20 +1922,17 @@ struct ScriptHook_t
// 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
bool CanRunInScope( HSCRIPT hScope ) bool CanRunInScope( HSCRIPT hScope )
{ {
// For now, assume null scope (which is used for global hooks) is always hooked
if ( !hScope || GetScriptHookManager().IsEventHookedInScope( m_desc.m_pszScriptName, hScope ) )
{
m_hFunc = NULL;
return true;
}
extern IScriptVM *g_pScriptVM; extern IScriptVM *g_pScriptVM;
// Check the hook system first to make sure an unintended function in the script scope does not cancel out all script hooks. // Legacy support if the new system is not being used
m_hFunc = g_pScriptVM->LookupHookFunction( m_desc.m_pszScriptName, hScope ); m_hFunc = g_pScriptVM->LookupFunction( m_desc.m_pszScriptName, hScope );
if ( !m_hFunc )
{
// Legacy support if the new system is not being used
m_hFunc = g_pScriptVM->LookupFunction( m_desc.m_pszScriptName, hScope );
m_bLegacy = true;
}
else
{
m_bLegacy = false;
}
return !!m_hFunc; return !!m_hFunc;
} }
@ -1661,10 +1947,8 @@ struct ScriptHook_t
Assert( CanRunInScope( hScope ) ); Assert( CanRunInScope( hScope ) );
// Legacy // Legacy
if ( m_bLegacy ) if ( m_hFunc )
{ {
Assert( m_hFunc );
for (int i = 0; i < m_desc.m_Parameters.Count(); i++) for (int i = 0; i < m_desc.m_Parameters.Count(); i++)
{ {
g_pScriptVM->SetValue( m_pszParameterNames[i], pArgs[i] ); g_pScriptVM->SetValue( m_pszParameterNames[i], pArgs[i] );
@ -1686,12 +1970,7 @@ struct ScriptHook_t
// New Hook System // New Hook System
else else
{ {
ScriptStatus_t status = g_pScriptVM->ExecuteHookFunction( m_hFunc, m_desc.m_pszScriptName, pArgs, m_desc.m_Parameters.Count(), pReturn, hScope, true ); ScriptStatus_t status = g_pScriptVM->ExecuteHookFunction( m_desc.m_pszScriptName, pArgs, m_desc.m_Parameters.Count(), pReturn, hScope, true );
if ( bRelease )
g_pScriptVM->ReleaseFunction( m_hFunc );
m_hFunc = NULL;
return status == SCRIPT_DONE; return status == SCRIPT_DONE;
} }
} }

View File

@ -188,8 +188,8 @@ public:
//-------------------------------------------------------- //--------------------------------------------------------
// Hooks // Hooks
//-------------------------------------------------------- //--------------------------------------------------------
virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope ) override; virtual HScriptRaw HScriptToRaw( HSCRIPT val ) override;
virtual ScriptStatus_t ExecuteHookFunction( HSCRIPT hFunction, const char *pszEventName, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) override; virtual ScriptStatus_t ExecuteHookFunction( const char *pszEventName, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) override;
//-------------------------------------------------------- //--------------------------------------------------------
// External functions // External functions
@ -2347,64 +2347,24 @@ ScriptStatus_t SquirrelVM::ExecuteFunction(HSCRIPT hFunction, ScriptVariant_t* p
return SCRIPT_DONE; return SCRIPT_DONE;
} }
HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope) HScriptRaw SquirrelVM::HScriptToRaw( HSCRIPT val )
{ {
SquirrelSafeCheck safeCheck(vm_); Assert( val );
Assert( val != INVALID_HSCRIPT );
// For now, assume null scope (which is used for global hooks) is always hooked HSQOBJECT *obj = (HSQOBJECT*)val;
if ( hScope ) #if 0
{ if ( sq_isweakref(*obj) )
Assert( hScope != INVALID_HSCRIPT ); return obj->_unVal.pWeakRef->_obj._unVal.raw;
#endif
sq_pushroottable(vm_); return obj->_unVal.raw;
sq_pushstring(vm_, "Hooks", -1);
sq_get(vm_, -2);
sq_pushstring(vm_, "IsEventHookedInScope", -1);
sq_get(vm_, -2);
sq_push(vm_, -2);
sq_pushstring(vm_, pszEventName, -1);
sq_pushobject(vm_, *((HSQOBJECT*)hScope));
sq_call(vm_, 3, SQTrue, SQTrue);
SQBool val;
if (SQ_FAILED(sq_getbool(vm_, -1, &val)))
{
sq_pop(vm_, 3);
return nullptr;
}
sq_pop(vm_, 4);
if (!val)
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_, 3);
HSQOBJECT* pObj = new HSQOBJECT;
*pObj = obj;
return (HSCRIPT)pObj;
} }
ScriptStatus_t SquirrelVM::ExecuteHookFunction(HSCRIPT hFunction, const char *pszEventName, ScriptVariant_t* pArgs, int nArgs, ScriptVariant_t* pReturn, HSCRIPT hScope, bool bWait) ScriptStatus_t SquirrelVM::ExecuteHookFunction(const char *pszEventName, ScriptVariant_t* pArgs, int nArgs, ScriptVariant_t* pReturn, HSCRIPT hScope, bool bWait)
{ {
if ( !hFunction )
return SCRIPT_ERROR;
SquirrelSafeCheck safeCheck(vm_); SquirrelSafeCheck safeCheck(vm_);
HSQOBJECT* pFunc = (HSQOBJECT*)hFunction; HSQOBJECT* pFunc = (HSQOBJECT*)GetScriptHookManager().GetHookFunction();
sq_pushobject(vm_, *pFunc); sq_pushobject(vm_, *pFunc);
// The call environment of the Hooks::Call function does not matter // The call environment of the Hooks::Call function does not matter

View File

@ -180,6 +180,8 @@ Hooks <-
t[scope] <- {}; t[scope] <- {};
t[scope][context] <- callback; t[scope][context] <- callback;
return __UpdateHooks();
} }
function Remove( event, context ) function Remove( event, context )
@ -244,6 +246,8 @@ Hooks <-
delete s_List[ev]; delete s_List[ev];
} }
} }
return __UpdateHooks();
} }
function Call( event, scope, ... ) function Call( event, scope, ... )
@ -287,9 +291,9 @@ Hooks <-
return firstReturn; return firstReturn;
} }
function IsEventHookedInScope( event, scope ) function __UpdateHooks()
{ {
return ( event in s_List ) && ( scope in s_List[event] ) return __UpdateScriptHooks( s_List );
} }
} }