7.9. Replica Manager

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:

In the Massiv Demo, ReplicaManager is extensively used by all game manager classes, their sources can be found in directory src/demo/client/game.

Example 7.2. Usage of replica manager
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 );