Multijugador sin servidor
Sincroniza el estado de la escena entre jugadores.
Decentraland ejecuta escenas localmente en la instancia del explorer de un jugador. De forma predeterminada, los jugadores pueden verse entre sí e interactuar directamente, pero cada jugador interactúa con el entorno de manera independiente. Los cambios en el entorno no se comparten entre jugadores por defecto.
Ver el mismo contenido en el mismo estado es extremadamente importante para que los jugadores interactúen de formas más significativas.
Hay tres formas de sincronizar el estado de la escena, para que todos los jugadores vean lo mismo:
Marcar una entity como sincronizada: La opción más sencilla. Ver Marcar una entity como sincronizada
Enviar mensajes explícitos de MessageBus: Enviar y escuchar manualmente mensajes específicos. Ver Enviar mensajes explícitos de MessageBus
Usar un Server: Ver servers de terceros. Esta opción es más complicada de configurar, pero es recomendable si los jugadores tienen incentivos para explotar tu escena.
Las dos primeras opciones se cubren en este documento. Son más sencillas, ya que no requieren un server. La desventaja es que dependes más de la velocidad de conexión de los jugadores, y el estado de la escena no se persiste cuando todos los jugadores salen de la escena.
Marcar una Entity como sincronizada
En el Creator Hub, marca una entity como sincronizada agregando un Multiplayer component a ella. Incluye una casilla de verificación para cada uno de los otros componentes de la entity, lo que te permite seleccionar cuáles actualizar.

