AngelScript
Serializer

Path: /sdk/add_on/serializer/

The CSerializer implements support for serializing the values of global variables in a module, for example in order to reload a slightly modified version of the script without reinitializing everything. It will resolve primitives and script classes automatically, including references and handles.

For application registered types, the application needs to implement callback objects to show how these should be serialized. The exception is for pod types, as the serializer will simply keep a bitwise copy. Registered reference types without factories will not be serialized, i.e. the object will be kept as-is.

The implementation currently has some limitations:

  • It can only serialize to memory, i.e. it is not possible to save the values to a file.
  • If the variables changed type when restoring, the serializer cannot restore the value.
  • The serializer will attempt to backup all objects, but in some cases an application may not want to backup the actual object, but only a reference to it, e.g. an internal application object referenced by the script. Currently there is no way of telling the serializer to do differently in this case.
  • If the module holds references to objects from another module it will probably fail in restoring the values.

Public C++ interface

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);
};

Example usage

This first example shows how to serialize a script module that uses application registered types.

struct CStringType;
struct CArrayType;
void RecompileModule(asIScriptEngine *engine, asIScriptModule *mod)
{
string modName = mod->GetName();
// Tell the serializer how the user types should be serialized
// by adding the implementations of the CUserType interface
CSerializer backup;
backup.AddUserType(new CStringType(), "string");
backup.AddUserType(new CArrayType(), "array");
// Backup the values of the global variables
backup.Store(mod);
// Application can now recompile the module
CompileModule(modName);
// Restore the values of the global variables in the new module
mod = engine->GetModule(modName.c_str(), asGM_ONLY_IF_EXISTS);
backup.Restore(mod);
}
// This serializes the std::string type
struct CStringType : public CUserType
{
void Store(CSerializedValue *val, void *ptr)
{
val->SetUserData(new std::string(*(std::string*)ptr));
}
void Restore(CSerializedValue *val, void *ptr)
{
std::string *buffer = (std::string*)val->GetUserData();
*(std::string*)ptr = *buffer;
}
void CleanupUserData(CSerializedValue *val)
{
std::string *buffer = (std::string*)val->GetUserData();
delete buffer;
}
};
// This serializes the CScriptArray type
struct CArrayType : public CUserType
{
void Store(CSerializedValue *val, void *ptr)
{
CScriptArray *arr = (CScriptArray*)ptr;
for( unsigned int i = 0; i < arr->GetSize(); i++ )
val->m_children.push_back(new CSerializedValue(val ,"", "", arr->At(i), arr->GetElementTypeId()));
}
void Restore(CSerializedValue *val, void *ptr)
{
CScriptArray *arr = (CScriptArray*)ptr;
arr->Resize(asUINT(val->m_children.size()));
for( size_t i = 0; i < val->m_children.size(); ++i )
val->m_children[i]->Restore(arr->At(asUINT(i)), arr->GetElementTypeId());
}
};

The following example shows how to serialize additional objects, not stored in the module itself.

// This object is stored outside of the module, so it has to be explicitly informed to the serializer
asIScriptObject *scriptObj = reinterpret_cast<asIScriptObject*>(engine->CreateScriptObject(mod->GetTypeInfoByName("CTest")));
void RecompileModule(asIScriptEngine *engine, asIScriptModule *mod)
{
string modName = mod->GetName();
// Tell the serializer about the additional object stored outside of the module
CSerializer backup;
backup.AddExtraObjectToStore(scriptObj);
// Backup the values of the global variables and the additional object
r = backup.Store(mod);
if( r < 0 )
TEST_FAILED;
// Application can now recompile the module
CompileModule(modName);
// Restore the values of the global variables in the new module
mod = engine->GetModule(modName.c_str(), asGM_ONLY_IF_EXISTS);
backup.Restore(mod);
// Restore the extra object by looking up the new instance using the address of the old instance as key
asIScriptObject *obj2 = (asIScriptObject*)backup.GetPointerToRestoredObject(scriptObj);
scriptObj->Release();
scriptObj = obj2;
scriptObj->AddRef();
}
asIScriptEngine::GetModule
virtual asIScriptModule * GetModule(const char *module, asEGMFlags flag=asGM_ONLY_IF_EXISTS)=0
Return an interface pointer to the module.
asIScriptEngine
The engine interface.
Definition: angelscript.h:1102
asGM_ONLY_IF_EXISTS
@ asGM_ONLY_IF_EXISTS
Don't return any module if it is not found.
Definition: angelscript.h:530
asIScriptObject::AddRef
virtual int AddRef() const =0
Increase reference counter.
asIScriptEngine::CreateScriptObject
virtual void * CreateScriptObject(const asITypeInfo *type)=0
Creates an object defined by its type.
asUINT
unsigned int asUINT
32 bit unsigned integer
Definition: angelscript.h:610
asIScriptModule
The interface to the script modules.
Definition: angelscript.h:2232
asIScriptObject
The interface for an instance of a script object.
Definition: angelscript.h:3586
asIScriptObject::Release
virtual int Release() const =0
Decrease reference counter.
asIScriptModule::GetTypeInfoByName
virtual asITypeInfo * GetTypeInfoByName(const char *name) const =0
Returns the type interface by name.
asIScriptModule::GetName
virtual const char * GetName() const =0
Gets the name of the module.