Skip to content

Replicated Attributes

Angus Hollands edited this page Apr 21, 2015 · 10 revisions

Introduction

Replicated attributes offer fast, simple server to client data transfer. Attributes can be marked to trigger a callback when modified. A conditions generator determines when attributes should be replicated to the remote peer. An optional hash comparison can be performed on a set of variables that have complex conditions; meaning that expensive checks can be cut out.

Replicated Attribute Definition

First we must import some classes from the network library

from network.descriptors import Attribute
from network.replicable import Replicable

Now let's create a network class

class NetworkObject(Replicable):
    pass

And give it a Replicated Attribute called name

class NetworkObject(Replicable):
    
    name = Attribute("Alex")

Sometimes we might not want to define a starting value. However, we need to define the value type, so that it can be serialised later on. So let's define its type

class NetworkObject(Replicable):
    
    name = Attribute(type_of=str)

We need to define when the server will send this to relevant clients. To do this we use a conditions generator function.

Replication Conditions

A basic replication conditions generator looks like this. The super class Replicable defines some conditions, so don't forget to yield from the super() method

def conditions(self, is_owner, is_complaint, is_initial):
    yield from super().conditions(is_owner, is_complaint, is_initial)

Let's tell the generator to send the name attribute

def conditions(self, is_owner, is_complaint, is_initial):
    yield from super().conditions(is_owner, is_complaint, is_initial)

    yield "name"

This will check if the value of name has changed every network tick. This may be expensive if the value type is expensive to produce a network description of. In addition, if the value changes infrequently, it is less expensive to tell the system when it has changed, rather than ask it every network tick. To do this, we ask the Attribute to "complain" when modified.

class NetworkObject(Replicable):
    
    name = Attribute(type_of=str, complain=True)

    def conditions(self, is_owner, is_complaint, is_initial):
        yield from super().conditions(is_owner, is_complaint, is_initial)
        
        yield "name"

And now we make use of the complaint system. This essentially calculates the network description whenever the value is modified. This is useful, but is not suited to mutable values (such as network.enums.roles). Complaints are course grained, meaning that if any Attribute is changed, it will set the is_complaint flag to True (assuming it belongs to the complaining attributes set).

class NetworkObject(Replicable):
    
    name = Attribute(type_of=str, complain=True)

    def conditions(self, is_owner, is_complaint, is_initial):
        yield from super().conditions(is_owner, is_complaint, is_initial)
        
        if is_complaint:
            yield "name"

Sometimes, it might be useful to be notified when an Attribute was changed over the network. To do this, we ask the Attribute to notify the class when modified by the network. This notification occurs once all attributes have been set (for all network objects).

class NetworkObject(Replicable):
    
    name = Attribute(type_of=str, complain=True, notify=True)

    def conditions(self, is_owner, is_complaint, is_initial):
        yield from super().conditions(is_owner, is_complaint, is_initial)
        
        if is_complaint:
            yield "name"

And then we define our own function which is called when a notifier Attribute is changed.

class NetworkObject(Replicable):
    
    name = Attribute(type_of=str, complain=True, notify=True)

    def conditions(self, is_owner, is_complaint, is_initial):
        yield from super().conditions(is_owner, is_complaint, is_initial)
        
        if is_complaint:
            yield "name" 

    def on_notify(self, name):
        if name == "name":
            print("Name was changed!)

        else:
            super().on_notify(name)

The three arguments infer context for replication.

  • is_owner indicates whether the target for this replication is the "owner" over this object.
  • is_complaint as aforementioned indicates if tagged variables are pending replication to this client.
  • is_initial indicates whether this client has been replicated to before

Getting Started

#Network

Worlds & Scenes

##Replication Overview

Attributes

Functions

Gotchas

##Serialisation Data handlers

##Communication Messaging

#Game Framework ##Bindings Creating bindings

Clone this wiki locally