Para marcar una entity como sincronizada mediante código, usa la syncEntity función:
La syncEntity función toma las siguientes entradas:
entityId: Una referencia a la entity que se va a sincronizar
componentIds: Una lista de los componentes que necesitan sincronizarse de esa entity. Es un array que puede contener tantas entities como sea necesario. Todos los valores deben ser propiedades
componentId.entityEnumId: (opcional) Un id único que se usa de forma consistente por todos los jugadores, ver Acerca del enum id.
No todas las entities o componentes necesitan sincronizarse. Los elementos estáticos, como un árbol que permanece en el mismo lugar, no requieren sincronización. En las entities que sí sincronizas, solo los componentes que cambian con el tiempo deben sincronizarse. Por ejemplo, si un cubo cambia de color cuando se hace Click, solo deberías sincronizar el componente Material, no el MeshRenderer ni el Transform, ya que estos nunca cambiarán.
💡 Consejo: Si los datos que quieres compartir no existen como un componente, define un componente personalizado que contenga esos datos.
Acerca del enum id
La entityEnumId de una entity debe ser único. No está relacionado con el entityId local asignado en engine.addEntity(), que se genera automáticamente y puede variar entre jugadores que ejecutan la misma escena. El entityEnumId de una entity debe definirse explícitamente en el código y ser único.
Establecer explícitamente este ID es importante para evitar inconsistencias si una condición de carrera hace que una parte de la escena cargue antes que otra. Tal vez para el jugador A la puerta de la escena sea la entity 512, pero para el jugador B esa misma puerta sea la entity 513. En ese caso, si el jugador A abre la puerta, el jugador B ve en su lugar cómo se mueve todo el edificio.
💡 Consejo: Crea un enum en tu escena para mantener referencias claras a cada id sincronizable en tu escena.
Aquí el enum EntityEnumId se usa para etiquetar entities con un identificador único, asegurando que cada client reconozca la entity modificada, independientemente del orden de creación.
📔 Nota: Evita usar números que sean mayores que 8001 si tu escena también incluye Smart Items. Los Items que son creados por el Creator Hub con un Multiplayer component usarán IDs asignados automáticamente a partir de 8001. Cualquier ID menor que 8001 es seguro para asignar a tus entities sincronizadas.
Entities creadas por un jugador
Si una entity se crea como resultado de la interacción de un jugador, y esta entity debe sincronizarse con otros jugadores, la entity no necesita un entityEnumId. Puedes usar syncEntity() pasando solo la entity y la lista de componentes. Un valor único para entityEnumId se asigna automáticamente entre bastidores.
Todas las entities instanciadas al iniciar la escena necesitan tener un ID asignado manualmente. Eso es para asegurar que todos los jugadores usen el mismo ID en cada una. Cuando un solo jugador se encarga de instanciar una entity, no se necesitan IDs explícitos. Los demás jugadores reciben actualizaciones sobre esta nueva entity con un ID ya asignado, por lo que no hay riesgo de desajustes de ID.
Por ejemplo, en una escena de pelea de bolas de nieve, cada vez que un jugador lanza una bola de nieve, está instanciando una nueva entity que se sincroniza con otros jugadores. La bola de nieve no necesita un entityEnumId único.
Entities parentadas
El parent de una entity normalmente se define mediante parent propiedad en el Transform component. Sin embargo, esta propiedad apunta al id local de la entity del parent, que podría variar, ver Acerca del enum id. Para parentar entities que necesiten ser sincronizadas, o que tengan children que necesiten ser sincronizados, usa la parentEntity() función en lugar de la Transform.
Ten en cuenta que tanto el parent como el child se sincronizan con syncEntity, de modo que todos los jugadores tengan una comprensión común de qué ids usan ambas entities. Esto es necesario incluso si es posible que los componentes del parent nunca necesiten cambiar. En este ejemplo, el syncEntity incluye un array vacío de componentes, para evitar sincronizar cualquier componente innecesario.
📔 Nota: Si una entity tiene parent tanto por el parentEntity() como también por el parent propiedad en el Transform component, la propiedad en el Transform component se ignora.
Cuando las entities se parentan mediante la parentEntity() función, también puedes usar las siguientes funciones auxiliares:
removeParent(): Deshace los efectos de
parentEntity(). Requiere que solo pases la child entity. El nuevo parent de la entity pasa a ser la root entity de la scene. La entity parent original no se elimina de la scene.getParent(): Devuelve la entity parent de una entity que pasaste.
getChildren(): Devuelve la lista de children de la entity que pasaste, como un iterable.
getFirstChild(): Devuelve el primer child de la lista para la entity que pasaste.
Comprobar el estado de sincronización
Cuando un jugador acaba de cargar una escena, es posible que aún no esté sincronizado con los demás jugadores que lo rodean. Si el jugador empieza a alterar el estado del juego antes de estar sincronizado, esto podría causar problemas en tu juego. Recomendamos comprobar siempre que un jugador esté sincronizado antes de permitirle editar cualquier cosa de la escena.
Si un jugador sale de los parcels de la escena, también estará fuera de sincronización con la escena mientras permanezca afuera. Así que también es importante que los systems de la escena manejen ese escenario, ya que la escena sigue ejecutándose mientras el jugador esté cerca. Una vez que el jugador vuelve a entrar, se actualiza automáticamente con cualquier cambio del estado de la escena.
Puedes comprobar si el estado de la escena está sincronizado actualmente para un jugador mediante la isStateSyncronized() función. Esta función devuelve un boolean, que es true si el jugador ya está sincronizado con la escena.
Por ejemplo, podrías incluir esta comprobación en un system y bloquear cualquier interacción si esta función devuelve false.
Enviar mensajes explícitos de MessageBus
Iniciar un message bus
Crea un objeto message bus para manejar los métodos necesarios para enviar y recibir mensajes entre jugadores.
Enviar mensajes
Usa el .emit comando del message bus para enviar un mensaje a todos los demás jugadores en la escena.
Cada mensaje puede contener un payload como segundo argumento. El payload es de tipo Object, y puede contener cualquier dato relevante que desees enviar.
💡 Consejo: Si necesitas que un solo mensaje incluya datos de más de una variable, crea un tipo personalizado para contener todos esos datos en un solo objeto.
Recibir mensajes
Para manejar mensajes de todos los demás jugadores en esa escena, usa .on. Al usar esta función, proporcionas una cadena de mensaje y defines una función a ejecutar. Cada vez que llega un mensaje con una cadena coincidente, la función dada se ejecuta una vez.
📔 Nota: Los mensajes enviados por un jugador también son captados por ese mismo jugador. El .on método no puede distinguir entre un mensaje emitido por ese mismo jugador y un mensaje emitido por otros jugadores.
Ejemplo completo de MessageBus
Este ejemplo usa un message bus para enviar un nuevo mensaje cada vez que se hace Click en el cubo principal, generando un nuevo cubo en una posición aleatoria. El mensaje incluye la posición del nuevo cubo, de modo que todos los jugadores vean estos nuevos cubos en las mismas posiciones.
Probar localmente una escena multijugador
Si lanzas una vista previa de la escena y la abres en dos (o más) ventanas diferentes del explorer, cada ventana abierta se interpretará como un jugador distinto, y un server de comunicaciones simulado mantendrá a estos jugadores sincronizados.
Interactúa con la escena en una ventana y luego cambia a la otra para ver que los efectos de esa interacción también son visibles allí.
Usando el Creator Hub, haz Click en el botón Preview una segunda vez, y eso abre una segunda ventana del explorer de Decentraland. Debes conectarte en ambas ventanas con direcciones diferentes. Las mismas sesiones permanecerán abiertas mientras la escena se recarga.

Como alternativa, puedes abrir una segunda ventana del explorer de Decentraland escribiendo lo siguiente en una URL del navegador:
decentraland://realm=http://127.0.0.1:8000&local-scene=true&debug=true&open-deeplink-in-new-instance=true
Escenas de un solo jugador
Si tu escena se despliega en un Decentraland World, puedes convertirla en una escena de un solo jugador. Los jugadores no se verán entre sí, no podrán chatear ni ver los efectos de las acciones de los demás.
Para hacer esto, configura el archivo scene.json de la escena para establecer fixedAdapter en offline:offline. La escena no tendrá ningún Communication Service en absoluto y cada usuario que se una a ese World siempre estará solo.
Ejemplo:
Última actualización