Fixed VScript material proxy retaining VM handles after level unload

This commit is contained in:
Blixibon 2020-05-31 20:58:50 -05:00
parent 82b0460d8f
commit 14efc92e33

View File

@ -39,6 +39,17 @@ extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
#endif // VMPROFILE #endif // VMPROFILE
#ifdef MAPBASE_VSCRIPT #ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
// Purpose: A base class for VScript-utilizing clientside classes which can persist
// across levels, requiring their scripts to be shut down manually.
//-----------------------------------------------------------------------------
abstract_class IClientScriptPersistable
{
public:
virtual void TermScript() = 0;
};
CUtlVector<IClientScriptPersistable*> g_ScriptPersistableList;
#define SCRIPT_MAT_PROXY_MAX_VARS 8 #define SCRIPT_MAT_PROXY_MAX_VARS 8
@ -46,7 +57,7 @@ extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
// Purpose: A material proxy which runs a VScript and allows it to read/write // Purpose: A material proxy which runs a VScript and allows it to read/write
// to material variables. // to material variables.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
class CScriptMaterialProxy : public IMaterialProxy class CScriptMaterialProxy : public IMaterialProxy, public IClientScriptPersistable
{ {
public: public:
CScriptMaterialProxy(); CScriptMaterialProxy();
@ -57,10 +68,12 @@ public:
virtual void OnBind( void *pRenderable ); virtual void OnBind( void *pRenderable );
virtual IMaterial *GetMaterial() { return NULL; } virtual IMaterial *GetMaterial() { return NULL; }
// It would be more preferable to init the script stuff in Init(), but // Proxies can persist across levels and aren't bound to a loaded map.
// the VM isn't usually active by that time, so we have to init it when // The VM, however, is bound to the loaded map, so the proxy's script variables persisting
// it's first called in OnBind(). // causes problems when they're used in a new level with a new VM.
// As a result, we call InitScript() and TermScript() during OnBind and when the level is unloaded respectively.
bool InitScript(); bool InitScript();
void TermScript();
bool ValidateIndex(int i) bool ValidateIndex(int i)
{ {
@ -206,9 +219,23 @@ bool CScriptMaterialProxy::InitScript()
return false; return false;
} }
g_ScriptPersistableList.AddToTail( this );
return true; return true;
} }
void CScriptMaterialProxy::TermScript()
{
if ( m_hScriptInstance )
{
g_pScriptVM->RemoveInstance( m_hScriptInstance );
m_hScriptInstance = NULL;
}
m_hFuncOnBind = NULL;
m_ScriptScope.Term();
}
void CScriptMaterialProxy::OnBind( void *pRenderable ) void CScriptMaterialProxy::OnBind( void *pRenderable )
{ {
if( !pRenderable ) if( !pRenderable )
@ -434,6 +461,18 @@ void VScriptClientTerm()
{ {
if( g_pScriptVM != NULL ) if( g_pScriptVM != NULL )
{ {
#ifdef MAPBASE_VSCRIPT
// Things like proxies can persist across levels, so we have to shut down their scripts manually
for (int i = g_ScriptPersistableList.Count()-1; i >= 0; i--)
{
if (g_ScriptPersistableList[i])
{
g_ScriptPersistableList[i]->TermScript();
g_ScriptPersistableList.FastRemove( i );
}
}
#endif
if( g_pScriptVM ) if( g_pScriptVM )
{ {
scriptmanager->DestroyVM( g_pScriptVM ); scriptmanager->DestroyVM( g_pScriptVM );