Skip to main content

Unity Components

The MonoBehaviours and ScriptableObject a game developer actually drops onto a GameObject or prefab to make it networked with Entangle. This page does not cover every class in the Entangle Unity folder - only the curated, public surface: EntangleView (entry point), EntangleManager / RoomManager (bootstrap, one of each per scene/app), NetworkTransform / NetworkAnimator (sync components you add per networked prefab), and EntangleEntityRegistry (the spawn registry asset that ties prefabs to entity ids).

All types live in namespace FigNet.Entangle.Unity (except AnimationSyncData, which is FigNet.Entangle).

EntangleView

EntangleView : MonoBehaviour - the component every networked GameObject needs. It holds the live NetworkEntity for that object and is the attach point sync components (NetworkTransform, NetworkAnimator, or any custom IEntangleSync) look for via GetComponentsInChildren.

public EntityType EntityType;
public short EntityId;

public NetworkEntity NetworkEntity { get; set; }

public T GetNetworkEntity<T>() where T : NetworkEntity
public void SetNetworkEntity(NetworkEntity networkEntity, System.Numerics.Vector3 position, System.Numerics.Vector4 rotation)

public void RequestOwnership(bool withLock = false)
public void ClearOwnership()
  • EntityType / EntityId are the fields the EntangleEntityRegistry list is matched against when the server spawns an Agent or Item - set them on the prefab so RoomManager can find it.
  • SetNetworkEntity is called by RoomManager when the entity is spawned; it wires the NetworkEntity into every child IEntangleSync component (Init), auto-registers any [Networked]-tagged field found on child MonoBehaviours (via NetworkEntity.RegisterNetworkedProperties), and completes bindings on the next frame. You normally don't call this yourself - RoomManager does it during spawn.
  • GetNetworkEntity<T>() is the typed accessor you use in gameplay code, e.g. view.GetNetworkEntity<NetAgent>().
  • RequestOwnership / ClearOwnership forward to NetworkEntity.RequestOwnership / NetworkEntity.ClearOwnership - call these to take/release authority over an object (e.g. picking up an item).
  • Auto-registration gotcha: a [Networked] field's Key must be < 32 - TryValidateNetworkBindings skips (and warns-logs) registration for a behaviour whose key falls outside [0-31].
  • OnDestroy clears NetworkEntity to null - don't cache a NetworkEntity reference across a destroy/respawn without re-fetching it from the view.

EntangleManager

EntangleManager : MonoBehaviour - the connection bootstrap component. Add exactly one to your scene; it loads the EntangleNetworkConfig asset, applies EntangleRuntimeSettings, initializes the EN facade, and drives the per-frame EN.Socket.Process() / TimeScheduler.Tick() loop.

public bool IsAutoConnect;

[ContextMenu("Connect")]
public void Connect()

[ContextMenu("Disconnect")]
public void Disconnect()

public void Process()
  • IsAutoConnect (inspector checkbox): when true, Connect() is called automatically from Start() after configuration is loaded.
  • Connect() / Disconnect() are also exposed as [ContextMenu] entries, so you can trigger them from the component's gear menu in the Inspector during testing.
  • Process() is called every Update(); it wraps EN.Socket?.Process() and TimeScheduler.Tick(Time.deltaTime) in a try/catch that logs failures rather than throwing.
  • On Start(), it reads Resources.Load<EntangleNetworkConfig>("EntangleNetworkConfig") and EntangleRuntimeSettings.Instance - both must exist as Resources assets or you get a load/config error (a missing EntangleRuntimeSettings logs one error and falls back to defaults).
  • On OnDestroy() it calls EN.Disconnect(); on OnApplicationQuit() it calls FN.Deinitialize().
  • See Configuration for what lives in EntangleNetworkConfig.

RoomManager

RoomManager : MonoBehaviour, IEntangleRoomListener - the spawn/despawn bootstrap. Add exactly one to your scene (it self-enforces a singleton and calls DontDestroyOnLoad); it binds itself as the Entangle room listener and instantiates/destroys EntangleView prefabs from the EntangleEntityRegistry as the server tells it entities were created, deleted, or players joined/left.

