Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Version 5 (modified by scheusso, 16 years ago) (diff)

Synchronisable

TracNav(TracNav/TOC_Development)? 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 toclient

Example: 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;
};