Callbacks described in the previous section may be useful, but they have many drawbacks. Especially before-update and after-update callbacks are a bit useless, because they are signalled during replication group update and other objects belonging to the replication group of the updated object can't be safely accessed.
Another problem is that the object itself must handle the callbacks. This may be a problem when you want to monitor changes to replicas of world objects on a client node, and modify their visual representation, for example. Because code of such objects is shared between client and server nodes, modifications to client-side structures may be pretty nasty.
The replica manager singleton object tries to solve all these problems. It allows you to register callback functions that will be invoked when objects with given object id or given class are modified.
Standard usage of ReplicaManager is shown in Example 7.2, “Usage of replica manager”. For complete documentation of the ReplicaManager class, see the Massic Core Reference Guide. What's important about the callbacks:
REPLICA_UPDATED callback is invoked for each updated replica, after contents of all replicas from an update have been modified. This means that at the time of this call, all objects belonging to the replication group of the updated object are already up-to-date.
REPLICA_GROUP_UPDATED callback is invoked for each replica that has not been modified by the update, but that belongs to a replication group of a replica that has been modified. REPLICA_GROUP_UDPATED callbacks are invoked after REPLICA_UPDATED callbacks.
REPLICA_DESTROY callback is invoked before any replica is destroyed or updated. All objects belonging to the replication group of the object-to-destroy still exist. The callback is invoked whenever replicas are about to be destroyed. This includes handling of standard replica update messages, handling of an incoming migration, node reinitialization and node shutdown.
In the Massiv Demo, ReplicaManager is extensively used by all game manager classes, their sources can be found in directory src/demo/client/game.
using namespace Massiv::Core; /* A structure. */ struct MyStruct; /* A managed object. */ class MyObject; /* The callback function. */ void my_callback ( ReplicaManager::UpdateReason reason, WeakPointer< Object > replica, int user_tag, VariantPointer user_data ) { /* Cast replica pointer to correct type. */ WeakPointer< MyObject > my_replica( replica.convert() ); /* Cast user data to correct type. */ MyStruct * const my_struct( variant_cast< MyStruct * >( user_data ) ); switch( reason ) { case ReplicaManager::REPLICA_UPDATED: /* Contents of my_replica have been updated. */ ... break; case ReplicaManager::REPLICA_GROUP_UPDATED: /* An object belonging to replication group */ /* of my_replica has been updated. */ ... break; case ReplicaManager::REPLICA_DESTROY: /* Replica my_replica is about to be destroyed. */ ... break; } } ... int my_tag = ...; MyStruct my_struct; /* Register callback monitoring changes to all objects of class MyObject. */ ReplicaManager & replica_manager = Global::replica_manager(); replica_manager.register_callback ( typeid( MyObject ), &my_callback, my_tag, VariantPointer( &my_struct ) ); /* Unregister all registered callbacks to the my_callback method. */ replica_manager.unregister_callback( &my_callback ); |