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/SessionIdare populated after the internalAuthenticateSession()completes (fired automatically onOnConnected, see below) - not something you call directly.Versionmirrors 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, constructsEN.Room/EN.Lobby/EN.MatchMaker, callsLobby.Initialize()(registers Entangle's message handlers), and subscribes the internal reconnect/auth handlers. Call once at startup beforeConnect().SetConfig(config)stores theEntangleConfig(app id, device id, auth mode/credential, room defaults such as cell size / AOI activation count / retention policy) thatConnect()andLobby.CreateRoomread from.SetDeviceIdentity/SetAuthTokenoverride the device id / display name / auth credential set bySetConfig, 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 aPeerConfigfromEN.Configand opens (or reconnects) the client socket. On success theOnConnectedevent fires, which internally triggersAuthenticateSession()- authentication is automatic, you don't call it yourself.ReconnectAndJoin()sets an internal "reconnect in progress" flag, firesOnReconnectStarted, then callsConnect(). When auth completes afterward, ifEntangleConfig.EnableAutoRoomReJoinOnReconnectis set and you wereIsInGame, it automatically callsLobby.ReJoinRoomfor the room you were in.Disconnect()is a no-op unlessIsConnectedandSocketis 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);
IsClusterModereflects whetherEntangleConfig.DiscoveryUrlis configured.GetRoomslists cluster-wide rooms via the discovery WebSocket when configured, otherwise falls back toLobby.GetRoomsagainst the currently connected server.ConnectToRoom(name)/ConnectToRoom(id)resolve which node hosts the room via discovery, pointEN.Configat that node'sServerIp/Port, then callConnect(). In single-node mode (noDiscoveryUrl) they just callConnect()directly. Authentication runs automatically on connect; callEN.Lobby.JoinRoomafterward (e.g. fromOnAuthenticationCompleted) 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);
Logis the shared zero-alloc templated logger (backed byFigNetCommon.Utils.Log); preferEN.Log.Log(...)over the olderEN_Internals.Log(...)path in new code. This property does not exist on the server-sideENat all - the server-side copy has noLogproperty.LoggingLevelis a compatibility shim overLog.MinLevelusing the module'sLoggingLevelenum (None/Info/Debug/All) on the Unity side only. The server-sideEN.LoggingLevelis a plain{ get; set; }auto-property with noLogto back onto (matchingEN_Internals.IsLoggingEnabled's own level-comparison logic instead).Diagnosticwrites straight toUnityEngine.Debugregardless ofLoggingLevel, for periodic health/telemetry lines only (not per-frame spam) - mirrorsFV.Diagnosticon the FnVoice side. This method does not exist on the server-sideEN.
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.