public void OnNetworkEntityCreated(NetworkEntity entity, System.Numerics.Vector3 position, System.Numerics.Vector4 rotation, System.Numerics.Vector3 scale)
public void OnNetworkEntityDeleted(NetworkEntity entity)
public void OnPlayerJoined(FigNet.Entangle.NetPlayer player)
public void OnPlayerLeft(FigNet.Entangle.NetPlayer player)
public void OnEventReceived(uint sender, EN_RoomEvent eventData)
public void OnRoomCreated()
public void OnRoomDispose()
public void OnRoomStateChange(int status)
public void PreRoomStateReceived()
public void PostRoomStateReceived()
  • These are the IEntangleRoomListener callbacks - you don't call them directly, the framework invokes them. Most day-to-day usage of RoomManager is just "drop it once in the scene next to EntangleManager" and it handles spawning; you customize spawning by editing the EntangleEntityRegistry asset instead of this component.
  • Start() loads Resources.Load<EntangleEntityRegistry>("EntangleEntityRegistry") into Container. If the asset itself is missing, Container is null and the first spawn attempt (Container.Entities.Find(...) / Container.MyPlayer) throws a NullReferenceException rather than logging a graceful error - there is no null-guard on Container itself. The friendlier "prefab is not registered" error only fires when the registry asset is present but has no matching entry for the incoming EntityId/EntityType (or MyPlayer/ RemotePlayer is left unassigned for a player spawn).
  • Entities spawn under a shared NETWORK_ENTITIES GameObject created lazily on Start().
  • Awake() registers itself with FigNet.Entangle.Room.BindListener(this); OnDestroy() unbinds and calls EN.Room.Deinit().
  • Update() ticks EN.Room.Tick(Time.deltaTime) and a scheduled heartbeat (Room.SendHeartbeat(), every 60s after an initial 15s delay) runs via TimeScheduler.

NetworkTransform

NetworkTransform : MonoBehaviour, IEntangleSync - the transform-sync component for the client-authoritative relay model. The owner streams position/rotation/scale (+ optional velocity) over TransformLite; proxies reconstruct motion with a velocity-aware SnapshotInterpolator (Hermite) and are held kinematic with gravity off while not owned. Supersedes the legacy PID NetworkTransform (now NetworkTransformLegacy) and the removed NetworkRigidBody - use this one for all new prefabs.

[RequireComponent(typeof(EntangleView))]
public class NetworkTransform : MonoBehaviour, IEntangleSync

Key inspector fields, grouped as they appear in the component:

// Target Transform
public bool IsOverrideTransform;
public Transform transformToSync;

// Channels (X and Y position always sync)
public bool syncPositionZ = true;
public bool syncRotation = true;
public bool syncScaleX, syncScaleY, syncScaleZ; // all false by default
public bool syncLinearVelocity = true;
public bool syncAngularVelocity = false;

// Precision
public PositionPrecision positionPrecision = PositionPrecision.Full; // Full, Half_1000, Half_100, Half_10
public bool velocityCoarse = false;

// Sync Mode
public TransformSyncMode syncMode = TransformSyncMode.Interpolate; // Interpolate or Extrapolate

// Interpolation
public bool useAdaptiveDelay = true;
public float adaptiveDelayTicks = 2.5f;
public float adaptiveJitterMultiplier = 2f;
public float adaptiveMinDelay = 0.03f;
public float adaptiveMaxDelay = 0.40f;
public float interpolationDelay = 0.10f; // manual delay, used when useAdaptiveDelay = false
public bool adaptiveMaxPrediction = false;
public float maxPredictionTicks = 2.5f;
public float maxPrediction = 0.12f; // absolute prediction ceiling (s)
public float predictionSoftStop = 0f;
public float teleportThreshold = 2f; // meters
public float correctionSharpness = 25f;

// Send
public float sendCooldown = 0.3f;

Public API / runtime access:

public SnapshotInterpolator RuntimeInterpolator => interp; // read-only, for a custom editor's runtime stats
public bool RuntimeIsMine => networkEntity != null && networkEntity.IsMine;

public static IReadOnlyList<NetworkTransform> ActiveInstances { get; }

public void Init(NetworkEntity networkEntity, System.Numerics.Vector3 _position = default,
System.Numerics.Vector4 _rotation = default, System.Numerics.Vector3 _scale = default)

// Re-applies inspector tuning (interpolator config + teleport threshold) to a live instance at runtime -
// call after changing sync-mode/prediction/delay/teleport fields from code (e.g. a diagnostics panel).
public void ApplyRuntimeConfig()

