Declarative Mode Data Serialization

Declarative Mode Data Serialization

Writing and maintaining all the code for (de)serialization manually can become a complicated task, especially if the protocol specification constantly changes during development. Using message templates with immediate-mode serialization can enforce a proper (de)serialization procedure, but this check is only performed at run time.

To solve these issues, the MessageConnection interface allows sending messages using a Serializable Structure (via MessageConnection::Send and MessageConnection::SendStruct). A Serializable Structure is a (user-definable) type that implicitly implements the following interface:

struct SerializableStructure
{
   // Serializes all the data members of this structure to dst. 
   void SerializeTo(DataSerializer &dst) const;
   
   // Fills in all the data members of this structure from src.
   void DeserializeFrom(DataDeserializer &src);
};

There is another structure interface that corresponds to a message in the kNet Message Model, and looks as follows:

struct SerializableMessage
{
   // Returns the MessageID of this message type.
   static inline u32 MessageID();

   // Returns the human-readable name of this message type.   
   static inline const char *Name();
   
   // If true, this message instance must have guaranteed delivery. 
   bool reliable;

   // If true, this message has ordering requirements. 
   bool inOrder;
   
   // Specificies how urgent this message is with respect to other messages.
   u32 priority;
   
   // Serializes all the data members of this structure to dst. 
   void SerializeTo(DataSerializer &dst) const;
   
   // Fills in all the data members of this structure from src.
   void DeserializeFrom(DataDeserializer &src);
};

The MessageCompiler tool produces structures that follow these two interfaces.

Compiling serialization structures from message description files

While the application developer can define its messages by writing Serializable Structures by hand, this is not even necessary, due to the help of MessageCompiler. This tool generates C++ headers out of kNet Message XML files. See the MessageCompiler page for instructions on how to use this tool.

The code generation process performed by the tool is best explained using an example.

<message id="5" name="PaintPixel" reliable="true" inOrder="true">
  <u16 name="x" />
  <u16 name="y" />
  <u32 name="color" />
</message>

Suppose the developer defines the abovementioned message in a message XML file.Processing it through the MessageCompiler tool produces the following header file:

MsgPaintPixel.h

struct MsgPaintPixel
{
   MsgPaintPixel()
   :reliable(true), inOrder(true), priority(0x7fffffff)  {}

   static inline u32 MessageID() { return 5; }
   static inline const char *Name() { return "PaintPixel"; }

   bool reliable;
   bool inOrder;
   u32 priority;

   u16 x;
   u16 y;
   u32 color;

   inline size_t Size() const
   {
      return 2 + 2 + 4;
   }

   inline void SerializeTo(DataSerializer &dst) const
   {
      dst.Add<u16>(x);
      dst.Add<u16>(y);
      dst.Add<u32>(color);
   }

   inline void DeserializeFrom(DataDeserializer &src)
   {
      x = src.Read<u16>();
      y = src.Read<u16>();
      color = src.Read<u32>();
   }

};

Sending messages using declarative-mode serialization structs

All classes that implement the SerializableStructure interface can be sent through a MessageConnection by calling MessageConnection::SendStruct. This function takes as additional parameters the fields that are required to represent a message in the kNet Message Model.

Classes that implement the SerializableMessage interface can be sent using the MessageConnection::Send function. For example, to send a message of type MsgPaintPixel as specified above, the following code can be used:

void SendPaintPixel(MessageConnection *connection)
{
   MsgPaintPixel msg; // Note MsgPaintPixel's ctor which initializes default values! 
   msg.x = 50;
   msg.y = 250;
   msg.color = 0xFFFF0000;
   connection->Send(msg);
}
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines