Skip to content

Commit 22f0b2c

Browse files
Refactor script hook system
1 parent fca05c8 commit 22f0b2c

File tree

8 files changed

+186
-160
lines changed

8 files changed

+186
-160
lines changed

sp/src/game/client/c_baseentity.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1353,7 +1353,7 @@ void C_BaseEntity::Term()
13531353
if ( m_hScriptInstance )
13541354
{
13551355
#ifdef MAPBASE_VSCRIPT
1356-
if ( m_ScriptScope.IsInitialized() )
1356+
if ( m_ScriptScope.IsInitialized() && g_Hook_UpdateOnRemove.CanRunInScope( m_ScriptScope ) )
13571357
{
13581358
g_Hook_UpdateOnRemove.Call( m_ScriptScope, NULL, NULL );
13591359
}

sp/src/game/server/baseentity.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -2646,7 +2646,7 @@ void CBaseEntity::UpdateOnRemove( void )
26462646
if ( m_hScriptInstance )
26472647
{
26482648
#ifdef MAPBASE_VSCRIPT
2649-
if (m_ScriptScope.IsInitialized())
2649+
if ( m_ScriptScope.IsInitialized() && g_Hook_UpdateOnRemove.CanRunInScope( m_ScriptScope ) )
26502650
{
26512651
g_Hook_UpdateOnRemove.Call( m_ScriptScope, NULL, NULL );
26522652
}

sp/src/game/server/filters.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -2157,7 +2157,7 @@ class CFilterScript : public CBaseFilter
21572157
public:
21582158
bool PassesFilterImpl( CBaseEntity *pCaller, CBaseEntity *pEntity )
21592159
{
2160-
if (m_ScriptScope.IsInitialized())
2160+
if ( m_ScriptScope.IsInitialized() && g_Hook_PassesFilter.CanRunInScope( m_ScriptScope ) )
21612161
{
21622162
// caller, activator
21632163
ScriptVariant_t functionReturn;
@@ -2176,7 +2176,7 @@ class CFilterScript : public CBaseFilter
21762176

21772177
bool PassesDamageFilterImpl( CBaseEntity *pCaller, const CTakeDamageInfo &info )
21782178
{
2179-
if (m_ScriptScope.IsInitialized())
2179+
if ( m_ScriptScope.IsInitialized() && g_Hook_PassesDamageFilter.CanRunInScope( m_ScriptScope ) )
21802180
{
21812181
HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast<CTakeDamageInfo*>(&info) );
21822182

@@ -2201,7 +2201,7 @@ class CFilterScript : public CBaseFilter
22012201

22022202
bool PassesFinalDamageFilter( CBaseEntity *pCaller, const CTakeDamageInfo &info )
22032203
{
2204-
if (m_ScriptScope.IsInitialized())
2204+
if ( m_ScriptScope.IsInitialized() && g_Hook_PassesFinalDamageFilter.CanRunInScope( m_ScriptScope ) )
22052205
{
22062206
HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast<CTakeDamageInfo*>(&info) );
22072207

@@ -2225,7 +2225,7 @@ class CFilterScript : public CBaseFilter
22252225

22262226
bool BloodAllowed( CBaseEntity *pCaller, const CTakeDamageInfo &info )
22272227
{
2228-
if (m_ScriptScope.IsInitialized())
2228+
if ( m_ScriptScope.IsInitialized() && g_Hook_BloodAllowed.CanRunInScope( m_ScriptScope ) )
22292229
{
22302230
HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast<CTakeDamageInfo*>(&info) );
22312231

@@ -2249,7 +2249,7 @@ class CFilterScript : public CBaseFilter
22492249

22502250
bool DamageMod( CBaseEntity *pCaller, CTakeDamageInfo &info )
22512251
{
2252-
if (m_ScriptScope.IsInitialized())
2252+
if ( m_ScriptScope.IsInitialized() && g_Hook_DamageMod.CanRunInScope( m_ScriptScope ) )
22532253
{
22542254
HSCRIPT pInfo = g_pScriptVM->RegisterInstance( &info );
22552255

sp/src/game/shared/baseentity_shared.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1613,7 +1613,7 @@ typedef CTraceFilterSimpleList CBulletsTraceFilter;
16131613
void CBaseEntity::FireBullets( const FireBulletsInfo_t &info )
16141614
{
16151615
#if defined(MAPBASE_VSCRIPT) && defined(GAME_DLL)
1616-
if (m_ScriptScope.IsInitialized())
1616+
if ( m_ScriptScope.IsInitialized() && g_Hook_FireBullets.CanRunInScope( m_ScriptScope ) )
16171617
{
16181618
HSCRIPT hInfo = g_pScriptVM->RegisterInstance( const_cast<FireBulletsInfo_t*>(&info) );
16191619

sp/src/game/shared/mapbase/weapon_custom_scripted.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,13 @@ CWeaponCustomScripted::CWeaponCustomScripted()
177177

178178
bool CWeaponCustomScripted::RunWeaponHook( ScriptHook_t &hook, HSCRIPT &cached, ScriptVariant_t *retVal, ScriptVariant_t *pArgs )
179179
{
180-
if (!hook.CheckFuncValid(cached))
181-
cached = hook.CanRunInScope(m_ScriptScope);
180+
if ( !cached )
181+
{
182+
if ( hook.CanRunInScope( m_ScriptScope ) )
183+
{
184+
cached = hook.m_hFunc;
185+
}
186+
}
182187

183188
if (cached)
184189
{

sp/src/public/vscript/ivscript.h

+49-40
Original file line numberDiff line numberDiff line change
@@ -885,9 +885,8 @@ class IScriptVM
885885
//--------------------------------------------------------
886886
// Hooks
887887
//--------------------------------------------------------
888-
virtual bool ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) = 0;
889-
virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope, bool &bLegacy ) = 0;
890-
virtual ScriptStatus_t ExecuteHookFunction( const char *pszEventName, HSCRIPT hFunction, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) = 0;
888+
virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope ) = 0;
889+
virtual ScriptStatus_t ExecuteHookFunction( HSCRIPT hFunction, const char *pszEventName, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) = 0;
891890
#endif
892891

893892
//--------------------------------------------------------
@@ -1593,17 +1592,6 @@ typedef CScriptScopeT<> CScriptScope;
15931592
//
15941593
// This was previously done with raw function lookups, but Mapbase adds more and
15951594
// it's hard to keep track of them without proper standards or documentation.
1596-
//
1597-
// At the moment, this simply plugs hook documentation into VScript and maintains
1598-
// the same function lookup method on the inside, but it's intended to be open for
1599-
// more complex hook mechanisms with proper parameters in the future.
1600-
//
1601-
// For example:
1602-
//
1603-
// if (m_hFunc)
1604-
// {
1605-
// g_pScriptVM->ExecuteFunction( m_Func, pArgs, m_desc.m_Parameters.Count(), pReturn, m_ScriptScope, true );
1606-
// }
16071595
//-----------------------------------------------------------------------------
16081596
struct ScriptHook_t
16091597
{
@@ -1620,71 +1608,92 @@ struct ScriptHook_t
16201608

16211609
// -----------------------------------------------------------------
16221610

1623-
// Cached for when CanRunInScope() is called before Call()
1611+
// Only valid between CanRunInScope() and Call()
16241612
HSCRIPT m_hFunc;
16251613
bool m_bLegacy;
16261614

1627-
// Checks if there's a function of this name which would run in this scope
1628-
HSCRIPT CanRunInScope( HSCRIPT hScope )
1615+
ScriptHook_t() :
1616+
m_bLegacy(false),
1617+
m_hFunc(NULL)
16291618
{
1630-
extern IScriptVM *g_pScriptVM;
1631-
m_hFunc = g_pScriptVM->LookupHookFunction( m_desc.m_pszScriptName, hScope, m_bLegacy );
1632-
return m_hFunc;
16331619
}
16341620

1635-
// Checks if an existing func can be used
1636-
bool CheckFuncValid( HSCRIPT hFunc )
1621+
#ifdef _DEBUG
1622+
//
1623+
// An uninitialised script scope will pass as null scope which is considered a valid hook scope (global hook)
1624+
// This should catch CanRunInScope() calls without CScriptScope::IsInitalised() checks first.
1625+
//
1626+
bool CanRunInScope( CScriptScope &hScope )
16371627
{
1638-
// TODO: Better crtieria for this?
1639-
if (hFunc)
1628+
Assert( hScope.IsInitialized() );
1629+
return hScope.IsInitialized() && CanRunInScope( (HSCRIPT)hScope );
1630+
}
1631+
#endif
1632+
1633+
// Checks if there's a function of this name which would run in this scope
1634+
bool CanRunInScope( HSCRIPT hScope )
1635+
{
1636+
extern IScriptVM *g_pScriptVM;
1637+
1638+
// Check the hook system first to make sure an unintended function in the script scope does not cancel out all script hooks.
1639+
m_hFunc = g_pScriptVM->LookupHookFunction( m_desc.m_pszScriptName, hScope );
1640+
if ( !m_hFunc )
16401641
{
1641-
m_hFunc = hFunc;
1642-
return true;
1642+
// Legacy support if the new system is not being used
1643+
m_hFunc = g_pScriptVM->LookupFunction( m_desc.m_pszScriptName, hScope );
1644+
m_bLegacy = true;
16431645
}
1644-
return false;
1646+
else
1647+
{
1648+
m_bLegacy = false;
1649+
}
1650+
1651+
return !!m_hFunc;
16451652
}
16461653

16471654
// Call the function
1655+
// NOTE: `bRelease` only exists for weapon_custom_scripted legacy script func caching
16481656
bool Call( HSCRIPT hScope, ScriptVariant_t *pReturn, ScriptVariant_t *pArgs, bool bRelease = true )
16491657
{
16501658
extern IScriptVM *g_pScriptVM;
16511659

1652-
// Make sure we have a function in this scope
1653-
if (!m_hFunc && !CanRunInScope(hScope))
1654-
return false;
1660+
// Call() should not be called without CanRunInScope() check first, it caches m_hFunc for legacy support
1661+
Assert( CanRunInScope( hScope ) );
1662+
16551663
// Legacy
1656-
else if (m_bLegacy)
1664+
if ( m_bLegacy )
16571665
{
1666+
Assert( m_hFunc );
1667+
16581668
for (int i = 0; i < m_desc.m_Parameters.Count(); i++)
16591669
{
16601670
g_pScriptVM->SetValue( m_pszParameterNames[i], pArgs[i] );
16611671
}
16621672

1663-
g_pScriptVM->ExecuteFunction( m_hFunc, NULL, 0, pReturn, hScope, true );
1673+
ScriptStatus_t status = g_pScriptVM->ExecuteFunction( m_hFunc, NULL, 0, pReturn, hScope, true );
16641674

1665-
if (bRelease)
1675+
if ( bRelease )
16661676
g_pScriptVM->ReleaseFunction( m_hFunc );
1667-
16681677
m_hFunc = NULL;
16691678

16701679
for (int i = 0; i < m_desc.m_Parameters.Count(); i++)
16711680
{
16721681
g_pScriptVM->ClearValue( m_pszParameterNames[i] );
16731682
}
16741683

1675-
return true;
1684+
return status == SCRIPT_DONE;
16761685
}
16771686
// New Hook System
16781687
else
16791688
{
1680-
g_pScriptVM->ExecuteHookFunction( m_desc.m_pszScriptName, m_hFunc, pArgs, m_desc.m_Parameters.Count(), pReturn, hScope, true );
1681-
if (bRelease)
1689+
ScriptStatus_t status = g_pScriptVM->ExecuteHookFunction( m_hFunc, m_desc.m_pszScriptName, pArgs, m_desc.m_Parameters.Count(), pReturn, hScope, true );
1690+
1691+
if ( bRelease )
16821692
g_pScriptVM->ReleaseFunction( m_hFunc );
16831693
m_hFunc = NULL;
1684-
return true;
1685-
}
16861694

1687-
return false;
1695+
return status == SCRIPT_DONE;
1696+
}
16881697
}
16891698
};
16901699
#endif

sp/src/vscript/vscript_squirrel.cpp

+33-51
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,8 @@ class SquirrelVM : public IScriptVM
188188
//--------------------------------------------------------
189189
// Hooks
190190
//--------------------------------------------------------
191-
virtual bool ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) override;
192-
virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope, bool &bLegacy ) override;
193-
virtual ScriptStatus_t ExecuteHookFunction( const char *pszEventName, HSCRIPT hFunction, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) override;
191+
virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope ) override;
192+
virtual ScriptStatus_t ExecuteHookFunction( HSCRIPT hFunction, const char *pszEventName, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) override;
194193

195194
//--------------------------------------------------------
196195
// External functions
@@ -2348,54 +2347,37 @@ ScriptStatus_t SquirrelVM::ExecuteFunction(HSCRIPT hFunction, ScriptVariant_t* p
23482347
return SCRIPT_DONE;
23492348
}
23502349

2351-
bool SquirrelVM::ScopeIsHooked( HSCRIPT hScope, const char *pszEventName )
2350+
HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope)
23522351
{
2353-
// For now, assume null scope (which is used for global hooks) is always hooked
2354-
if (!hScope)
2355-
return true;
2356-
23572352
SquirrelSafeCheck safeCheck(vm_);
23582353

2359-
Assert(hScope != INVALID_HSCRIPT);
2360-
2361-
sq_pushroottable(vm_);
2362-
sq_pushstring(vm_, "Hooks", -1);
2363-
sq_get(vm_, -2);
2364-
sq_pushstring(vm_, "ScopeHookedToEvent", -1);
2365-
sq_get(vm_, -2);
2366-
sq_push(vm_, -2);
2367-
sq_pushobject(vm_, *((HSQOBJECT*)hScope));
2368-
sq_pushstring(vm_, pszEventName, -1);
2369-
sq_call(vm_, 3, SQTrue, SQTrue);
2370-
2371-
SQBool val;
2372-
if (SQ_FAILED(sq_getbool(vm_, -1, &val)))
2354+
// For now, assume null scope (which is used for global hooks) is always hooked
2355+
if ( hScope )
23732356
{
2374-
sq_pop(vm_, 3);
2375-
return false;
2376-
}
2357+
Assert( hScope != INVALID_HSCRIPT );
23772358

2378-
sq_pop(vm_, 4);
2379-
return val ? true : false;
2380-
}
2359+
sq_pushroottable(vm_);
2360+
sq_pushstring(vm_, "Hooks", -1);
2361+
sq_get(vm_, -2);
2362+
sq_pushstring(vm_, "IsEventHookedInScope", -1);
2363+
sq_get(vm_, -2);
2364+
sq_push(vm_, -2);
2365+
sq_pushstring(vm_, pszEventName, -1);
2366+
sq_pushobject(vm_, *((HSQOBJECT*)hScope));
2367+
sq_call(vm_, 3, SQTrue, SQTrue);
23812368

2382-
HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope, bool &bLegacy)
2383-
{
2384-
HSCRIPT hFunc = hScope ? LookupFunction( pszEventName, hScope ) : nullptr;
2385-
if (hFunc)
2386-
{
2387-
bLegacy = true;
2388-
return hFunc;
2389-
}
2390-
else
2391-
{
2392-
bLegacy = false;
2393-
}
2369+
SQBool val;
2370+
if (SQ_FAILED(sq_getbool(vm_, -1, &val)))
2371+
{
2372+
sq_pop(vm_, 3);
2373+
return nullptr;
2374+
}
23942375

2395-
if (!ScopeIsHooked(hScope, pszEventName))
2396-
return nullptr;
2376+
sq_pop(vm_, 4);
23972377

2398-
SquirrelSafeCheck safeCheck(vm_);
2378+
if (!val)
2379+
return nullptr;
2380+
}
23992381

24002382
sq_pushroottable(vm_);
24012383
sq_pushstring(vm_, "Hooks", -1);
@@ -2411,31 +2393,31 @@ HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope,
24112393

24122394
HSQOBJECT* pObj = new HSQOBJECT;
24132395
*pObj = obj;
2396+
24142397
return (HSCRIPT)pObj;
24152398
}
24162399

2417-
ScriptStatus_t SquirrelVM::ExecuteHookFunction(const char *pszEventName, HSCRIPT hFunction, ScriptVariant_t* pArgs, int nArgs, ScriptVariant_t* pReturn, HSCRIPT hScope, bool bWait)
2400+
ScriptStatus_t SquirrelVM::ExecuteHookFunction(HSCRIPT hFunction, const char *pszEventName, ScriptVariant_t* pArgs, int nArgs, ScriptVariant_t* pReturn, HSCRIPT hScope, bool bWait)
24182401
{
2419-
SquirrelSafeCheck safeCheck(vm_);
2420-
if (!hFunction)
2402+
if ( !hFunction )
24212403
return SCRIPT_ERROR;
24222404

2423-
if (hFunction == INVALID_HSCRIPT)
2424-
return SCRIPT_ERROR;
2405+
SquirrelSafeCheck safeCheck(vm_);
24252406

24262407
HSQOBJECT* pFunc = (HSQOBJECT*)hFunction;
24272408
sq_pushobject(vm_, *pFunc);
24282409

2429-
// TODO: Run in hook scope
2410+
// The call environment of the Hooks::Call function does not matter
2411+
// as the function does not access any member variables.
24302412
sq_pushroottable(vm_);
24312413

2414+
sq_pushstring(vm_, pszEventName, -1);
2415+
24322416
if (hScope)
24332417
sq_pushobject(vm_, *((HSQOBJECT*)hScope));
24342418
else
24352419
sq_pushnull(vm_); // global hook
24362420

2437-
sq_pushstring(vm_, pszEventName, -1);
2438-
24392421
for (int i = 0; i < nArgs; ++i)
24402422
{
24412423
PushVariant(vm_, pArgs[i]);

0 commit comments

Comments
 (0)