Added save/restore to client-side VScript

This commit is contained in:
Blixibon
2021-01-27 11:01:38 -06:00
parent 2ee7845e8d
commit fa45fffa39
14 changed files with 386 additions and 207 deletions

View File

@@ -161,6 +161,32 @@ public:
BaseClass::ClientThink();
}
void OnSave()
{
// HACKHACK: Save the next think in the VM since the VM is saved
if (m_bClientThink)
{
g_pScriptVM->SetValue( m_ScriptScope, "__c_think", GetNextThink() );
}
BaseClass::OnSave();
}
void OnRestore()
{
// HACKHACK: See OnSave()
if (m_bClientThink)
{
ScriptVariant_t flNextThink;
if (g_pScriptVM->GetValue( m_ScriptScope, "__c_think", &flNextThink ))
{
SetNextClientThink( flNextThink );
}
}
BaseClass::OnRestore();
}
#else
void InputCallScriptFunctionClient( inputdata_t &inputdata )
{

View File

@@ -757,7 +757,12 @@ public: // IGameSystem
}
}
#ifdef CLIENT_DLL
// On the client, OnRestore() is called before VScript is actually restored, so this has to be called manually from VScript save/restore instead
void OnVMRestore()
#else
void OnRestore()
#endif
{
if ( g_pScriptVM )
{
@@ -783,6 +788,13 @@ private:
} g_ScriptSaveRestoreUtil;
#ifdef CLIENT_DLL
void VScriptSaveRestoreUtil_OnVMRestore()
{
g_ScriptSaveRestoreUtil.OnVMRestore();
}
#endif
CUtlMap< unsigned int, KeyValues* > CScriptSaveRestoreUtil::m_Lookup( DefLessFunc(unsigned int) );
StringHashFunctor CScriptSaveRestoreUtil::Hash;
@@ -1164,6 +1176,13 @@ void CNetMsgScriptHelper::RecieveMessage( bf_read &msg )
word hash = m_MsgIn_()ReadWord();
// Don't do anything if there's no VM here. This can happen if a message from the server goes to a VM-less client, or vice versa.
if ( !g_pScriptVM )
{
CGWarning( 0, CON_GROUP_VSCRIPT, "CNetMsgScriptHelper: No VM on receiving side\n" );
return;
}
ScriptVariant_t hfn;
if ( g_pScriptVM->GetValue( m_Hooks, hash, &hfn ) )
{

View File

@@ -136,4 +136,8 @@ public:
extern CNetMsgScriptHelper *g_ScriptNetMsg;
#ifdef CLIENT_DLL
void VScriptSaveRestoreUtil_OnVMRestore();
#endif
#endif

View File

@@ -13,6 +13,9 @@
#include "characterset.h"
#include "isaverestore.h"
#include "gamerules.h"
#ifdef MAPBASE_VSCRIPT
#include "mapbase/vscript_singletons.h"
#endif
IScriptVM * g_pScriptVM;
extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * );
@@ -278,3 +281,187 @@ CON_COMMAND_SHARED( script_dump_all, "Dump the state of the VM to the console" )
}
g_pScriptVM->DumpState();
}
//-----------------------------------------------------------------------------
static short VSCRIPT_SERVER_SAVE_RESTORE_VERSION = 2;
//-----------------------------------------------------------------------------
class CVScriptSaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler
{
public:
CVScriptSaveRestoreBlockHandler() :
m_InstanceMap( DefLessFunc(const char *) )
{
}
const char *GetBlockName()
{
#ifdef CLIENT_DLL
return "VScriptClient";
#else
return "VScriptServer";
#endif
}
//---------------------------------
void Save( ISave *pSave )
{
pSave->StartBlock();
int temp = g_pScriptVM != NULL;
pSave->WriteInt( &temp );
if ( g_pScriptVM )
{
temp = g_pScriptVM->GetLanguage();
pSave->WriteInt( &temp );
CUtlBuffer buffer;
g_pScriptVM->WriteState( &buffer );
temp = buffer.TellPut();
pSave->WriteInt( &temp );
if ( temp > 0 )
{
pSave->WriteData( (const char *)buffer.Base(), temp );
}
}
pSave->EndBlock();
}
//---------------------------------
void WriteSaveHeaders( ISave *pSave )
{
pSave->WriteShort( &VSCRIPT_SERVER_SAVE_RESTORE_VERSION );
}
//---------------------------------
void ReadRestoreHeaders( IRestore *pRestore )
{
// No reason why any future version shouldn't try to retain backward compatability. The default here is to not do so.
short version;
pRestore->ReadShort( &version );
m_fDoLoad = ( version == VSCRIPT_SERVER_SAVE_RESTORE_VERSION );
}
//---------------------------------
void Restore( IRestore *pRestore, bool createPlayers )
{
if ( !m_fDoLoad && g_pScriptVM )
{
return;
}
#ifdef CLIENT_DLL
C_BaseEntity *pEnt = ClientEntityList().FirstBaseEntity();
#else
CBaseEntity *pEnt = gEntList.FirstEnt();
#endif
while ( pEnt )
{
if ( pEnt->m_iszScriptId != NULL_STRING )
{
#ifndef MAPBASE_VSCRIPT
g_pScriptVM->RegisterClass( pEnt->GetScriptDesc() );
#endif
m_InstanceMap.Insert( STRING( pEnt->m_iszScriptId ), pEnt );
}
#ifdef CLIENT_DLL
pEnt = ClientEntityList().NextBaseEntity( pEnt );
#else
pEnt = gEntList.NextEnt( pEnt );
#endif
}
pRestore->StartBlock();
if ( pRestore->ReadInt() && pRestore->ReadInt() == g_pScriptVM->GetLanguage() )
{
int nBytes = pRestore->ReadInt();
if ( nBytes > 0 )
{
CUtlBuffer buffer;
buffer.EnsureCapacity( nBytes );
pRestore->ReadData( (char *)buffer.AccessForDirectRead( nBytes ), nBytes, 0 );
g_pScriptVM->ReadState( &buffer );
}
}
pRestore->EndBlock();
}
void PostRestore( void )
{
for ( int i = m_InstanceMap.FirstInorder(); i != m_InstanceMap.InvalidIndex(); i = m_InstanceMap.NextInorder( i ) )
{
CBaseEntity *pEnt = m_InstanceMap[i];
if ( pEnt->m_hScriptInstance )
{
ScriptVariant_t variant;
if ( g_pScriptVM->GetValue( STRING(pEnt->m_iszScriptId), &variant ) && variant.m_type == FIELD_HSCRIPT )
{
pEnt->m_ScriptScope.Init( variant.m_hScript, false );
#ifndef CLIENT_DLL
pEnt->RunPrecacheScripts();
#endif
}
}
else
{
// Script system probably has no internal references
pEnt->m_iszScriptId = NULL_STRING;
}
}
m_InstanceMap.Purge();
#if defined(MAPBASE_VSCRIPT) && defined(CLIENT_DLL)
VScriptSaveRestoreUtil_OnVMRestore();
#endif
}
CUtlMap<const char *, CBaseEntity *> m_InstanceMap;
private:
bool m_fDoLoad;
};
//-----------------------------------------------------------------------------
CVScriptSaveRestoreBlockHandler g_VScriptSaveRestoreBlockHandler;
//-------------------------------------
ISaveRestoreBlockHandler *GetVScriptSaveRestoreBlockHandler()
{
return &g_VScriptSaveRestoreBlockHandler;
}
bool CBaseEntityScriptInstanceHelper::ToString( void *p, char *pBuf, int bufSize )
{
CBaseEntity *pEntity = (CBaseEntity *)p;
if ( pEntity->GetEntityName() != NULL_STRING )
{
V_snprintf( pBuf, bufSize, "([%d] %s: %s)", pEntity->entindex(), STRING(pEntity->m_iClassname), STRING( pEntity->GetEntityName() ) );
}
else
{
V_snprintf( pBuf, bufSize, "([%d] %s)", pEntity->entindex(), STRING(pEntity->m_iClassname) );
}
return true;
}
void *CBaseEntityScriptInstanceHelper::BindOnRead( HSCRIPT hInstance, void *pOld, const char *pszId )
{
int iEntity = g_VScriptSaveRestoreBlockHandler.m_InstanceMap.Find( pszId );
if ( iEntity != g_VScriptSaveRestoreBlockHandler.m_InstanceMap.InvalidIndex() )
{
CBaseEntity *pEnt = g_VScriptSaveRestoreBlockHandler.m_InstanceMap[iEntity];
pEnt->m_hScriptInstance = hInstance;
return pEnt;
}
return NULL;
}
CBaseEntityScriptInstanceHelper g_BaseEntityScriptInstanceHelper;

View File

@@ -31,6 +31,17 @@ inline bool VScriptRunScript( const char *pszScriptName, bool bWarnMissing = fal
// Only allow scripts to create entities during map initialization
bool IsEntityCreationAllowedInScripts( void );
class ISaveRestoreBlockHandler;
ISaveRestoreBlockHandler *GetVScriptSaveRestoreBlockHandler();
class CBaseEntityScriptInstanceHelper : public IScriptInstanceHelper
{
bool ToString( void *p, char *pBuf, int bufSize );
void *BindOnRead( HSCRIPT hInstance, void *pOld, const char *pszId );
};
extern CBaseEntityScriptInstanceHelper g_BaseEntityScriptInstanceHelper;
#ifdef MAPBASE_VSCRIPT
void RegisterSharedScriptConstants();
void RegisterSharedScriptFunctions();