Skip to content

How to Serialize

Prog'z edited this page May 27, 2021 · 5 revisions

How to Serialize in GP Engine

Serialize a script

  1. Reflect the class and add the Serialize() property to it.
  2. Reflect the field and add the Serialize() property to it.

Example :

// MyScript.hpp

// Put your includes here
#include "Engine/ECS/Component/BehaviourComponent.hpp"

// Generated
#include "Generated/MyScript.rfk.h"

namespace GPG RFKNamespace()
{
	class RFKClass(Serialize()) MyScript : public GPE::BehaviourComponent
	{
		// Put your fields and methods here

		RFKField(Serialize()) 
		float mySerializedFloat;

		RFKField(Serialize()) 
		GPM::Vec3 mySerializedVector;

		RFKField(Serialize()) 
		GameObject* mySerializedPointer;

		RFKField(Serialize()) 
		GPE::Function* mySerializedFunctionPtr;

		MyScript_GENERATED
	};
}
// MyScript.cpp

// Put your includes here
#include "MyScript.hpp"

// Generated
#include "Generated/MyScript.rfk.h"
File_GENERATED

// Put your code here

Serialize a custom struct or class

It is very similar to serializing a script.

  1. Reflect your class or your struct, and its data.
  2. Add the Serialize() to what you want to serialize.

Example :

namespace GPG RFKNamespace()
{
	struct RFKStruct(Serialize()) MyCustomStruct
	{
		MyCustomStruct() = default;

		RFKField(Serialize())
		int i;

		MyCustomStruct_GENERATED
	};

	class RFKClass(Serialize()) MyCustomClass
	{
		MyCustomClass() = default;

		RFKField(Serialize())
		char c;

		MyCustomClass_GENERATED
	};

	class RFKClass(Serialize()) MyScript : public GPE::BehaviourComponent
	{
		// Put your fields and methods here

		RFKField(Serialize()) 
		MyCustomStruct mySerializedCustomStruct;

		RFKField(Serialize()) 
		MyCustomClass mySerializedCustomClass;

		MyScript_GENERATED
	};
}
// MyScript.cpp

// Put your includes here
#include "MyScript.hpp"

// Generated
#include "Generated/MyScript.rfk.h"
File_GENERATED

// Put your code here

Serialize a pointer to a polymorphic class

You have to inherit from rfk::Object. Be careful, you have to put Serialize(false) in the base class.

Example :

namespace GPG RFKNamespace()
{
	class RFKClass(Serialize(false)) MyBaseClass : public rfk::Object
	{
		MyBaseClass() = default;

		RFKField(Serialize())
		int i;

		MyBaseClass_GENERATED
	};

	class RFKClass(Serialize()) MyChildClass : public MyBaseClass
	{
		MyChildClass() = default;

		RFKField(Serialize())
		char c;

		MyChildClass_GENERATED
	};

	class RFKClass(Serialize()) MyScript : public GPE::BehaviourComponent
	{
		// Put your fields and methods here

		MyScript()
		{
			myPolymorphicPointer = new MyChildClass();
		}

		RFKField(Serialize()) 
		MyBaseClass* myPolymorphicPointer = nullptr;

		MyScript_GENERATED
	};
}
// MyScript.cpp

// Put your includes here
#include "MyScript.hpp"

// Generated
#include "Generated/MyScript.rfk.h"
File_GENERATED

// Put your code here

In this example, when myPolymorphicPointer is loaded, a new MyChildClass will be instancied. Its serialized fields will be loaded too. If different serialized pointers point to the same instance, there will only be one instance loaded and all the pointers will then point to the new instance.

Serialize an extern class (or struct)

If you can't modify a class, then you can't reflect it with RFKClass and generate serialize functions automatically.
In that case, you have to make the serialize functions of the class yourself.

Example :

// .hpp
class MyThirdPartyClass
{
public:
	int a;
	char b;
	float c;
};

template <>
void GPE::save(GPE::XmlSaver& context, const MyThirdPartyClass& data, const GPE::XmlSaver::SaveInfo& info);

template <>
void GPE::load(GPE::XmlLoader& context, MyThirdPartyClass& data, const GPE::XmlLoader::LoadInfo& info);
// .cpp
template <>
void GPE::save(GPE::XmlSaver& context, const MyThirdPartyClass& data, const GPE::XmlSaver::SaveInfo& info)
{
    context.push(info);

    GPE::save(context, data.a, XmlSaver::SaveInfo{"a", "int", 0});
    GPE::save(context, data.b, XmlSaver::SaveInfo{"b", "char", 0});
    GPE::save(context, data.c, XmlSaver::SaveInfo{"c", "float", 0});

    context.pop();
}

template <>
void load(GPE::XmlLoader& context, GPM::SplitTransform& data, const GPE::XmlLoader::LoadInfo& info)
{
    if (context.goToSubChild(info))
    {
        GPE::load(context, data.a, XmlLoader::LoadInfo{"a", "int", 0});
        GPE::load(context, data.b, XmlLoader::LoadInfo{"b", "char", 0});
        GPE::load(context, data.c, XmlLoader::LoadInfo{"c", "float", 0});

        context.pop();
    }
}

Clone this wiki locally