Advertisement

Working with and Saving CSerializer/CSerializeObject

Started by April 29, 2016 11:51 PM
3 comments, last by chasester123 8 years, 6 months ago

Im Gonna start by saying this question is a preview over about 500+ lines of code (including the default code in CSerializer.h and .cpp) So please ask if something doesnt make sense.


Struct node
{
vec o, vec rot; //vector 3 position and rotation repectively.
asIScriptObject *ctrl; //script controler aka user code
CSerializeObject *savedata;
void store()
{
if (!c) c = asScript->serializer->storenode(this);
}
}


This is my base object that needs to be added to the angel script code. This object and all of asObjectType list of members, need to saved to the file.

When serializing this object this is how it its done right now.


int CSerialnode::nodeID = -1; //changed at init to the id of Node set by the engine
int CSerialvec::nodeID = -1; //changed at init to the id of Vec set by the engine

CSerializedValue * CSerializer::storenode(node *g)
{
	if (!m_engine)return NULL;
        if(!g)return NULL;
	CSerializedValue *c = new CSerializedValue(&m_root, "SERIAL_OBJECT" , "", g, CSerialnode::nodeID);
	m_root.m_children.push_back(c);
	return c;
}
//NOTE CSerialnode and CSerialvec inherients CUserType
void CSerialnode::Store(CSerializedValue *val, void *ptr)
{
node *g = (node *)ptr;
vec *o = new vec(g->o);
vec *rot = new vec(g->rot);
val->m_children.push_back(new CSerializedValue(val, "pos", "", new vec(g->o), CSerialVec::getID())); //store vec o
val->m_children.push_back(new CSerializedValue(val, "rot", "", new vec(g->rot), CSerialVec::getID())); // store vec rot
val->m_children.push_back(new CSerializedValue(val, "ctrl", "", g->ctrl, g->ctrl->GetTypeId())); //store the controler for this element
}
void CSerialnode::Restore(CSerializedValue *val, void *ptr)
{
node *g = (node *)ptr;
val->m_children[0]->Restore(&g->o, CSerialVec::getID());
val->m_children[1]->Restore(&g->rot, CSerialVec::getID());
if (val->m_children[2]) val->m_children[2]->Restore(g->ctrl->object, g->ctrl->object->GetTypeId());
}
This should allow me to use the Serializer to Store and Restore they Objects using.


bool node::restore()
{
    if (!c) return false; //if no c then object wasnt saved, so delete object.
    c->Restore(this,CSerialnode::getID());
}

This kinda works sometimes I feel like there is some kinda error here when passing the pointers around ??

When Writting to file, The code looks as follows.

The concept here is Get all the Namespaces Types, and names in the tree. Then store each object using an ID for each of the before (namespaceID, typeID, nameID). Then first store the vector of strings with the data, then list all the objects using IDs to reference the spot in the vector. This code works almost flawlessly. The question is how do i Reinitialize the object.


void CSerializer::save(stream *f)
{    
    if (!m_engine) SetEngine(asScript->asEngine); //force the engine only using one engine so this should nv call.
	names.shrink(0);
	types.shrink(0);
	namespaces.shrink(0);
	saveddata.shrink(0);
        names.put("__ERROR__");
        m_root.save();
        PUTLILVECTOR(namespaces);
        PUTLILVECTOR(types);
        PUTLILVECTOR(names);
        f->putlil<uint>(saveddata.length());
        loopv(saveddata)
		saveddata[i]->write(f);
}


