Serverless Multiplayer
Sync scene state between players.
Decentraland runs scenes locally in a player's browser. By default, players are able to see each other and interact directly, but each player interacts with the environment independently. Changes in the environment aren't shared between players by default.
Seeing the same content in the same state is extremely important for players to interact in more meaningful ways.
There are three ways to sync the scene state, so that all players see the same:
Mark an entity as synced: The easiest option. See Marked an entity as synced
Send Explicit MessageBus Messages: Manually send and listen for specific messages. See Send explicit MessageBus messages
Use a Server: See 3rd party servers. This option is more complicated to set up, but is recommendable if players have incentives to exploit your scene.
The first two options are covered in this document. They are simpler, as they require no server. The downside is that you rely more on player's connection speeds, and the scene state is not persisted when all players leave the scene.
Mark an Entity as Synced
In the Creator Hub, mark an entity as synced by adding a Multiplayer component to it. It includes a checkbox for each of the other components on the entity, allowing you to select which ones to update.

To mark an entity as synced via code, use the syncEntity function:
The syncEntity function takes the following inputs:
entityId: A reference to the entity to sync
componentIds: A list of the components that need to be synced from that entity. This is an array that may contain as many entities as needed. All values should be
componentIdproperties.entityEnumId: (optional) A unique id that is used consistently by all players, see About enum id.
Not all entities or components need to be synced. Static elements like a tree that remains in the same spot don't require syncing. On entities you do sync, only the components that change over time should be synchronized. For example, if a cube changes color when clicked, you should only sync the Material component, not the MeshRenderer or the Transform, as those will never change.
About the enum id
The entityEnumId of an entity must be unique. It's not related to the local entityId assigned on engine.addEntity(), that is automatically generated and may vary between players running the same scene. The entityEnumId of an entity must be explicitly defined in the code and be unique.
Explicitly setting this ID is important to avoid inconsistencies if a race condition makes one part of the scene load before another. Maybe for player A the door in the scene is the entity 512, but for player B that same door is entity 513. In that case, if player A opens the door, player B instead sees the whole building move.
📔 Note: Avoid using numbers that are higher than 8001 if your scene also includes Smart Items. Items that are created by the Creator Hub with a Multiplayer component will use automatically assigned IDs from 8001 up. Any ID lower than 8001 is safe to assign to your synced entities.
Entities created by a player
If an entity is created as a result of a player interaction, and this entity should be synced with other players, the entity doesn't need an entityEnumId. You can use syncEntity() passing only the entity and the list of components. A unique value for entityEnumId is assigned automatically behind the curtains.
All entities instanced on scene initiation need to have a manually-assigned ID. That's to ensure that all players use the same ID on each. When a single player is in charge of instancing an entity, explicit IDs are not needed. Other players get updates about this new entity with an ID already assigned, so there is no risk of ID mismatches.
For example, in a snowball fight scene, every time a player throws a snowball, they're instancing a new entity that gets synced with other players. The snowball doesn't need a unique entityEnumId.
Parented entities
The parent of an entity is normally defined via parent property in the Transform component. This property however points to the local entity id of the parent, which could vary, see About enum id. To parent entities that need to be synced, or that have children that need to be synced, use the parentEntity() function instead of the Transform.
Note that both the parent and the child are synced with syncEntity, so all players have a common understanding of what ids are used by both entities. This is necessary even if the parent's components may never need to change. In this example, the syncEntity includes an empty array of components, to avoid syncing any unnecessary components.
📔 Note: If an entity is parented by both the parentEntity() and also the parent property in the Transform component, the property in the Transform component is ignored.
When entities are parented via the parentEntity() function, you can also make use of the following helper functions:
removeParent(): Undo the effects of
parentEntity(). It requires that you pass only the child entity. The entity's new parent becomes the scene's root entity. The original parent entity is not removed from the scene.getParent(): Returns the parent entity of an entity you passed.
getChildren(): Returns the list of children of the entity you passed, as an iterable.
getFirstChild(): Returns the first child on the list for the entity you passed.
Check the sync state
When a player just loads into a scene, they may not yet be synchronized with other players surrounding them. If the player starts altering the state of the game before they are synced, this could cause problems in your game. We recommend always checking for a player to be synchronized before they are allowed to edit anything about the scene.
If a player steps out of the parcels of the scene, they will also be out of sync with the scene while they're standing outside. So it's also important that the scene's systems handle that scenario, as the scene keeps running while the player is nearby. Once the player steps back in, they are updated automatically with any changes from the scene's state.
You can check if the scene state is currently synced for a player via the isStateSyncronized() function. This function returns a boolean, that is true if the player is already synchronized with the scene.
You could for example include this check in a system, and block any interaction if this function returns false.
Send Explicit MessageBus Messages
Initiate a message bus
Create a message bus object to handle the methods that are needed to send and receive messages between players.
Send messages
Use the .emit command of the message bus to send a message to all other players in the scene.
Each message can contain a payload as a second argument. The payload is of type Object, and can contain any relevant data you wish to send.
Receive messages
To handle messages from all other players in that scene, use .on. When using this function, you provide a message string and define a function to execute. For each time that a message with a matching string arrives, the given function is executed once.
📔 Note: Messages that are sent by a player are also picked up by that same player. The .on method can't distinguish between a message that was emitted by that same player from a message emitted from other players.
Full MessageBus example
This example uses a message bus to send a new message every time the main cube is clicked, generating a new cube in a random position. The message includes the position of the new cube, so that all players see these new cubes in the same positions.
Test a multiplayer scene locally
If you launch a scene preview and open it in two (or more) different explorer windows, each open window will be interpreted as a separate player, and a mock communications server will keep these players in sync.
Interact with the scene on one window, then switch to the other to see that the effects of that interaction are also visible there.
Using the Creator Hub, click the Preview button a second time, and that opens a second Decentraland explorer window. You must connect on both windows with different addresses. The same sessions will remain open as the scene reloads.

As an alternative, you can open a second Decentraland explorer window by writing the following into a browser URL:
decentraland://realm=http://127.0.0.1:8000&local-scene=true&debug=true&open-deeplink-in-new-instance=true
Single player scenes
If your scene is deployed to a Decentraland World, you can make it a single player scene. Players won't see each other, won't be able to chat or see the effects of each other's actions.
To do this, configure the scene's scene.json file to set the fixedAdapter to offline:offline. The scene will have no Communication Service at all and each user joining that world will always be alone.
Example:
Last updated