initial commit
This commit is contained in:
548
add_on/serializer/serializer.cpp
Normal file
548
add_on/serializer/serializer.cpp
Normal file
@@ -0,0 +1,548 @@
|
||||
//
|
||||
// CSerializer
|
||||
//
|
||||
// This code was based on the CScriptReloader written by FDsagizi
|
||||
// http://www.gamedev.net/topic/604890-dynamic-reloading-script/
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h> // strstr
|
||||
#include <stdio.h> // sprintf
|
||||
#include "serializer.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CSerializer::CSerializer()
|
||||
{
|
||||
m_engine = 0;
|
||||
}
|
||||
|
||||
CSerializer::~CSerializer()
|
||||
{
|
||||
// Extra objects need to be released, since they are not stored in
|
||||
// the module and we cannot rely on the application releasing them
|
||||
for( size_t i = 0; i < m_extraObjects.size(); i++ )
|
||||
{
|
||||
SExtraObject &o = m_extraObjects[i];
|
||||
for( size_t i2 = 0; i2 < m_root.m_children.size(); i2++ )
|
||||
{
|
||||
if( m_root.m_children[i2]->m_originalPtr == o.originalObject && m_root.m_children[i2]->m_restorePtr )
|
||||
reinterpret_cast<asIScriptObject*>(m_root.m_children[i2]->m_restorePtr)->Release();
|
||||
}
|
||||
}
|
||||
|
||||
// Clean the serialized values before we remove the user types
|
||||
m_root.Uninit();
|
||||
|
||||
// Delete the user types
|
||||
std::map<std::string, CUserType*>::iterator it;
|
||||
for( it = m_userTypes.begin(); it != m_userTypes.end(); it++ )
|
||||
delete it->second;
|
||||
|
||||
if( m_engine )
|
||||
m_engine->Release();
|
||||
}
|
||||
|
||||
void CSerializer::AddUserType(CUserType *ref, const std::string &name)
|
||||
{
|
||||
m_userTypes[name] = ref;
|
||||
}
|
||||
|
||||
int CSerializer::Store(asIScriptModule *mod)
|
||||
{
|
||||
m_mod = mod;
|
||||
|
||||
// The engine must not be destroyed before we're completed, so we'll hold on to a reference
|
||||
mod->GetEngine()->AddRef();
|
||||
if( m_engine ) m_engine->Release();
|
||||
m_engine = mod->GetEngine();
|
||||
|
||||
m_root.m_serializer = this;
|
||||
|
||||
// First store global variables
|
||||
asUINT i;
|
||||
for( i = 0; i < mod->GetGlobalVarCount(); i++ )
|
||||
{
|
||||
const char *name, *nameSpace;
|
||||
int typeId;
|
||||
mod->GetGlobalVar(i, &name, &nameSpace, &typeId);
|
||||
m_root.m_children.push_back(new CSerializedValue(&m_root, name, nameSpace, mod->GetAddressOfGlobalVar(i), typeId));
|
||||
}
|
||||
|
||||
// Second store extra objects
|
||||
for( i = 0; i < m_extraObjects.size(); i++ )
|
||||
m_root.m_children.push_back(new CSerializedValue(&m_root, "", "", m_extraObjects[i].originalObject, m_extraObjects[i].originalTypeId));
|
||||
|
||||
// For the handles that were stored, we need to substitute the stored pointer
|
||||
// that is still pointing to the original object to an internal reference so
|
||||
// it can be restored later on.
|
||||
m_root.ReplaceHandles();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Retrieve all global variables after reload script.
|
||||
int CSerializer::Restore(asIScriptModule *mod)
|
||||
{
|
||||
m_mod = mod;
|
||||
|
||||
// The engine must not be destroyed before we're completed, so we'll hold on to a reference
|
||||
mod->GetEngine()->AddRef();
|
||||
if( m_engine ) m_engine->Release();
|
||||
m_engine = mod->GetEngine();
|
||||
|
||||
// First restore extra objects, i.e. the ones that are not directly seen from the module's global variables
|
||||
asUINT i;
|
||||
for( i = 0; i < m_extraObjects.size(); i++ )
|
||||
{
|
||||
SExtraObject &o = m_extraObjects[i];
|
||||
asITypeInfo *type = m_mod->GetTypeInfoByName( o.originalClassName.c_str() );
|
||||
if( type )
|
||||
{
|
||||
for( size_t i2 = 0; i2 < m_root.m_children.size(); i2++ )
|
||||
{
|
||||
if( m_root.m_children[i2]->m_originalPtr == o.originalObject )
|
||||
{
|
||||
// Create a new script object, but don't call its constructor as we will initialize the members.
|
||||
// Calling the constructor may have unwanted side effects if for example the constructor changes
|
||||
// any outside entities, such as setting global variables to point to new objects, etc.
|
||||
void *newPtr = m_engine->CreateUninitializedScriptObject( type );
|
||||
m_root.m_children[i2]->Restore( newPtr, type->GetTypeId() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Second restore the global variables
|
||||
asUINT varCount = mod->GetGlobalVarCount();
|
||||
for( i = 0; i < varCount; i++ )
|
||||
{
|
||||
const char *name, *nameSpace;
|
||||
int typeId;
|
||||
mod->GetGlobalVar(i, &name, &nameSpace, &typeId);
|
||||
|
||||
CSerializedValue *v = m_root.FindByName(name, nameSpace);
|
||||
if( v )
|
||||
v->Restore(mod->GetAddressOfGlobalVar(i), typeId);
|
||||
}
|
||||
|
||||
// The handles that were restored needs to be
|
||||
// updated to point to their final objects.
|
||||
m_root.RestoreHandles();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *CSerializer::GetPointerToRestoredObject(void *ptr)
|
||||
{
|
||||
return m_root.GetPointerToRestoredObject( ptr );
|
||||
}
|
||||
|
||||
void CSerializer::AddExtraObjectToStore( asIScriptObject *object )
|
||||
{
|
||||
if( !object )
|
||||
return;
|
||||
|
||||
// Check if the object hasn't been included already
|
||||
for( size_t i=0; i < m_extraObjects.size(); i++ )
|
||||
if( m_extraObjects[i].originalObject == object )
|
||||
return;
|
||||
|
||||
SExtraObject o;
|
||||
o.originalObject = object;
|
||||
o.originalClassName = object->GetObjectType()->GetName();
|
||||
o.originalTypeId = object->GetTypeId();
|
||||
|
||||
m_extraObjects.push_back( o );
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CSerializedValue::CSerializedValue()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
CSerializedValue::CSerializedValue(CSerializedValue *parent, const std::string &name, const std::string &nameSpace, void *ref, int typeId)
|
||||
{
|
||||
Init();
|
||||
|
||||
m_name = name;
|
||||
m_nameSpace = nameSpace;
|
||||
m_serializer = parent->m_serializer;
|
||||
Store(ref, typeId);
|
||||
}
|
||||
|
||||
void CSerializedValue::Init()
|
||||
{
|
||||
m_handlePtr = 0;
|
||||
m_restorePtr = 0;
|
||||
m_typeId = 0;
|
||||
m_isInit = false;
|
||||
m_serializer = 0;
|
||||
m_userData = 0;
|
||||
m_originalPtr = 0;
|
||||
}
|
||||
|
||||
void CSerializedValue::Uninit()
|
||||
{
|
||||
m_isInit = false;
|
||||
|
||||
ClearChildren();
|
||||
|
||||
if( m_userData )
|
||||
{
|
||||
CUserType *type = m_serializer->m_userTypes[m_typeName];
|
||||
if( type )
|
||||
type->CleanupUserData(this);
|
||||
m_userData = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CSerializedValue::ClearChildren()
|
||||
{
|
||||
// If this value is for an object handle that created an object during the restore
|
||||
// then it is necessary to release the handle here, so we won't get a memory leak
|
||||
if( (m_typeId & asTYPEID_OBJHANDLE) && m_children.size() == 1 && m_children[0]->m_restorePtr )
|
||||
{
|
||||
m_serializer->m_engine->ReleaseScriptObject(m_children[0]->m_restorePtr, m_serializer->m_engine->GetTypeInfoById(m_children[0]->m_typeId));
|
||||
}
|
||||
|
||||
for( size_t n = 0; n < m_children.size(); n++ )
|
||||
delete m_children[n];
|
||||
m_children.clear();
|
||||
}
|
||||
|
||||
CSerializedValue::~CSerializedValue()
|
||||
{
|
||||
Uninit();
|
||||
}
|
||||
|
||||
CSerializedValue *CSerializedValue::FindByName(const std::string &name, const std::string &nameSpace)
|
||||
{
|
||||
for( size_t i = 0; i < m_children.size(); i++ )
|
||||
if( m_children[i]->m_name == name &&
|
||||
m_children[i]->m_nameSpace == nameSpace )
|
||||
return m_children[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CSerializedValue::GetAllPointersOfChildren(std::vector<void*> *ptrs)
|
||||
{
|
||||
ptrs->push_back(m_originalPtr);
|
||||
|
||||
for( size_t i = 0; i < m_children.size(); ++i )
|
||||
m_children[i]->GetAllPointersOfChildren(ptrs);
|
||||
}
|
||||
|
||||
CSerializedValue *CSerializedValue::FindByPtr(void *ptr)
|
||||
{
|
||||
if( m_originalPtr == ptr )
|
||||
return this;
|
||||
|
||||
for( size_t i = 0; i < m_children.size(); i++ )
|
||||
{
|
||||
CSerializedValue *find = m_children[i]->FindByPtr(ptr);
|
||||
if( find )
|
||||
return find;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *CSerializedValue::GetPointerToRestoredObject(void *ptr)
|
||||
{
|
||||
if( m_originalPtr == ptr )
|
||||
return m_restorePtr;
|
||||
|
||||
for( size_t i = 0; i < m_children.size(); ++i )
|
||||
{
|
||||
void *ret = m_children[i]->GetPointerToRestoredObject(ptr);
|
||||
if( ret )
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// find variable by ptr but looking only at those in the references, which will create a new object
|
||||
CSerializedValue *CSerializedValue::FindByPtrInHandles(void *ptr)
|
||||
{
|
||||
// if this handle created object
|
||||
if( (m_typeId & asTYPEID_OBJHANDLE) && m_children.size() == 1 )
|
||||
{
|
||||
if( m_children[0]->m_originalPtr == ptr )
|
||||
return this;
|
||||
}
|
||||
|
||||
if( !(m_typeId & asTYPEID_OBJHANDLE) )
|
||||
{
|
||||
for( size_t i = 0; i < m_children.size(); i++ )
|
||||
{
|
||||
CSerializedValue *find = m_children[i]->FindByPtrInHandles(ptr);
|
||||
if( find )
|
||||
return find;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CSerializedValue::Store(void *ref, int typeId)
|
||||
{
|
||||
m_isInit = true;
|
||||
SetType(typeId);
|
||||
m_originalPtr = ref;
|
||||
|
||||
if( m_typeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
m_handlePtr = *(void**)ref;
|
||||
}
|
||||
else if( m_typeId & asTYPEID_SCRIPTOBJECT )
|
||||
{
|
||||
asIScriptObject *obj = (asIScriptObject *)ref;
|
||||
asITypeInfo *type = obj->GetObjectType();
|
||||
SetType(type->GetTypeId());
|
||||
|
||||
// Store children
|
||||
for( asUINT i = 0; i < type->GetPropertyCount(); i++ )
|
||||
{
|
||||
int childId;
|
||||
const char *childName;
|
||||
type->GetProperty(i, &childName, &childId);
|
||||
|
||||
m_children.push_back(new CSerializedValue(this, childName, "", obj->GetAddressOfProperty(i), childId));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int size = m_serializer->m_engine->GetSizeOfPrimitiveType(m_typeId);
|
||||
|
||||
if( size == 0 )
|
||||
{
|
||||
// if it is user type( string, array, etc ... )
|
||||
if( m_serializer->m_userTypes[m_typeName] )
|
||||
m_serializer->m_userTypes[m_typeName]->Store(this, m_originalPtr);
|
||||
else
|
||||
{
|
||||
// POD-types can be stored without need for user type
|
||||
asITypeInfo *type = GetType();
|
||||
if( type && (type->GetFlags() & asOBJ_POD) )
|
||||
size = GetType()->GetSize();
|
||||
|
||||
// It is not necessary to report an error here if it is not a POD-type as that will be done when restoring
|
||||
}
|
||||
}
|
||||
|
||||
if( size )
|
||||
{
|
||||
m_mem.resize(size);
|
||||
memcpy(&m_mem[0], ref, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSerializedValue::Restore(void *ref, int typeId)
|
||||
{
|
||||
if( !this || !m_isInit || !ref )
|
||||
return;
|
||||
|
||||
// Verify that the stored type matched the new type of the value being restored
|
||||
if( typeId <= asTYPEID_DOUBLE && typeId != m_typeId ) return; // TODO: We may try to do a type conversion for primitives
|
||||
if( (typeId & ~asTYPEID_MASK_SEQNBR) ^ (m_typeId & ~asTYPEID_MASK_SEQNBR) ) return;
|
||||
asITypeInfo *type = m_serializer->m_engine->GetTypeInfoById(typeId);
|
||||
if( type && m_typeName != type->GetName() ) return;
|
||||
|
||||
// Set the new pointer and type
|
||||
m_restorePtr = ref;
|
||||
SetType(typeId);
|
||||
|
||||
// Restore the value
|
||||
if( m_typeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
// if need create objects
|
||||
if( m_children.size() == 1 )
|
||||
{
|
||||
asITypeInfo *ctype = m_children[0]->GetType();
|
||||
|
||||
if( ctype->GetFactoryCount() == 0 )
|
||||
{
|
||||
// There are no factories, so assume the same pointer is going to be used
|
||||
m_children[0]->m_restorePtr = m_handlePtr;
|
||||
|
||||
// Increase the refCount for the object as it will be released upon clean-up
|
||||
m_serializer->m_engine->AddRefScriptObject(m_handlePtr, ctype);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new script object, but don't call its constructor as we will initialize the members.
|
||||
// Calling the constructor may have unwanted side effects if for example the constructor changes
|
||||
// any outside entities, such as setting global variables to point to new objects, etc.
|
||||
void *newObject = m_serializer->m_engine->CreateUninitializedScriptObject(ctype);
|
||||
m_children[0]->Restore(newObject, ctype->GetTypeId());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( m_typeId & asTYPEID_SCRIPTOBJECT )
|
||||
{
|
||||
asIScriptObject *obj = (asIScriptObject *)ref;
|
||||
|
||||
// Retrieve children
|
||||
for( asUINT i = 0; i < type->GetPropertyCount() ; i++ )
|
||||
{
|
||||
const char *nameProperty;
|
||||
int ptypeId;
|
||||
type->GetProperty(i, &nameProperty, &ptypeId);
|
||||
|
||||
CSerializedValue *var = FindByName(nameProperty, "");
|
||||
if( var )
|
||||
var->Restore(obj->GetAddressOfProperty(i), ptypeId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( m_mem.size() )
|
||||
{
|
||||
// POD values can be restored with direct copy
|
||||
memcpy(ref, &m_mem[0], m_mem.size());
|
||||
}
|
||||
else if( m_serializer->m_userTypes[m_typeName] )
|
||||
{
|
||||
// user type restore
|
||||
m_serializer->m_userTypes[m_typeName]->Restore(this, m_restorePtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string str = "Cannot restore type '";
|
||||
str += type->GetName();
|
||||
str += "'";
|
||||
m_serializer->m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSerializedValue::CancelDuplicates(CSerializedValue *from)
|
||||
{
|
||||
std::vector<void*> ptrs;
|
||||
from->GetAllPointersOfChildren(&ptrs);
|
||||
|
||||
for( size_t i = 0; i < ptrs.size(); ++i )
|
||||
{
|
||||
CSerializedValue *find = m_serializer->m_root.FindByPtrInHandles(ptrs[i]);
|
||||
|
||||
while( find )
|
||||
{
|
||||
// cancel create object
|
||||
find->ClearChildren();
|
||||
|
||||
// Find next link to this ptr
|
||||
find = m_serializer->m_root.FindByPtrInHandles(ptrs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSerializedValue::ReplaceHandles()
|
||||
{
|
||||
if( m_handlePtr )
|
||||
{
|
||||
// Find the object that the handle is referring to
|
||||
CSerializedValue *handle_to = m_serializer->m_root.FindByPtr(m_handlePtr);
|
||||
|
||||
// If the object hasn't been stored yet...
|
||||
if( handle_to == 0 )
|
||||
{
|
||||
// Store the object now
|
||||
asITypeInfo *type = GetType();
|
||||
CSerializedValue *need_create = new CSerializedValue(this, m_name, m_nameSpace, m_handlePtr, type->GetTypeId());
|
||||
|
||||
// Make sure all other handles that point to the same object
|
||||
// are updated, so we don't end up creating duplicates
|
||||
CancelDuplicates(need_create);
|
||||
|
||||
m_children.push_back(need_create);
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the handles in the children too
|
||||
for( size_t i = 0; i < m_children.size(); ++i )
|
||||
m_children[i]->ReplaceHandles();
|
||||
}
|
||||
|
||||
void CSerializedValue::RestoreHandles()
|
||||
{
|
||||
if( m_typeId & asTYPEID_OBJHANDLE )
|
||||
{
|
||||
if( m_handlePtr )
|
||||
{
|
||||
// Find the object the handle is supposed to point to
|
||||
CSerializedValue *handleTo = m_serializer->m_root.FindByPtr(m_handlePtr);
|
||||
|
||||
if( m_restorePtr && handleTo && handleTo->m_restorePtr )
|
||||
{
|
||||
asITypeInfo *type = m_serializer->m_engine->GetTypeInfoById(m_typeId);
|
||||
|
||||
// If the handle is already pointing to something it must be released first
|
||||
if( *(void**)m_restorePtr )
|
||||
m_serializer->m_engine->ReleaseScriptObject(*(void**)m_restorePtr, type);
|
||||
|
||||
// Update the internal pointer
|
||||
*(void**)m_restorePtr = handleTo->m_restorePtr;
|
||||
|
||||
// Increase the reference
|
||||
m_serializer->m_engine->AddRefScriptObject(handleTo->m_restorePtr, type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the handle is pointing to something, we must release it to restore the null pointer
|
||||
if( m_restorePtr && *(void**)m_restorePtr )
|
||||
{
|
||||
m_serializer->m_engine->ReleaseScriptObject(*(void**)m_restorePtr, m_serializer->m_engine->GetTypeInfoById(m_typeId));
|
||||
*(void**)m_restorePtr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do the same for the children
|
||||
for( size_t i = 0; i < m_children.size(); ++i )
|
||||
m_children[i]->RestoreHandles();
|
||||
}
|
||||
|
||||
void CSerializedValue::SetType(int typeId)
|
||||
{
|
||||
m_typeId = typeId;
|
||||
|
||||
asITypeInfo *type = m_serializer->m_engine->GetTypeInfoById(typeId);
|
||||
|
||||
if( type )
|
||||
m_typeName = type->GetName();
|
||||
}
|
||||
|
||||
asITypeInfo *CSerializedValue::GetType()
|
||||
{
|
||||
if( !m_typeName.empty() )
|
||||
{
|
||||
int newTypeId = m_serializer->m_mod->GetTypeIdByDecl(m_typeName.c_str());
|
||||
return m_serializer->m_engine->GetTypeInfoById(newTypeId);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CSerializedValue::SetUserData(void *data)
|
||||
{
|
||||
m_userData = data;
|
||||
}
|
||||
|
||||
void *CSerializedValue::GetUserData()
|
||||
{
|
||||
return m_userData;
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
193
add_on/serializer/serializer.h
Normal file
193
add_on/serializer/serializer.h
Normal file
@@ -0,0 +1,193 @@
|
||||
//
|
||||
// CSerializer
|
||||
//
|
||||
// This code was based on the CScriptReloader written by FDsagizi
|
||||
// http://www.gamedev.net/topic/604890-dynamic-reloading-script/
|
||||
//
|
||||
|
||||
#ifndef SERIALIZER_H
|
||||
#define SERIALIZER_H
|
||||
|
||||
#ifndef ANGELSCRIPT_H
|
||||
// Avoid having to inform include path if header is already include before
|
||||
#include <angelscript.h>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class CSerializer;
|
||||
class CSerializedValue;
|
||||
|
||||
// Need for register user types objects
|
||||
// string, any, array... for all object
|
||||
// user ref type.
|
||||
struct CUserType
|
||||
{
|
||||
virtual ~CUserType() {};
|
||||
virtual void Store(CSerializedValue *val, void *ptr) = 0;
|
||||
virtual void Restore(CSerializedValue *val, void *ptr) = 0;
|
||||
virtual void CleanupUserData(CSerializedValue * /*val*/) {}
|
||||
};
|
||||
|
||||
|
||||
class CSerializedValue
|
||||
{
|
||||
public:
|
||||
CSerializedValue();
|
||||
CSerializedValue(CSerializedValue *parent, const std::string &name, const std::string &nameSpace, void *ref, int typeId);
|
||||
~CSerializedValue();
|
||||
|
||||
// Save the object and its children
|
||||
void Store(void *ref, int refTypeId);
|
||||
|
||||
// Restore the object and its children
|
||||
void Restore(void *ref, int refTypeId);
|
||||
|
||||
// Set type of this var
|
||||
void SetType(int typeId);
|
||||
|
||||
// Returns the object type for non-primitives
|
||||
asITypeInfo *GetType();
|
||||
|
||||
// Get child by name variable
|
||||
CSerializedValue *FindByName(const std::string &name, const std::string &nameSpace);
|
||||
|
||||
// Find variable by ptr
|
||||
CSerializedValue *FindByPtr(void *ptr);
|
||||
|
||||
// User data
|
||||
void *GetUserData();
|
||||
void SetUserData(void *data);
|
||||
|
||||
// Children, e.g. properties of a script class, or elements
|
||||
// of an array, or object pointed to by a handle unless it
|
||||
// is already a variable)
|
||||
std::vector<CSerializedValue*> m_children;
|
||||
|
||||
protected:
|
||||
friend class CSerializer;
|
||||
|
||||
void Init();
|
||||
void Uninit();
|
||||
|
||||
// you first need to save all the objects before you can save references to objects
|
||||
void ReplaceHandles();
|
||||
|
||||
// After the objects has been restored, the handles needs to
|
||||
// be updated to point to the right objects
|
||||
void RestoreHandles();
|
||||
|
||||
// Recursively get all ptrs of the children
|
||||
void GetAllPointersOfChildren(std::vector<void*> *ptrs);
|
||||
|
||||
// may be that the two references refer to the same variable.
|
||||
// But this variable is not available in the global list.
|
||||
// According to this reference will be restores it.
|
||||
// And so two links are not created 2 variables,
|
||||
// it is necessary to cancel the creation of one of them.
|
||||
void CancelDuplicates(CSerializedValue *from);
|
||||
|
||||
// Find variable by ptr but looking only at those in the references, which will create a new object
|
||||
CSerializedValue *FindByPtrInHandles(void *ptr);
|
||||
|
||||
// ptr - is a handle to class
|
||||
void *GetPointerToRestoredObject(void *ptr);
|
||||
|
||||
// Cleanup children
|
||||
void ClearChildren();
|
||||
|
||||
// The serializer object
|
||||
CSerializer *m_serializer;
|
||||
|
||||
// The user data can be used by CUserType to store extra information
|
||||
void *m_userData;
|
||||
|
||||
// The type id of the stored value
|
||||
int m_typeId;
|
||||
|
||||
// For non-primitives the typeId may change if the module is reloaded so
|
||||
// it is necessary to store the type name to determine the new type id
|
||||
std::string m_typeName;
|
||||
|
||||
// Name of variable or property
|
||||
std::string m_name;
|
||||
std::string m_nameSpace;
|
||||
|
||||
// Is initialized
|
||||
bool m_isInit;
|
||||
|
||||
// 'this' pointer to variable.
|
||||
// While storing, this points to the actual variable that was stored.
|
||||
// While restoring, it is just a unique identifier.
|
||||
void *m_originalPtr;
|
||||
|
||||
// where handle references
|
||||
// While storing, this points to the actual object.
|
||||
// While restoring, it is just a unique identifier.
|
||||
void *m_handlePtr;
|
||||
|
||||
// new address object, ie address the restoration
|
||||
// While storing this isn't used.
|
||||
// While restoring it will point to the actual variable/object that is restored.
|
||||
void *m_restorePtr;
|
||||
|
||||
// Serialized data for primitives
|
||||
std::vector<char> m_mem;
|
||||
};
|
||||
|
||||
|
||||
// This class keeps a list of variables, then restores them after the script is rebuilt.
|
||||
// But you have to be careful with the change of signature in classes, or
|
||||
// changing the types of objects. You can remove or add variables, functions,
|
||||
// methods, but you can not (yet) change the type of variables.
|
||||
//
|
||||
// You also need to understand that after a rebuild you should get
|
||||
// new functions and typeids from the module.
|
||||
class CSerializer
|
||||
{
|
||||
public:
|
||||
CSerializer();
|
||||
~CSerializer();
|
||||
|
||||
// Add implementation for serializing user types
|
||||
void AddUserType(CUserType *ref, const std::string &name);
|
||||
|
||||
// Store all global variables in the module
|
||||
int Store(asIScriptModule *mod);
|
||||
|
||||
// Restore all global variables after reloading script
|
||||
int Restore(asIScriptModule *mod);
|
||||
|
||||
// Store extra objects that are not seen from the module's global variables
|
||||
void AddExtraObjectToStore(asIScriptObject *object);
|
||||
|
||||
// Return new pointer to restored object
|
||||
void *GetPointerToRestoredObject(void *originalObject);
|
||||
|
||||
protected:
|
||||
friend class CSerializedValue;
|
||||
|
||||
CSerializedValue m_root;
|
||||
asIScriptEngine *m_engine;
|
||||
asIScriptModule *m_mod;
|
||||
|
||||
std::map<std::string, CUserType*> m_userTypes;
|
||||
|
||||
struct SExtraObject
|
||||
{
|
||||
asIScriptObject *originalObject;
|
||||
std::string originalClassName;
|
||||
int originalTypeId;
|
||||
};
|
||||
|
||||
std::vector<SExtraObject> m_extraObjects;
|
||||
};
|
||||
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user