Gotchas:

  • [RequireComponent(typeof(EntangleView))] - must sit on a GameObject that also has (or gets) an EntangleView. Init is invoked by EntangleView.SetNetworkEntity through the IEntangleSync interface, not called directly by your code.
  • If transformToSync ends up null after Awake() (and IsOverrideTransform isn't handling it), Start() logs an error and disables the component.
  • Ownership flips (OnOwnershipChange) toggle Rigidbody.isKinematic/useGravity on proxies: a proxy is always held kinematic with gravity off; the owner gets back its originally-authored useGravity value. This absorbs what used to be a separate RigidBodyStabilizer component - you don't need one anymore.
  • ActiveInstances is a static registry of currently-enabled NetworkTransforms (added/removed in OnEnable/OnDisable), intended for diagnostics/reporting rather than gameplay use.

NetworkAnimator

NetworkAnimator : MonoBehaviour, IEntangleSync - syncs Animator parameters (float/bool/int + triggers) and, optionally, per-layer state (state hash, normalized time, playback speed) from an owner to proxies at a fixed poll rate.

[RequireComponent(typeof(EntangleView), typeof(Animator))]
public class NetworkAnimator : MonoBehaviour, IEntangleSync

Inspector fields:

[Header("Network Settings")]
public float updateRate = 0.2f; // seconds between update checks

[Header("Synchronization Options")]
public bool syncLayerStates = true;
public int[] syncLayers = { 0 }; // layer indices to sync, when syncLayerStates is on
public float timeThreshold = 0.05f; // normalized-time change threshold to consider "changed"

[Header("Debug")]
public bool showDebugInfo = false;

Public API - use these instead of calling Animator.Set* directly so the owner-side change snapshot stays correct:

public void SetFloat(string name, float value)
public void SetBool(string name, bool value)
public void SetInteger(string name, int value)
public void SetTrigger(string name)

Other members worth knowing:

public const byte NETWORK_TAG = 31;
public const FigNet.Core.DeliveryMethod NETWORK_DELIVERY = Core.DeliveryMethod.Unreliable;

public enum NetworkAuthority { Local, Remote }
public NetworkAuthority authority = NetworkAuthority.Remote;

Gotchas:

  • [RequireComponent(typeof(EntangleView), typeof(Animator))] - the GameObject needs both an EntangleView and an Animator; Awake() does GetComponent<Animator>() and will NRE without one.
  • Only call SetFloat/SetBool/SetInteger/SetTrigger on the object you own - the internal OnNetworkDataChanged handler bails out early if authority == NetworkAuthority.Local, i.e. proxies never apply their own network updates back onto themselves, and the local owner is the one expected to drive the Animator directly.
  • Animator parameters are auto-mapped to byte ids at Awake() in declaration order (cachedParameters) - if you add/remove/reorder parameters on the AnimatorController between builds, the byte mapping shifts, so don't rely on it being stable across content changes.
  • Floats are quantized to a 2-byte short (value * 1000, clamped to short range) for bandwidth - usable range is roughly +/-32.767 with 0.001 resolution.
  • The wire payload is AnimationSyncData, sent via a [Networked(NETWORK_TAG, NETWORK_DELIVERY, ...)] field (syncData), delivered Unreliable.

EntangleEntityRegistry

EntangleEntityRegistry : ScriptableObject - the registry of runtime-spawnable networked prefabs. RoomManager loads it from Resources.Load<EntangleEntityRegistry>("EntangleEntityRegistry"), so the asset must exist at exactly that Resources path.

[CreateAssetMenu(fileName = "EntangleEntityRegistry", menuName = "FigNet/Entangle/Entity Registry", order = 1)]
public class EntangleEntityRegistry : ScriptableObject
{
public EntangleView MyPlayer;
public EntangleView RemotePlayer;
public List<EntangleView> Entities;
}
  • MyPlayer / RemotePlayer are the prefabs instantiated on OnPlayerJoined for the local vs. a remote player, respectively. The unassigned-field checks are silent (no log) and not symmetric: OnPlayerJoined checks Container.MyPlayer == null first and returns early - before branching on player.IsMine - so leaving MyPlayer unassigned silently skips spawning both local and remote players, not just the local one. RemotePlayer == null is checked separately inside the remote-player branch and only blocks remote spawns. A "prefab is not registered" error is logged only in the narrower case where the field is assigned but Instantiate itself returns null.
  • Entities is the lookup list for non-player entities: on OnNetworkEntityCreated, RoomManager finds the prefab whose EntangleView.EntityId and EntangleView.EntityType match the incoming entity (Container.Entities.Find(e => e.EntityId == ... && e.EntityType == ...)) and instantiates that prefab. A missing match logs a "prefab is not registered" error and the spawn is skipped.
  • Create/find the asset via the FigNet/Entangle/Entity Registry menu item (from [CreateAssetMenu]); it must live under a Resources/ folder and be named EntangleEntityRegistry.