Room Execution Modes
Every Entangle room runs in one of three execution modes, set once at room creation via RoomExecutionMode:
ClientRelayedAuthoritativeHybrid
The mode controls how gameplay traffic - entity instantiation/deletion, entity state and transform updates,
ownership requests, and room events - is handled between clients in the room. All three modes share the same
room lifecycle and join flow: CreateRoom -> JoinRoom -> RoomState. RoomState is the bootstrap snapshot
returned on join, rejoin, and forced resync in every mode, and it carries the room's Mode and GameName
alongside the usual players, entities, and room property data - so a client never needs a second bootstrap
message to know what kind of room it joined.
The three modes
ClientRelayed
The default mode, and Entangle's original behavior. Clients drive room entities, room events, ownership, and
transforms directly; the server relays these operations between peers in the room. No server-side room plugin
is loaded. Room.SendEvent(...) follows the normal relay path, including area-of-interest, custom-group,
presenter, and cached-event behavior.
Authoritative
The room loads a server-side room plugin (a class implementing IEntangleRoom - see
Writing a Server Game for Entangle) that is authoritative for gameplay. Clients
still join through the normal JoinRoom/ReJoinRoom flow and still receive RoomState, but client-driven
relayed gameplay operations are rejected once in the room:
- instantiate entity
- delete entity
- entity state / transform updates
- ownership request / clear ownership
- room event relay
- room state / lock changes
Room.SendEvent(...) is delivered to the room plugin's OnRoomEventReceived(senderId, eventData) instead of
being relayed to other clients.
Hybrid
The room loads a server-side room plugin the same way Authoritative does, but the relayed entity/state/
ownership flow stays enabled alongside it - the room plugin runs with full room context while relayed gameplay
operations continue to work as they do in ClientRelayed.
For room events specifically, Hybrid behaves the same as Authoritative: Room.SendEvent(...) reaches the
room plugin's OnRoomEventReceived(...) and is not auto-relayed. If the plugin wants clients to observe
something as a result, it does so explicitly - by broadcasting a room event, updating RoomProperty or entity
state, or changing room state.
Selecting a mode at room creation
Mode and plugin selection happen once, on CreateRoomData:
RoomExecutionMode Mode(defaults toClientRelayed)string GameName
The server enforces:
ClientRelayed-GameNameis ignoredAuthoritative/Hybrid-GameNameis required; room creation fails if it is emptyAuthoritative/Hybrid-GameNamemust resolve to an enabled, non-breaker-tripped game plugin, or the request is rejected withRoomResponseCode.GameNotAllowed(see Writing a Server Game for Entangle for the plugin allowlist and loading rules)
Once a room is created, both Mode and GameName are fixed for the room's lifetime. JoinRoom and
ReJoinRoom never choose or change them - they join an already-configured room.
// Client-side room creation
var op = new CreateRoomOperation().GetOperation(
roomName: "Arena-1",
maxPlayers: 8,
mode: RoomExecutionMode.Authoritative,
gameName: "LiarsBar");
Discovery
Room mode and game name are also exposed on room-listing/discovery models (RoomInfoData and the load
balancer's room discovery model), so a room browser can filter or label rooms by execution mode without
joining them first.
Server-side room plugin contract
Authoritative and Hybrid rooms load a plugin implementing IEntangleRoom:
public interface IEntangleRoom
{
void OnInitialize(IEntangleRoomContext context, ILogger logger);
void OnTick(float deltaTime);
void OnPlayerJoined(NetPlayer player);
void OnPlayerLeft(NetPlayer player);
void OnRoomStateChanged(int state, bool isLocked);
void OnRoomEventReceived(uint senderId, RoomEventData eventData);
void OnTerminate();
}
IEntangleRoomContext is the room-scoped surface passed to the plugin. It mirrors what a client already gets
from RoomState:
RoomId,RoomName,Mode,GameName,State,IsLocked,MasterClientIdPlayers,Agents,Items,RoomPropertyInstantiateNetworkEntity(...),DeleteNetworkEntity(...),SetRoomState(...)SendMessageToPeer(...),BroadcastMessage(...)SendRoomEventToPlayer(...),BroadcastRoomEvent(...)
For the full set of rules a room plugin must follow (threading, tick budget, hot-reload, wire-type restrictions), the strike/circuit-breaker behavior, and the ops runbook, see Writing a Server Game for Entangle.
Client-side listener
Client code binds a single listener interface, IEntangleRoomListener, regardless of the room's execution
mode:
public interface IEntangleRoomListener
{
void OnRoomCreated();
void OnRoomDispose();
void PreRoomStateReceived();
void PostRoomStateReceived();
void OnRoomStateChange(int status);
void OnPlayerJoined(NetPlayer player);
void OnPlayerLeft(NetPlayer player);
void OnNetworkEntityCreated(NetworkEntity entity, Vector3 position, Vector4 rotation, Vector3 scale);
void OnNetworkEntityDeleted(NetworkEntity entity);
void OnEventReceived(uint sender, EN_RoomEvent eventData);
}
The same listener works in ClientRelayed, Authoritative, and Hybrid rooms, and room initialization always
begins from RoomState regardless of mode.