We use proprietary and third party's cookies to improve your experience and our services, identifying your Internet Browsing preferences on our website; develop analytic activities and display advertising based on your preferences. If you keep browsing, you accept its use. You can get more information on our Cookie Policy
Cookies Policy
Synchronization Open API Specification - FIWARE Forge Wiki

Synchronization Open API Specification

From FIWARE Forge Wiki

Jump to: navigation, search

Contents

The SceneAPI is defined in a separate document

Real-Time Sync Protocol

This API description is based on the currently implemented features and is subject to change once more features are implemented.

To maintain low coupling and eg. allow the scene model to be reused without networking, the JavaScript client API is divided into classes with different responsibilities:

  • WebSocketClient: WebSocket connection management
  • Scene, Entity, Component and Attribute: scene model implementation
  • SyncManager: bidirectional synchronization of the scene with the server

Connection management

Initiating a WebSocket connection to a server happens through the WebSocketClient object, which exposes the following functions:

webSocketClient.connect(hostname, port, loginData)
webSocketClient.disconnect()

The loginData is optional JSON data that specifies user name, authentication information etc.

The WebSocketClient provides signals for the connect succeeding or failing, and provides access to sending and receiving raw binary messages which is utilized by the SyncManager. After a successful connection to the server the client is assigned and sent back an integer user ID and a reply data which is also JSON, and these can be read via the WebSocketClient's "userID" and "loginReplyData" properties.

Scene model

The Scene, Entity, Component and Attribute classes implement access to the Entity-Component-Attribute -based scene and are what the SyncManager manipulates to replicate scene modifications coming from the server.

These classes provide also signals for scene modification operations that happen on them (such as "entityCreated", "entityRemoved") and the SyncManager hooks into these to be able to send the client's scene modifications to the server.

All scene modification operations (creation, modification and removal of entities, components and attributes) are accompanied by a "change type" or signaling mode. It is possible to make changes to the scene without sending them to the network, or even without signaling them internally at all. The default change mode should be used in most cases, and is also used if the change type parameter is omitted.

change type Description
Default Use the default signaling mode which makes most sense, which is Replicated for replicated entities/components, or LocalOnly for local entities / components
Replicate If the entity or component in question is replicated, send the change as a network message
LocalOnly Signal the change locally, but do not send a network message
Disconnected Do not signal locally and do not send a network message

The entities in the scene and the components in an entity are primarily identified with their integer ID's. The ID's are split into different ranges based on their purpose:

ID Range Purpose
0x00000001
0x3fffffff
Replicated entities / components. These are synchronized between the server and the client
0x40000001
0x7fffffff
Unacked entities / components. When a client creates an entity or component that should appear on the server, it allocates an "unacked" ID for it. This will be transformed by the server to an authoritatively allocated replicated ID. A reply message is sent to the client so that it knows also to change the ID of the entity or component it created.
0x80000001
0xffffffff
Local entities / components. These are created on the client only (or the server only) and willnot be synchronized
0x00000001
0x3fffffff
Replicated entities / components. These are synchronized between the server and the client

Next follows a brief description of the most important functions in the Scene, Entity and Component classes needed by the network synchronization.

Scene

scene.createEntity(id, changeType)

Create an empty entity into the scene. ID 0 will assign the next available. The change type decides whether to create a replicated (Replicate) or local (LocalOnly) entity.

scene.removeEntity(id, changeType)

Remove an entity by ID.

scene.entityById(id)

Return an entity by ID, or no entity if not found.

scene.entityByName(name)

Return an entity by string name. The name is contained in its Name component.

Entity

entity.createComponent(id, typeId, name, changeType)

Create a component to the entity. ID 0 will assign the next available. The typeId can be a string (such as "Mesh" or "Placeable") or an integer type value that is used internally in the network protocol for optimization. Components can be optionally given a string name.

entity.removeComponent(id, changeType)

Remove a component from the entity by ID.

entity.removeAllComponents(changeType)

Remove all components from the entity.

entity.triggerAction(name, params, execType)

