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/EntityIdare the fields theEntangleEntityRegistrylist is matched against when the server spawns anAgentorItem- set them on the prefab soRoomManagercan find it.SetNetworkEntityis called byRoomManagerwhen the entity is spawned; it wires theNetworkEntityinto every childIEntangleSynccomponent (Init), auto-registers any[Networked]-tagged field found on childMonoBehaviours (viaNetworkEntity.RegisterNetworkedProperties), and completes bindings on the next frame. You normally don't call this yourself -RoomManagerdoes it during spawn.GetNetworkEntity<T>()is the typed accessor you use in gameplay code, e.g.view.GetNetworkEntity<NetAgent>().RequestOwnership/ClearOwnershipforward toNetworkEntity.RequestOwnership/NetworkEntity.ClearOwnership- call these to take/release authority over an object (e.g. picking up an item).- Auto-registration gotcha: a
[Networked]field'sKeymust be< 32-TryValidateNetworkBindingsskips (and warns-logs) registration for a behaviour whose key falls outside[0-31]. OnDestroyclearsNetworkEntityto null - don't cache aNetworkEntityreference 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 fromStart()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 everyUpdate(); it wrapsEN.Socket?.Process()andTimeScheduler.Tick(Time.deltaTime)in a try/catch that logs failures rather than throwing.- On
Start(), it readsResources.Load<EntangleNetworkConfig>("EntangleNetworkConfig")andEntangleRuntimeSettings.Instance- both must exist as Resources assets or you get a load/config error (a missingEntangleRuntimeSettingslogs one error and falls back to defaults). - On
OnDestroy()it callsEN.Disconnect(); onOnApplicationQuit()it callsFN.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
IEntangleRoomListenercallbacks - you don't call them directly, the framework invokes them. Most day-to-day usage ofRoomManageris just "drop it once in the scene next toEntangleManager" and it handles spawning; you customize spawning by editing theEntangleEntityRegistryasset instead of this component. Start()loadsResources.Load<EntangleEntityRegistry>("EntangleEntityRegistry")intoContainer. If the asset itself is missing,Containerisnulland the first spawn attempt (Container.Entities.Find(...)/Container.MyPlayer) throws aNullReferenceExceptionrather than logging a graceful error - there is no null-guard onContaineritself. The friendlier "prefab is not registered" error only fires when the registry asset is present but has no matching entry for the incomingEntityId/EntityType(orMyPlayer/RemotePlayeris left unassigned for a player spawn).- Entities spawn under a shared
NETWORK_ENTITIESGameObject created lazily onStart(). Awake()registers itself withFigNet.Entangle.Room.BindListener(this);OnDestroy()unbinds and callsEN.Room.Deinit().Update()ticksEN.Room.Tick(Time.deltaTime)and a scheduled heartbeat (Room.SendHeartbeat(), every 60s after an initial 15s delay) runs viaTimeScheduler.
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) anEntangleView.Initis invoked byEntangleView.SetNetworkEntitythrough theIEntangleSyncinterface, not called directly by your code.- If
transformToSyncends up null afterAwake()(andIsOverrideTransformisn't handling it),Start()logs an error and disables the component. - Ownership flips (
OnOwnershipChange) toggleRigidbody.isKinematic/useGravityon proxies: a proxy is always held kinematic with gravity off; the owner gets back its originally-authoreduseGravityvalue. This absorbs what used to be a separateRigidBodyStabilizercomponent - you don't need one anymore. ActiveInstancesis a static registry of currently-enabledNetworkTransforms (added/removed inOnEnable/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 anEntangleViewand anAnimator;Awake()doesGetComponent<Animator>()and will NRE without one.- Only call
SetFloat/SetBool/SetInteger/SetTriggeron the object you own - the internalOnNetworkDataChangedhandler bails out early ifauthority == NetworkAuthority.Local, i.e. proxies never apply their own network updates back onto themselves, and the local owner is the one expected to drive theAnimatordirectly. - Animator parameters are auto-mapped to byte ids at
Awake()in declaration order (cachedParameters) - if you add/remove/reorder parameters on theAnimatorControllerbetween 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 toshortrange) for bandwidth - usable range is roughly+/-32.767with0.001resolution. - The wire payload is
AnimationSyncData, sent via a[Networked(NETWORK_TAG, NETWORK_DELIVERY, ...)]field (syncData), deliveredUnreliable.
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/RemotePlayerare the prefabs instantiated onOnPlayerJoinedfor the local vs. a remote player, respectively. The unassigned-field checks are silent (no log) and not symmetric:OnPlayerJoinedchecksContainer.MyPlayer == nullfirst and returns early - before branching onplayer.IsMine- so leavingMyPlayerunassigned silently skips spawning both local and remote players, not just the local one.RemotePlayer == nullis 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 butInstantiateitself returns null.Entitiesis the lookup list for non-player entities: onOnNetworkEntityCreated,RoomManagerfinds the prefab whoseEntangleView.EntityIdandEntangleView.EntityTypematch 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 Registrymenu item (from[CreateAssetMenu]); it must live under aResources/folder and be namedEntangleEntityRegistry.