Skip to main content

EN Facade

EN (FigNet.Entangle.EN) is the static entry point a Unity game developer calls day to day for the Entangle module: connecting, authenticating, and driving room/lobby flow. It is defined in Assets/Modules/Entangle/Core/Entangle.cs.

The .NET server side (Entangle/EN.cs) defines a class with the same name and mostly the same shape - Room/Lobby/MatchMaker members, the same connection lifecycle, the same auth flow - because both sides implement the same protocol as hand-ported, duplicated code (see Repo Shape). It is used by server-side module code that needs to act as an Entangle client itself (or during testing), not by a typical Unity game. The two copies do diverge in real ways, called out inline below; where nothing is called out, assume the two match.

Everything on this page is copy-verified from the Unity Entangle.cs, plus Lobby.cs/Room.cs for the room/lobby operations that hang off EN.Lobby / EN.Room, since those are the calls a game actually makes.

Connection state and identity

public static bool IsConnected { get; }
public static bool IsAuthenticated { get; }
public static bool IsMasterClient { get; }
public static string UserId { get; }
public static string SessionId { get; }
public static IClientSocket Socket { get; }
public static bool IsInGame { get; set; }
public static uint MyTeamId { get; set; }
public static uint MyPlayerId { get; set; }
public const string Version;
  • IsAuthenticated/UserId/SessionId are populated after the internal AuthenticateSession() completes (fired automatically on OnConnected, see below) - not something you call directly.
  • Version mirrors the codegen'd module manifest (FigNetModules.Entangle.Version) on the Unity side; it's compared against the server at connect-time as part of the module version handshake. The server-side copy hardcodes it as a "2.0.0" literal instead of reading a manifest.

Setup

public static void Initialize();
public static void SetConfig(EntangleConfig config);
public static void SetDeviceIdentity(string deviceId, string displayName = null);
public static void SetAuthToken(string token, string deviceId = null, string displayName = null);
  • Initialize() wires up the MemoryPack serializer, constructs EN.Room/EN.Lobby/EN.MatchMaker, calls Lobby.Initialize() (registers Entangle's message handlers), and subscribes the internal reconnect/auth handlers. Call once at startup before Connect().
  • SetConfig(config) stores the EntangleConfig (app id, device id, auth mode/credential, room defaults such as cell size / AOI activation count / retention policy) that Connect() and Lobby.CreateRoom read from.
  • SetDeviceIdentity / SetAuthToken override the device id / display name / auth credential set by SetConfig, useful when you resolve identity after config load (e.g. from a login screen).

Connecting

public static void Connect();
public static void Disconnect();
public static void ReconnectAndJoin();
  • Connect() builds a PeerConfig from EN.Config and opens (or reconnects) the client socket. On success the OnConnected event fires, which internally triggers AuthenticateSession() - authentication is automatic, you don't call it yourself.
  • ReconnectAndJoin() sets an internal "reconnect in progress" flag, fires OnReconnectStarted, then calls Connect(). When auth completes afterward, if EntangleConfig.EnableAutoRoomReJoinOnReconnect is set and you were IsInGame, it automatically calls Lobby.ReJoinRoom for the room you were in.
  • Disconnect() is a no-op unless IsConnected and Socket is non-null.
public static int GetPing();

Returns Socket.Ping, or 0 if there's no socket yet (the server-side copy returns -1 in that case instead).

Cluster / discovery mode (Unity-only)

These helpers exist only in the Unity EN - the server-side EN.cs has no discovery layer:

public static bool IsClusterMode { get; }
public static void GetRooms(RoomQuery query, Action<List<RoomInfoData>> callBack);
public static void ConnectToRoom(string roomName, Action<bool> onResult = null);
public static void ConnectToRoom(uint roomId, Action<bool> onResult = null);
  • IsClusterMode reflects whether EntangleConfig.DiscoveryUrl is configured.
  • GetRooms lists cluster-wide rooms via the discovery WebSocket when configured, otherwise falls back to Lobby.GetRooms against the currently connected server.
  • ConnectToRoom(name) / ConnectToRoom(id) resolve which node hosts the room via discovery, point EN.Config at that node's ServerIp/Port, then call Connect(). In single-node mode (no DiscoveryUrl) they just call Connect() directly. Authentication runs automatically on connect; call EN.Lobby.JoinRoom afterward (e.g. from OnAuthenticationCompleted) to actually enter the room - resolving/connecting to the right server does not by itself join it.

Events

public static event Action OnConnected;
public static event Action OnDisconnected;
public static event Action<PeerStatus> OnNetworkStatusChanged;
public static event Action<RoomResponseCode> OnRoomAutoReJoinStatus;
public static event Action<DeviceAuthResponseCode> OnAuthenticated;
public static event Action<AuthResponseCode> OnAuthenticationCompleted;
public static event Action<Message> OnNetworkReceive;
public static event Action<Message, DeliveryMethod, byte> OnNetworkSent;
public static event Action OnReconnectStarted;
public static event Action OnReconnectRestored;
public static event Action OnRoomRejoinSucceeded;
public static event Action<RoomResponseCode> OnRoomRejoinFailed;
public static Action<bool> OnMasterClientUpdate;

OnNetworkReceive and OnNetworkSent exist only on the Unity side (the server-side listener does not re-raise them as EN events). OnAuthenticated is a legacy-shaped event (DeviceAuthResponseCode) kept for compatibility; prefer OnAuthenticationCompleted (AuthResponseCode) in new code - both fire from the same auth completion.

Logging

public static ModuleLog Log { get; }
public static LoggingLevel LoggingLevel { get; set; }
public static void Diagnostic(string area, string message, LogType level = LogType.Info);
  • Log is the shared zero-alloc templated logger (backed by FigNetCommon.Utils.Log); prefer EN.Log.Log(...) over the older EN_Internals.Log(...) path in new code. This property does not exist on the server-side EN at all - the server-side copy has no Log property.
  • LoggingLevel is a compatibility shim over Log.MinLevel using the module's LoggingLevel enum (None/Info/Debug/All) on the Unity side only. The server-side EN.LoggingLevel is a plain { get; set; } auto-property with no Log to back onto (matching EN_Internals.IsLoggingEnabled's own level-comparison logic instead).
  • Diagnostic writes straight to UnityEngine.Debug regardless of LoggingLevel, for periodic health/telemetry lines only (not per-frame spam) - mirrors FV.Diagnostic on the FnVoice side. This method does not exist on the server-side EN.

