This page is aimed at people who already use and understand SpatialOS, but aren’t familiar with layers yet.
What layers are
You can look at layers in two ways:
- A layer is a group of components on entities in the game world.
- A layer comprises the worker instances that have authority over one of those groups.
To explore that in more detail: for the entities in the world, you split their components up into layers: groups where the same type of worker should have authority over all of the group. This determines which worker type should have authority over the component.
Then, for each layer, you can decide separately how to load-balance the worker instances responsible for simulating the layer.
For example: for a layer involving the physics in the world, you might need quite a few worker instances to handle the work of that layer; but for a layer that involves managing a chat system, you might only need one worker instance for the whole world.
Thinking about authority and layers
In the old paradigm, you used an entity’s ACL to specify that a particular type of worker had permission to write to particular components on that entity, and this would imply that a worker meeting those permissions should simulate those components. With layers, you’re explicitly specifying that you want a particular type of worker to simulate a particular set of components on the entity.
By making a component part of a layer, you’re saying: if a worker instance is authoritative over one of these
components (for example,
Position) of a given entity, it should be authoritative over all of the components of
that entity that are also part of the layer (for example,
What about clients?
Clients aren’t part of layers, and neither are the components they have authority over. If you want a client to have authority over a component, you leave that component out of layers, and specify that it’s assigned to that specific client instance instead.
How to use layers
This isn’t a huge change organisationally from the current system of ACLs and authority, but it is a little simpler conceptually.
For each component on an entity:
- Before layers: You specified a worker requirement set that a worker instance would have to match in order to be able to get authority over the component. This was the ACL component: a map of components to worker requirement sets.
- With layers: You specify which layer the component is part of. (At the moment, this is still done using the ACL component.) Like the ACL component, this is a map, but of components to layers. For clients, you specify the specific worker instance instead of the layer, as before.
For each type of worker:
- Before layers: In the launch configuration file, for each worker type, you specified a load balancing configuration for the worker type - how many worker instances to start of that type, and how to split the world up between them. In the worker’s configuration file, you specified a worker attribute, to match up to what’s in the ACL.
- With layers: In the launch configuration file, for each layer, you specify a load balancing configuration - how many worker instances to start, and how to split the world up between them. In the worker’s configuration file, specifically within the bridge field, you specify which layer the worker simulates. Currently, a worker type can only be responsible for one layer.
We’ve introduced layers for a few reasons:
- Modularising game systems: layers allow you to express modularity in your game - discrete game systems that don’t depend much on each other.
- Layers make it easier to express and reason about projects that have many types of workers.
- Layers are a simpler, clearer way to express splitting up authority.
This version of layers is a starting point towards a future where you could use layers to bring in worker types that other people have built into your game. In this system, the components in schema could effectively act as a public interface: if you add the components to your entities, you can add in that worker type to simulate those components, and not worry about the internal implementation of that worker type.