Signal an RPC-like Entity Action. The action is identified with its string name, and the parameters are an array of strings. The execution type is a bit combination of the following constants: cExecTypeLocal, cExecTypeServer, cExecTypePeers, which means to either execute the action only locally, send it to the server, or to send it to all connected clients via the server.

The network synchronization of the action is also implemented through a signal, "actionTriggered", that the SyncManager hooks into.

entity.componentById(id)

Return a component from the entity by ID, or no component if not found.

entity.componentByType(typeId, name)

Return a component from the entity by its type, which can be a string or an integer type number. Optionally limit the query to components with the specified name.

Component

component.createAttribute(index, typeId, name, value, changeType)

Create a dynamic attribute to the component. Index starts from zero and should be allocated sequentially. Currently only the DynamicComponent supports dynamic attributes. Type id is a string name identifying the type (such as "string", "float3" or "bool"), or an integer type value that is used internally in the network protocol for optimization.

component.removeAttribute(index, changeType)

Remove a dynamic attribute by its zero-based index.

component.attributeById(id)

Returns an attribute by its string ID. The ID is a short identifier starting with a lowercase letter which is also the same as the property name of the attribute for shorthand access (ie. component.attributeName)

component.attributeByName(name)

Returns an attribute by its string name. This is separate from the ID and should be a longer descriptive name that is shown in eg. editor tools. Note that for dynamic attributes the ID and the name can not be separately specified, but are set to the same string value.

registerCustomComponent(typeName, blueprintComponent, changeType)

Registers a custom static-structured component. Its attribute structure (described by a "blueprint" component that should have been created beforehand) will be sent to the server the next time syncManager.sendChanges() is called. After that components of the new type can be created both on the client and the server.

Scene synchronization

To begin synchronizing scene content with the server, the Scene and SyncManager objects need to be created. On construction, the SyncManager needs to be given a WebSocketClient object that is connected to a server and a Scene, preferably empty of entities.

var syncManager = new SyncManager(webSocketClient, scene);

After this, the SyncManager automatically receives scene modification messages from the server and applies the changes to the Scene. To send pending changes made on the client side back to the server, the following function on the SyncManager needs to be called:

syncManager.sendChanges()

Binary protocol description

The binary messages sent between the client and server are described in detail in following document: Tundra protocol

In a WebSocket implementation, each message is sent as one binary WebSocket frame, with the message ID encoded as an unsigned little-endian 16-bit value in the beginning.

Model of operation in pseudocode

Implementing a synchronization client is easier than a server, as it does not need to handle several connections. A client needs only to listen to the binary protocol messages as they arrive from the server, and perform them on its local scene. It also needs to listen to the change signals from the local scene, and send those that have the change type Replicated back to the server.

The server, on the other hand, should for efficiency operate on network "ticks" or "frames" that happen for example 20 or 30 times per second. It collects all the scene changes up to the next tick, then processes them in a batched manner. If for example the position in an entity's Transform component changes several times before the next tick, only the latest data should be sent to conserve bandwidth.

The server needs to maintain a structure, called here the SyncState, for each client connections that contains the list of "dirty" (contains changes that need to be sent) entities, components and attributes. When it is time to perform the next network tick, the default (naive) operation mode is to go through this structure for all client connections, and send all pending changes. More intelligent per-client operations such as interest management (throttling the update rate or excluding updates completely for far away entities) or overall bandwidth throttling can be performed. In pseudocode, the algorithm for going through the SyncState of a client is the following:

Go through any newly registered component types. Send them to the client
Go through all dirty entities in the SyncState
 If entity was removed, send RemoveEntity message
 If entity is new for the client, send CreateEntity message with full component and attribute data
 Otherwise go through its dirty components
  If component was removed, collect it into a RemoveComponents message
  If component is new for the client, collect it into a CreateComponents message with full attribute data
  Otherwise go through its dirty attributes
   If attribute is dynamic and was removed, collect it into a RemoveAttributes message
   If attribute is dynamic and is new for the client, collect it into a CreateAttributes message
   Otherwise (the attribute is modified) collect it into an EditAttributes message
  Send RemoveComponents, CreateComponents, RemoveAttributes, CreateAttributes, EditAttributes messages that have data in them
  Clear the dirty status for the entity and all its components & attributes
Personal tools
Create a book