Various vscript fixes

* Fixes scopes not being restored from a save
* Fixes closure environment not being restored from a save
* Fixes singletons not being properly restored from a save
* Fixes root table being incorrectly duplicated in a save
* Fixes various cases where duplicate objects could be created from a save
This commit is contained in:
James Mitchell 2020-05-21 21:24:10 +10:00
parent 33e7a45657
commit 1210dee374

View File

@ -1218,6 +1218,14 @@ HSCRIPT SquirrelVM::CreateScope(const char* pszScope, HSCRIPT hParent)
sq_pushroottable(vm_);
}
sq_pushstring(vm_, pszScope, -1);
sq_push(vm_, -3);
sq_rawset(vm_, -3);
sq_pushstring(vm_, "__vname", -1);
sq_pushstring(vm_, pszScope, -1);
sq_rawset(vm_, -4);
if (SQ_FAILED(sq_setdelegate(vm_, -2)))
{
sq_pop(vm_, 2);
@ -1238,6 +1246,15 @@ void SquirrelVM::ReleaseScope(HSCRIPT hScript)
SquirrelSafeCheck safeCheck(vm_);
if (!hScript) return;
HSQOBJECT* obj = (HSQOBJECT*)hScript;
sq_pushobject(vm_, *obj);
sq_getdelegate(vm_, -1);
sq_pushstring(vm_, "__vname", -1);
sq_rawdeleteslot(vm_, -2, SQFalse);
sq_pop(vm_, 2);
sq_release(vm_, obj);
delete obj;
}
@ -1931,6 +1948,17 @@ void SquirrelVM::WriteObject(CUtlBuffer* pBuffer, WriteStateMap& writeState, SQI
}
}
if (_closure(obj)->_env)
{
sq_pushobject(vm_, _closure(obj)->_env->_obj);
}
else
{
sq_pushnull(vm_);
}
WriteObject(pBuffer, writeState, -1);
sq_poptop(vm_);
break;
}
case OT_NATIVECLOSURE:
@ -2077,7 +2105,11 @@ void SquirrelVM::WriteObject(CUtlBuffer* pBuffer, WriteStateMap& writeState, SQI
if (pClassInstanceData)
{
if (pClassInstanceData->instanceId)
if (pClassInstanceData->desc->m_pszDescription[0] == SCRIPT_SINGLETON[0])
{
// Do nothing, singleton should be created from just the class
}
else if (!pClassInstanceData->instanceId.IsEmpty())
{
pBuffer->PutString(pClassInstanceData->instanceId);
}
@ -2150,6 +2182,12 @@ void SquirrelVM::WriteState(CUtlBuffer* pBuffer)
sq_pushroottable(vm_);
// Not really a check cache, but adds the root
HSQOBJECT obj;
sq_resetobject(&obj);
sq_getstackobj(vm_, -1, &obj);
writeState.CheckCache(pBuffer, _table(obj));
int count = sq_getsize(vm_, 1);
sq_pushnull(vm_);
pBuffer->PutInt(count);
@ -2204,6 +2242,7 @@ void SquirrelVM::ReadObject(CUtlBuffer* pBuffer, ReadStateMap& readState)
int size = pBuffer->GetInt();
char* buffer = new char[size + 1];
pBuffer->Get(buffer, size);
buffer[size] = 0;
sq_pushstring(vm_, buffer, size);
delete[] buffer;
break;
@ -2234,6 +2273,7 @@ void SquirrelVM::ReadObject(CUtlBuffer* pBuffer, ReadStateMap& readState)
ReadObject(pBuffer, readState);
sq_rawset(vm_, -3);
}
break;
}
case OT_ARRAY:
@ -2301,6 +2341,16 @@ void SquirrelVM::ReadObject(CUtlBuffer* pBuffer, ReadStateMap& readState)
sq_pushobject(vm_, *obj);
}
ReadObject(pBuffer, readState);
HSQOBJECT env;
sq_resetobject(&env);
sq_getstackobj(vm_, -1, &env);
if (!sq_isnull(env))
{
_closure(*obj)->_env = _refcounted(env)->GetWeakRef(sq_type(env));
}
sq_poptop(vm_);
break;
}
case OT_NATIVECLOSURE:
@ -2317,6 +2367,7 @@ void SquirrelVM::ReadObject(CUtlBuffer* pBuffer, ReadStateMap& readState)
sq_pushnull(vm_);
}
sq_remove(vm_, -2);
break;
}
case OT_CLASS:
@ -2392,6 +2443,49 @@ void SquirrelVM::ReadObject(CUtlBuffer* pBuffer, ReadStateMap& readState)
ReadObject(pBuffer, readState);
SQUserPointer typetag;
sq_gettypetag(vm_, -1, &typetag);
if (typetag && typetag != TYPETAG_VECTOR &&
((ScriptClassDesc_t*)typetag)->m_pszDescription[0] == SCRIPT_SINGLETON[0])
{
HSQOBJECT klass;
sq_resetobject(&klass);
sq_getstackobj(vm_, -1, &klass);
sq_poptop(vm_);
Assert(sq_isclass(klass));
// singleton, lets find an equivlent in the root
bool foundSingleton = false;
sq_pushroottable(vm_);
sq_pushnull(vm_);
HSQOBJECT singleton;
sq_resetobject(&singleton);
while (SQ_SUCCEEDED(sq_next(vm_, -2)))
{
sq_getstackobj(vm_, -1, &singleton);
if (sq_isinstance(singleton) && _instance(singleton)->_class == _class(klass))
{
foundSingleton = true;
*obj = singleton;
sq_pop(vm_, 2);
break;
}
sq_pop(vm_, 2);
}
sq_pop(vm_, 2);
if (!foundSingleton)
{
Warning("SquirrelVM::ReadObject: Failed to find singleton for %s\n",
((ScriptClassDesc_t*)typetag)->m_pszScriptName);
}
sq_pushobject(vm_, *obj);
break;
}
sq_createinstance(vm_, -1);
sq_getstackobj(vm_, -1, obj);
@ -2410,8 +2504,7 @@ void SquirrelVM::ReadObject(CUtlBuffer* pBuffer, ReadStateMap& readState)
}
}
SQUserPointer typetag;
sq_gettypetag(vm_, -1, &typetag);
if (typetag == TYPETAG_VECTOR)
{
@ -2453,6 +2546,10 @@ void SquirrelVM::ReadObject(CUtlBuffer* pBuffer, ReadStateMap& readState)
}
sq_setreleasehook(vm_, -1, &destructor_stub);
}
else
{
sq_setinstanceup(vm_, -1, nullptr);
}
}
break;
@ -2481,6 +2578,7 @@ void SquirrelVM::ReadObject(CUtlBuffer* pBuffer, ReadStateMap& readState)
}
vm_->Push(ret);
sq_getstackobj(vm_, -1, obj);
}
case OT_OUTER: //internal usage only
{
@ -2500,6 +2598,7 @@ void SquirrelVM::ReadObject(CUtlBuffer* pBuffer, ReadStateMap& readState)
outer->_valptr = &(outer->_value);
sq_poptop(vm_);
vm_->Push(outer);
sq_getstackobj(vm_, -1, obj);
break;
}
@ -2521,6 +2620,10 @@ void SquirrelVM::ReadState(CUtlBuffer* pBuffer)
sq_pushroottable(vm_);
HSQOBJECT* obj = nullptr;
readState.CheckCache(pBuffer, &obj);
sq_getstackobj(vm_, -1, obj);
int count = pBuffer->GetInt();
for (int i = 0; i < count; ++i)