Operations: how workers communicate with SpatialOS
If you’re building a worker from scratch with our Worker SDK in C++, C# or Java or writing your own engine integration, you’ll need to learn how workers interact with SpatialOS through operations.
SpatialOS worlds are simulated by a number of workers, each of which has a view on a part of the entire world, consisting of the components they have active read access to. Operations are granular, high-throughput messages sent between workers and SpatialOS. They update each worker on changes within the worker’s local view of the world, and notify SpatialOS of the changes workers make to entities and components they control.
This page gives a high-level overview of operations - defining their purpose and properties in order to give you an idea of how to handle operations when writing a SpatialOS worker.
What are operations?
Operations are messages sent between each worker and SpatialOS, carrying information about updates to workers, entities and components. Workers can subscribe to some or all incoming operations in order to:
- keep local entity and component state in sync with the canonical versions maintained by SpatialOS
- respond to incoming events and commands associated with entities simulated by the worker
- receive and propagate SpatialOS metrics
Operations communicate updates at a granular level - for example, a
ComponentUpdate operation carries information
about a single entity component’s change in value, and may be sent hundreds of times a second to each worker.
The Worker SDK
Connection object is used to receive operations, which can then be passed to a
in order to subscribe custom handlers for each type of operation.
The protocol does not automatically keep track of what entities and components a worker has active read access to. However,
View object is available as a means of keeping track of entities and components present in the worker’s
view of the world.
Operations received by a SpatialOS worker
This section explores all of the operations available in SpatialOS, organised into several groups for ease of reading. Please note that these groups are not reflected in the API itself.
||The worker is disconnected from SpatialOS.|
||A worker flag has been created or deleted, or its value has changed.|
||The SDK issues a log message for the worker to print.|
||The SDK reports built-in internal metrics.|
||A critical section is about to be entered or has just been left.|
||An entity is added to the worker’s view of the world. This operation does not suggest that an entity was created in the world, rather that it has entered the worker’s view.|
||An entity is removed from the worker’s view of the world. This operation does not suggest that the entity has been deleted from the world.|
||The worker has received a response for an entity ID reservation it requested.|
||The worker has received a response for a reservation of an entity ID range it requested.|
||The worker has received a response for an entity creation it requested.|
||The worker has received a response for an entity deletion it requested.|
||The worker has received a response for an entity query it requested.|
||A component is added to an existing entity in the worker’s view of the world.|
||A component is removed from an existing entity in the worker’s view of the world.|
||The worker’s authority state over a component is changed to Authoritative, Not Authoritative or Authority Loss Imminent.|
||A component for an entity in the worker’s view of the world has been updated.|
||The worker has received a command request for a component on an entity over which it has write access authority.|
||The worker has received a command response for a request it issued previously.|
The Dispatcher and the View
Your worker implementation handles data received from SpatialOS using the
Dispatcher object, used to subscribe
a custom handling function for each type of operation received.
Dispatcher does not process the incoming operations in any way: it’s your responsibility to keep track of
the state of the entities and components in your worker’s view. One way to do this would be to keep an in-memory
data structure that keeps track of visible entities and components, and update it when entities and components
are added to and removed from the worker’s view (through the corresponding operations).
Alternatively, you can use the
View object: a special type of dispatcher that automatically keeps track of the
entities and components available in your worker’s local view of the world. It works by reading incoming operations
before passing them to your subscribed handling functions. You can use a
View instance instead of a
instance if your worker needs to keep track of the entities and components in its interest area.
Example of operation handling in a worker implementation
To help you understand how a custom worker may handle operations received from SpatialOS, let’s consider as a scenario a simple world with many non-player characters (NPCs) running on SpatialOS. A particular NPC is moving a large distance across the world, during which it crosses the boundaries of two workers:
The NPC is controlled by an AI running on the workers. There are three important points in time during this scenario:
- When the NPC enters the interest area of worker 2, the worker receives operations containing the data needed to add the NPC to its local view of the world.
- When the NPC leaves the area of authority of worker 1 and enters the area of authority of worker 2, worker 2 receives operations telling it about newly gained write access authority over the NPC. Worker 1 receives operations to allow it to propagate any local AI state to SpatialOS, and revoking its write access authority over the NPCs components.
- When the NPC leaves the interest area of worker 1, the worker receives operations telling it to remove the NPC from its local view.
The diagram below shows some of the operations sent to the workers by SpatialOS, along with a sensible way in which
these operations may be handled by a custom worker implementation. Workers receive many other operations, such as
ComponentUpdate, sent every time the NPCs position changes within the simulation. However, these operations are
not included in the diagram, to make it easier to understand.
Let’s look at the individual operations in the scenario above, when they are sent to workers and how they can be handled.
AddEntity is sent to worker 2 when the NPC moves into the worker’s interest area. This operation tells the worker
that there is a new entity in its local view of the world. We store this information in the worker’s memory using a
sensible data structure - such as a hash map from the entity id to a list of the entity’s components.
AddComponent operations are sent to worker 2 after
AddEntity, in order to inform the worker of all of the
components available on the NPC entity. Each operation provides the data for a particular entity component, allowing
the worker to store this information in-memory. Two
AddComponent operations are received by the worker - one for
the position and another for the ai_state component.
AuthorityChange operations are sent to both worker 1 and worker 2 at different points in time within the scenario.
This type of operation tells workers that their write access authority over a particular component has changed. The values received
in our scenario are:
Authority Loss Imminent- sent to worker 1 when the NPC leaves the worker’s authoritative area. This value alerts the worker that it’s about to lose write access authority over NPC components, giving our implementation a chance to push any in-memory state related to each component to SpatialOS through component updates. In our case, we want to push any state relating to the NPC’s AI (such as the current path followed by the AI) to SpatialOS, so that worker 2 can take over the NPCs simulation where worker 1 left off.
Not Authoritative- sent to worker 1 after
Authority Loss Imminentto tell the worker that it no longer has write access authority over the NPC’s components. We handle this by flagging the write access authority loss on each component, and ensure that our worker implementation stops sending component updates for the NPC.
Authoritative- sent to worker 2 when the NPC enters worker 2’s area of authority. We handle this by flagging the write access authority gain on each component, triggering the worker to begin simulating the NPC using the values in ai_state, picking up from where worker 1 left off.
ComponentUpdate operations are sent to each worker when any of the components on the NPC are updated. Each operation
carries the value of a particular component after the update. For example, as worker 1 simulates the NPC and changes
its position, worker 2 will receive each update as a
ComponentUpdate operation (as long as the NPC is in worker 2’s
checkout area). We handle this operation by writing the new values to the worker’s in-memory store.
RemoveComponent operations are sent to worker 1 when the NPC leaves the worker’s area of authority. These tell
the worker that the component is no longer visible to the worker, and hence that it will no longer receive component
updates for that component. We handle this by removing the component from our in-memory store.
RemoveEntity operations are sent to worker 1 when the NPC leaves the worker’s area of authority, and after every
RemoveComponent operation for the entity. This tells the worker that the entity is no longer visible, and we handle
this by removing the entry for the entity from the worker’s in-memory store.
Now that you have learned about operations, you are ready to build a custom worker or an engine integration for your SpatialOS project! Learn more by reading our C++, C# or Java Worker SDK documentation.