Synchronisable
See also Synchronisable howto.
Purpose
The most important part of the Network API is the Synchronisable Class. It provides the functionality for objects to get synchronised over the network.
Contents of Synchronisable
- objectID: this is a unique id identifying the object inside alls synchronisables
- classID: this is a unique id identifying the class of the object
Synchronisation
There are different modes of synchronisation:
- network::direction::toclient (== 0x1) sync only from server to client
- network::direction::toserver (== 0x2) sync only to server (not really recommended)
- network::direction::bidirectional (==0x3) sync in both directions
Every object and every registered variable has a syncdirection (default: toclient).
In order to synchronise a variable in a class, these steps must be done:
- The class must (public) inherit from Synchronisable
- Every variable that needs synchronisation must be registered to the network engine (see below)
- Make sure the syncdirection of the object is set correctly (setObjectMode, see below)
Register Variables
There are two methods of synchronisation:
- Data synchronisation: use this for every type of linear allocated object (e.g. no pointers)
- String synchronisation: use this for strings only
If you need to synchronise different types of objects, you can synchronise it's membervariables manually. But make sure, the object (to be synchronised) exists when creating an instance of your class.
The registrations must be done in the function registerAllVariables(). Also call this function in your constructor.
Example: Synchronisation of a basic type (membervariable)
int SomeClass::i; REGISTERDATA(i); //this sets the syncdirection to toclientExample: Synchronisation of a Ogre::Vector3
Ogre::Vector3 SomeClass::v; REGISTERDATA( v.x ); REGISTERDATA( v.y ); REGISTERDATA( v.z );
Register linearly allocated object / basic type
To register an object, that is linearly allocated (e.g. from 0x20 to 0x50, no pointers outside this range) you can use REGISTERDATA(varname) or REGISTERDATA_WITHDIR(varname, direction) (if you want a non-default sync. direction).
int SomeClass::i; // membervariable i REGISTERDATA(i);
REGISTERDATA_WITHMODE(varname, mode)
Use this makro if you want to sync a variable using a different direction than the default.
int SomeClass::i; //membervariable i REGISTERDATA_WITHMODE(i, network::direction::toclient); //same as REGISTERDATA(i) //or REGISTERDATA_WITHMODE(i, network::direction::toserver); //sync i only to the server (be carefull when using this) //or REGISTERDATA_WITHMODE(i, network::direction::bidirectional); //sync i in both directions
Register Strings
To register a string object use REGISTERSTRING(stringname) or REGISTERSTRING_WITHDIR(stringname, direction).
Synchronisation Direction
As mentioned above, the default direction of the Synchronisation is toclient. If you want to change this, you need to register the variable with either REGISTERDATA_WITHDIR or REGISTERSTRING_WITHDIR (normally per-class, see below). Additionally you have to set the global syncdirection (per-object, see below) to bidirectional or toclient (again: not recommended)
int SomeClass::syncback; REGISTERDATA_WITHDIR(syncback, network::direction::bidirectional); // put this inside registerAllVariables this->setObjectMode(network::direction::bidirectional); // put this wherever you want (it is possible to do this only for specific objects specified by objectID)
The create function
When synchronising an object the first time to a client (or server) the following steps occur:
- A new object gets created with the appropriate class
- By calling the constructor of the class registerAllVariables gets called (make sure this is in your constructor)
- After construction of the object is finished the data gets updated (all variables previously registered by registerAllVariables)
- After that the create() function gets called.
Because we don't have the data at construction time, all functions that need member variables (with data from the server) must be called inside create() (instead of inside the constructor). See example class for details.
Preconditions
To make a class A synchronisable make sure these conditions are fullfilled:
- A has a default constructor A::A()
- A implements the function registerAllVariables which has all the calls of REGISTERXXX
- Make sure all you put all critical calls into the create function
- If you have nondefault sync directions make sure you called setObjectMode
Example Class
#include "network/Synchronisable.h" class ExampleClass : public network::Synchronisable, public SomeOtherClass{ public: ExampleClass(){ registerAllVariables(); } ~ExampleClass(){} ....... void registerAllVariables(){ REGISTERDATA(i); REGISTERDATA_WITHDIR(v.x, network::direction::bidirectional); REGISTERDATA_WITHDIR(v.y, network::direction::bidirectional); REGISTERDATA_WITHDIR(v.z, network::direction::bidirectional); REGISTERSTRING(s); } bool create(){ Synchronisable::create(); SomeOtherClass::create(); //do all the critical stuff here //eg set meshsrc or whatever (see Model for details) } private: int i; Vector3 v; String s; };