Rooms and lobby

Room/lobby operations live on EN.Room and EN.Lobby (constructed by Initialize()), not directly on EN. Both Room and Lobby are identically shaped on the server-side EN.cs.

public static Room Room { get; }
public static Lobby Lobby { get; }
public static MatchMaker MatchMaker { get; }

MatchMaker is currently an empty stub class (constructed but with no members) on both sides - matchmaking is not yet implemented behind it.

Create

public static void CreateRoom(string roomName, ushort maxPlayers, string password, Action<RoomResponseCode, uint> callBack);
public static void CreateRoom(string roomName, ushort maxPlayers, string password, RoomExecutionMode mode, string gameName, Action<RoomResponseCode, uint> callBack);
public static void CreateRoom(string roomName, ushort maxPlayers, string password, RoomExecutionMode mode, string gameName, RoomAuthorityMode authorityMode, OrphanedEntityPolicy orphanedEntityPolicy, Action<RoomResponseCode, uint> callBack);

Called as EN.Lobby.CreateRoom(...). Room-wide defaults (cell size, width/length, AOI activation count, LOD level, forced state-sync interval, empty-room/inactive-player retention) come from the EntangleConfig passed to EN.SetConfig. Pass an empty password for a public room. The three-arg-tail overload lets you set RoomAuthorityMode (who may write room-wide state: MasterOnly default or AnyMember) and OrphanedEntityPolicy (what happens to a departing player's entities: TransferToMaster default or Delete) - entity writes themselves are always owner-scoped regardless of these. On success this sets EN.Room.RoomId/ RoomName/Mode/GameName and marks the caller as master client. Aborts with RoomResponseCode.Failure if not connected/authenticated.

List

public static void GetRooms(RoomQuery query, Action<List<RoomInfoData>> callBack);

Called as EN.Lobby.GetRooms(...) (or via EN.GetRooms, which additionally routes through cluster discovery when configured - see above). query selects All vs. only-available rooms; each RoomInfoData carries id, name, max players, active player count, and state.

Join / rejoin

public static void JoinRoom(uint roomId, string password, uint teamId, string userName, Action<RoomResponseCode> onRoomJoin);
public static void ReJoinRoom(uint roomId, string password, uint teamId, string roomAuthToken = "", Action<RoomResponseCode> onRoomJoin = default);

Called as EN.Lobby.JoinRoom(...) / EN.Lobby.ReJoinRoom(...). JoinRoom aborts (and calls back with AlreadyInRoom) if you're already IsInGame, or with Failure if not connected/authenticated. On success it applies the returned RoomState snapshot into EN.Room and marks EN.IsInGame = true. ReJoinRoom is the disconnect/reconnect-recovery path (uses a roomAuthToken instead of re-authenticating identity) - it is not meant for an explicit fresh join, and is what EN.ReconnectAndJoin's auto-rejoin calls internally.

Leave

public static void LeaveRoom(Action<RoomResponseCode> onRoomLeft);

Called as EN.Lobby.LeaveRoom(...). On Sucess or RoomNotFound it tears down local room state (EN.Room.Deinit()). Note this deliberately does not clear the auto-rejoin path the way ReJoinRoom expects - an explicit LeaveRoom is not something ReJoinRoom will restore afterward.

Room state (on EN.Room)

public uint RoomId { get; set; }
public string RoomName { get; set; }
public string Password { get; set; }
public string RoomAuthToken { get; set; }
public RoomExecutionMode Mode { get; set; }
public string GameName { get; set; }
public int MaxPlayer { get; set; }
public uint MyPlayerId { get; set; }
public bool IsLocked { get; set; }
public int RoomState { get; set; }
public List<NetPlayer> Players;
public List<NetAgent> Agents;
public List<NetItem> Items;
public readonly List<RoomEventData> CachedEvents;
public static event Action OnRoomCreate;
public static event Action OnRoomDispose;
public static event Action<int> OnRoomStateChanged;
public static event Action<NetPlayer> OnPlayerJoined;
public static event Action<NetPlayer> OnPlayerLeft;
public static event Action<NetworkEntity, Vector3, Vector4, Vector3> OnEntityCreated;
public static event Action<NetworkEntity> OnEntityDeleted;
public static event Action<uint, EN_RoomEvent> OnEventReceived;
public static event Action<uint, RoomEventData> OnChachedEventRemoved;

Most day-to-day gameplay code subscribes to these Room events rather than polling. Players/Agents/Items are the live roster of networked entities in the current room.

public static void SendEvent(EN_RoomEvent eventData, bool isEncrypted = false);
public bool AddCachedEvent(RoomEventData eventData);
public void RemoveCachedEvent(RoomEventData eventData);
public static void SendRemoveCachedEvent(RoomEventData eventData);
public static void SendRemoveAllCachedEvent(byte eventId, byte tag);
public static void SetRoomState(int state, bool isLock);
public static void SendCreateOrJoinGroup(byte tag);
public static void SendLeaveGroup(byte tag);
public void FetchRoomState();

SendEvent throws if eventData.eventData is null (use its SetData method first); it also silently drops the event (and returns the pooled object) if the client-side flood-gate budget for events is exhausted. SetRoomState changes the shared room-state integer and lock flag. SendCreateOrJoinGroup/SendLeaveGroup manage custom group membership (tag-scoped broadcast groups). These are documented here because they're common per-frame/per-action calls; the full entity subscription/AOI surface is out of scope for this page.

Notes on what's intentionally skipped

Internal plumbing not part of the day-to-day public surface is skipped: EN_Internals (backing fields, log-level plumbing), ClientSocketEventListner (the private IClientSocketListener implementation wiring socket events to EN's public events), AuthenticateSession/ResolveDeviceId/ResolveDisplayName/GetServerConfigToConnect/ TryAutoRejoinRoom/MapLegacyAuthResponse (private helpers behind Connect/auth), and Room's per-tick batching internals (Tick, FlushUpdateBatch, FlushStateBatch, the CachedEventStore class) - these are the mechanics behind area-of-interest/state replication, covered separately in Area of Interest rather than on this facade-reference page.