void CSerializer::load(stream *f)
{
	if (!m_engine) SetEngine(asScript->asEngine);
	m_root.ClearChildren();
	names.shrink(0);
	types.shrink(0);
	namespaces.shrink(0);
	saveddata.shrink(0);
	PULLLILVECTOR(namespaces);
	PULLLILVECTOR(types);
	PULLLILVECTOR(names);
	uint size = f->getlil<uint>();
	//conoutf("%d", size);
	loopi(size)saveddata.put(DataHold::read(f));
	loopv(saveddata)
	{
		DataHold &sd = *saveddata[i];
		sd.print();
	}
	m_root.m_typeId = 0;
	m_root.m_name = "root";
	m_root.m_nameSpace = "";
	m_root.m_isInit = true;
	m_root.load(0);
	//return;
	loopi(m_root.m_children.size())
	{
		//what do I put here.
                //can i just put
               node *n = new node();
               m_root[i].restore(*n, Serialnode::getId());
               world.addnode(n);
	}
}

//this is where I load up the tree.
void CSerializedValue::load(uint index)
{
	loopioff( 1, saveddata.length())
	{
		DataHold &sd = *saveddata[i];
		CSerializedValue *child;
		str name =  names[VECTOROVERLOADCHECK(names, sd.nameID)];
		str tname = types[VECTOROVERLOADCHECK(types, sd.typeID - (asTYPEID_DOUBLE + 1))];
		str nameSP = namespaces[VECTOROVERLOADCHECK(namespaces, sd.namespaceID)];

		asIObjectType *ot;
		if (sd.typeID > asTYPEID_DOUBLE)
		{
			if (tname == str("__ERROR__")) tname = "void";
			ot = asScript->asEngine->GetObjectTypeByName(tname.c_str());
			if (!ot)
			{
				asScript->recompilemodule(tname.c_str());
				asIScriptModule *mod = asScript->asEngine->GetModule(tname.c_str());
				if (!mod){ conoutf("ERROR!!! no mod"); return; }
				ot = mod->GetObjectTypeByName(tname.c_str());
			}
		}
		else continue; //handle globals here

		if (ot)
		{
			int typeID = ot->GetTypeId();
			void * newptr = asScript->asEngine->CreateUninitializedScriptObject(ot);
			child = new CSerializedValue(this, name, nameSP, newptr, typeID);
			this->m_children.push_back(child);
		}
		else conoutf("ooops");
		i = sd.count(i)-1;//jump to next asObject type
	}
}

As of right now, it goes between not creating the object to, throwing a nullpointer error when loading the nodes. inside that last section where I actually create the object and add it to the scene.

Any help would be great. Sorrie If it seems a bit of a a mess. Im trying to reduce the amount of code to make it easier to read.

chasester

When serializing the data to file have you tried saving it in a human-readable form so that you can visually verify that the saved data is correct? If you have this, can you show us an example of a small data set?

When restoring from the serialized data where are the problems occurring? Are you having trouble getting the correct asIObjectType?

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement

I found the error I didn't realize that reference objects could not be called from creatuninitializedobject. So I've started on a wrap around that creates an object using CSerialCLASSNAME::create() and creates the object from a datahold class object which has been set up in a tree structure, Then once the object is created then I can simply add them into the serializer as objects and pointers.

Just a simple error I wasnt paying attention to the code :)

chasester

PS:

SideNote:: when passing m_mem (vector<char>) into my file parser, can i just copy it using vector<char> DataHold::mem = m_mem; or do i have to do a data copy like mem_copy(). And visa vera after reading the data, can I just do a f->read(mem[0], length); or is there a better way to do this. IO operations aren't my forte.

vector<char> mem = m_mem; will perform a copy of the content in the vector, so there is no need to manually do this using memcpy().

As for reading from a file into a vector, you'll first need to make sure the vector has room for the bytes you'll write to it when reading from the file. You can do that by calling mem.resize(length). After that you can pass the address of the first element to the f->read() function with f->read(&mem[0], length);

When in doubt on what a function or operation do, always consult the manual :)

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

thankx I imagine the reason it was erroring is because vector::length was to short and so when i did the f->read(%vector[0], length) it was either erroring out or throwing the data where ever. Thanx for the help.

chasester

This topic is closed to new replies.

Advertisement