Container
Defines a box-shaped authority area with its own local coordinate space.
Nebula · Packages/com.1by3.nebula/Runtime/Containers/Container.cs[DisallowMultipleComponent]
public sealed class Container : MonoBehaviourDefines a box-shaped authority area with its own local coordinate space. Nebula parents contained entities under its transform and replicates their local positions. The orchestrator assigns a static container from a scene or world manifest to a worker.
A container on the root of an entity (next to its NetworkIdentity) is carried by that entity: a ship's interior, a lift, a train car (FrameMode is ContainerFrameMode.Entity). It registers when the entity spawns on a process and unregisters when it despawns there, moves with the entity's root transform, and normally follows the entity's authoritative worker. Reach it through NetworkIdentity.Carried. The entity needs a NetworkTransform on its root; a container on a child object of an entity is not supported.
Nebula uses NebulaConfig.GhostBandMargin to send nearby entities to a neighboring worker before they cross the boundary. It uses NebulaConfig.HandoverHysteresis to prevent an entity near a boundary from repeatedly changing workers.
Fields
ContainerId
public string ContainerId = "container";Stable id used by the control plane. Must be unique in the scene. On an entity's root it is a label: the runtime id is '<label>#<carrier net id>'.
Size
public Vector3 Size = new Vector3(20f, 10f, 20f);Box size in local space, centred on Center.
Center
public Vector3 Center = new Vector3(0f, 5f, 0f);Authority
public ContainerAuthority Authority = ContainerAuthority.Auto;Who simulates what is inside. Auto: leased for a fixed box, inherited for a box an entity carries (what baked, runtime and carried containers always did). Leased: its own lease and owner, dealt by the planner. Inherited: whoever owns the parent container.
OwnPhysicsFrame
public bool OwnPhysicsFrame;Give this container a physics scene of its own in which it stands still: everything inside is simulated in container-local coordinates, with the container's own up as gravity. Use it for ships, stations and planets; a small vehicle is cheaper without one.
FrameContent
public GameObject FrameContent;Frame only: the interior geometry (colliders, visuals; no NetworkIdentity) instantiated into the frame's physics scene. Empty: the carrier's static colliders are cloned into the frame.
FrameInterest
public FrameInterestMode FrameInterest = FrameInterestMode.WithCarrier;Frame only: WithCarrier publishes everything inside with the carrier (ships); OwnRegions buckets it in regions of the frame itself (planets).
FrameApproachMargin
[Min(0f)]
public float FrameApproachMargin;Frame with OwnRegions only: metres from this container's box within which a client in the space around it also looks into it (a pilot over a planet sees what stands on it). 0, the default, turns it off: nobody outside the box sees in. Hold it to the distance a viewer can use; it widens interest to every client that comes that near.
Hint
public ContainerHint Hint = ContainerHint.Default;What the game tells the planner about this container (ContainerHint): the baked value, from the world manifest or the scene. The orchestrator prefers the control-plane row when one was set while the mesh runs (IControlPlane.SetContainerHint).
Properties
Index
public ushort Index { get; } = ushort.MaxValue;Dense index assigned by ContainerRegistry (sorted by id, or manifest order in a partitioned world). Used on the wire. A dynamic container has ContainerRef.DynamicIndex and is named by its carrier instead (see Ref).
Cell
public Vector3Int Cell { get; }Partitioned worlds: the grid cell this container belongs to (see WorldContainerManifest).
IsCell
public bool IsCell { get; }Partitioned worlds: this container spans its whole cell.
Neighbors
public List<Container> Neighbors { get; } = new List<Container>();Static adjacency: containers whose boxes touch or overlap this one, computed when the registry loads. Dynamic containers are not in it; see ContainerRegistry.NeighborsOf.
IsDynamic
public bool IsDynamic { get; }Registered as a carried container on this process: its entity has spawned here, and the box is named on the wire by the entity's net id. A container on an entity's root that has not spawned (a prefab asset, a copy not yet spawned) is FrameMode ContainerFrameMode.Entity but not yet dynamic.
FrameMode
public ContainerFrameMode FrameMode { get; }Where the box is (docs/container-tree.md D1): ContainerFrameMode.Entity when the container sits on an entity's root, next to its NetworkIdentity, which then carries it; otherwise ContainerFrameMode.Fixed. It is read from the object, never authored: an entity's own box cannot be fixed.
Source
public ContainerSource Source { get; }Where the container comes from: baked, registered at runtime, or part of a prefab.
ResolvedAuthority
public ContainerAuthority ResolvedAuthority { get; }Authority with ContainerAuthority.Auto resolved: leased for a fixed frame, inherited for an entity frame.
IsLeased
public bool IsLeased { get; }Whether this container is simulated under a lease of its own right now. A fixed container that resolves to leased always is; a carried container is once its row is pinned to a worker (an authored-leased one pins itself when its carrier spawns). Either way it is not while AuthorityDemoted: a leased container under a moving parent without a physics frame of its own is simulated as inherited (docs/container-tree.md D7).
AuthorityDemoted
public bool AuthorityDemoted { get; }The container would be leased, but sits under a moving parent that has no physics frame of its own, so its owner would simulate against a pose one replication delay old: it is simulated as inherited instead until it leaves (docs/container-tree.md D7).
InMovingSpace
public bool InMovingSpace { get; }Some ancestor moves (it is carried by an entity) and no container between here and it has a physics frame of its own: the box is somewhere whose pose only the moving ancestor's authority knows exactly.
Parent
public Container Parent { get; }The container this one sits in, or null for a root of its scope (docs/container-tree.md D2). A baked container's parent is the smallest baked box of its scope enclosing it, a runtime container's is named on its lease row, and a carried container's is wherever its carrier stands, so it changes as the carrier moves.
Children
public IReadOnlyList<Container> Children { get; }The fixed containers whose parent this is (baked and runtime). Carried containers are not listed: they come and go with the entities standing in Entities, whose NetworkIdentity.Carried they are.
Depth
public int Depth { get; }How many containers are above this one: 0 for a root of its scope. Resolution prefers the deepest box (D3).
Space
public Container Space { get; }The container whose physics frame this box lives in: the nearest ancestor with OwnPhysicsFrame, or null when the box is in its scope's own space (docs/container-tree.md §3). A framed container's own box lives in its parent's space; what it holds lives in its frame.
InnerSpace
public Container InnerSpace { get; }The space what this container holds lives in: its own frame when it has one, otherwise its Space.
ContentRoot
public Transform ContentRoot { get; }The transform what this container holds is parented under: the root of its physics frame when it has one (PhysicsFrame.Root), otherwise its own transform. Entities and fixed child containers hang here, so their local pose is their container-local pose either way.
Frame
public PhysicsFrame Frame { get; }The physics frame this container owns (OwnPhysicsFrame) on this process, or null while it has none.
IsRuntime
public bool IsRuntime { get; }Registered by the game while the mesh runs (ContainerRegistry.RegisterRuntime): a static box that is not in the baked set. Leased and owned like a baked container; named on the wire by RuntimeId (Index is ContainerRef.RuntimeIndex).
RuntimeId
public ulong RuntimeId { get; }Runtime containers: the 64-bit id the game registered this container under. 0 otherwise.
InstanceId
public ulong InstanceId { get; }Private simulation scope, or zero for the public world. Carried containers follow their carrier, through every carrier above it. A carrier chain that loops back on itself has no scope and reads as zero.
ScopeKey
public string ScopeKey { get; }The opaque scope key of the scope this container belongs to (EntityLocation.ScopeKey): EntityLocation.PublicScope (empty) for the public world, the instance key for an instance container. Carried containers follow their carrier, through every carrier above it. Never null.
Instance
public InstanceContainerInfo Instance { get; }Carrier
public NetworkIdentity Carrier { get; }Dynamic containers: the entity carrying this container. Null for static ones.
CarrierNetId
public ulong CarrierNetId { get; }Dynamic containers: the carrier's net id, which names this container on the wire. 0 for static ones.
Ref
public ContainerRef Ref { get; }How this container is named on the wire.
Entities
public List<NetworkIdentity> Entities { get; } = new List<NetworkIdentity>();The entities currently inside this container on this process, kept by NetworkIdentity as they move.
Enclosing
public Container Enclosing { get; }Dynamic containers: the container the carrier itself is in (what encloses this one). Null for static containers and for a carrier in no container.
LeaseState
public string LeaseState { get; } = "";State string of the control-plane lease as last applied ("" when there is none). See Nebula.LeaseState.
IsPinned
public bool IsPinned { get; }Dynamic containers: the orchestrator pinned this container to a worker of its own (lease state Nebula.LeaseState.Pinned), so it no longer follows its carrier. The pinned worker holds a permanent ghost of the carrier and simulates everything inside.
OwnerWorkerId
public string OwnerWorkerId { get; }Runtime: id of the worker currently authoritative for this container ("" if none). Static containers: from the control plane lease. Dynamic containers: the pinned worker when the lease is pinned, otherwise whoever is authoritative for the carrier, resolved through ContainerRegistry.WorkerIdByIndex (only workers know every peer's id; on a client it is "" unless the game supplies a resolver).
OwnerWorkerIndex
public ushort OwnerWorkerIndex { get; }Index of the owning worker (ushort.MaxValue when unowned), derived as OwnerWorkerId is.
LeaseEpoch
public ulong LeaseEpoch { get; }Lease epoch from the control plane; derived as OwnerWorkerId is (a carried container following its carrier: the carrier's authority epoch).
WorldBounds
public Bounds WorldBounds { get; }Volume
public float Volume { get; }World-space volume of the box (nested containers: the smallest one holding a point wins).
Rotation
public Quaternion Rotation { get; }World rotation of the container's frame (cached; see RefreshCache).
InverseRotation
public Quaternion InverseRotation { get; }NestingDepth
public int NestingDepth { get; }How many carriers this container sits inside, walking up through Enclosing: 0 for a static container, 1 for a ship in a static container, 2 for a shuttle inside that ship. There is no depth limit. This is what orders simulation and the ghost band, and two containers at different depths reported as equal would let a passenger tick before the ship it stands in. The walk cannot run away: every dynamic container is registered, so a chain longer than the registry has closed a cycle. That is the only bound; a cycle cannot be built in the first place (see IsCarriedBy).
Methods
IsEntityObject
public static bool IsEntityObject(GameObject go);Whether a container on go would be carried by an entity: the same rule as FrameMode, for code that has only the object (baking, export).
OfRigidbody
public static Container OfRigidbody(Rigidbody body);The container carried by the entity that owns body, or null. Game movement code that treats colliders without a Rigidbody as the level can use this to walk on a vehicle's floor as well.
IsCarrierGeometry
public static bool IsCarrierGeometry(Collider collider);Whether collider belongs to the carrier of a registered container (the hull of a vehicle, the floor of a lift).
IsCarriedBy
public bool IsCarriedBy(NetworkIdentity entity);Whether entity carries this container, directly or through a chain of carriers: this is entity's own box, or a box riding somewhere inside it (a shuttle parked in its hangar, a crate's box in that shuttle). Putting entity in such a container would make it ride inside itself; ContainerRegistry.Find skips these containers for the entity and the entity refuses to be placed in one. A chain longer than the registry holds has already looped and also answers true, so nothing is ever added to it.
RefreshCache
public void RefreshCache();Re-read the transform. ContainerRegistry.Rebuild does this for every container and the worker repeats it once per tick, so a container that moves (a ship) is never more than a tick stale.
Contains
public bool Contains(Vector3 worldPosition);SignedDistance
public float SignedDistance(Vector3 worldPosition);Signed distance to the box surface: positive outside (how far, in any direction), negative inside (how deep, measured to the nearest wall only). The floor and ceiling do not count as depth: pawns stand on the floor, which is the bottom face of the box, and treating it as a seam would keep every entity in a room permanently "about to leave" for the ghost band and never past the handover hysteresis.
SignedDistanceInner
public float SignedDistanceInner(Vector3 local);SignedDistance for a point already in this container's local coordinates: the inner face of a container with a physics frame of its own, whose contents are in exactly those coordinates (docs/container-tree.md §3).
ContainsInner
public bool ContainsInner(Vector3 local);Contains for a point in this container's local coordinates (the inner face of its frame).
DistanceToSeam
public float DistanceToSeam(Vector3 worldPosition, Container neighbor);How far a point inside this container is from its seam with neighbor. For a sibling or an inner box that is the neighbor's surface; for a neighbor that encloses this one (a building inside the outdoor area, the area around a ship) the seam is this container's own surface, so the answer is how far the point is from getting out - not "inside the enclosing box", which would put every entity in every building in the band permanently.
Encloses
public bool Encloses(Container other);other's box lies entirely inside this one (nested containers). A dynamic container is enclosed by the container its carrier is in whatever the boxes say.
IntersectsSegment
public bool IntersectsSegment(Vector3 a, Vector3 b, float margin, out float tEnter, out float tExit);Whether the segment from a to b passes through the box grown by margin on every side, and where along it (tEnter and tExit are fractions of the segment, clamped to [0, 1]). A segment starting inside the box enters at 0. Slab test in the container's local space, so rotated boxes are exact. The margin absorbs handover hysteresis and an entity's own radius when the caller asks "whose entities could this ray touch".
ToLocal
public Vector3 ToLocal(Vector3 world);ToWorld
public Vector3 ToWorld(Vector3 local);IsOwnedBy
public bool IsOwnedBy(string workerId);ToString
public override string ToString();NewContainerId
public static string NewContainerId();A fresh random container id, e.g. "container-3f9a1c07".
FitToBounds
public bool FitToBounds();Set Size and Center to the local-space box around this object's enabled renderers and those of its children, falling back to their colliders when there are no renderers. Returns false and leaves the box unchanged when neither is found (an empty object keeps its authored box).
PlacementProblem
public static string PlacementProblem(Container c, out bool error);Where a container sits decides what it is (FrameMode); say so when the placement cannot work. A box on a child object of an entity is baked as a fixed container, so it would never move with the entity; a box on an entity's root needs a root NetworkTransform, because every process positions the contents from the carrier's replicated pose. The Nebula validator reports the same.
Returns: Null when the placement works; otherwise the problem, with error set when the container cannot work at all.
UpdateGapDelay
The extra render delay a client gives one remote entity whose state arrives further apart than the render delay: an entity the worker updates every few ticks (NetworkIdentity.UpdateInterval), or one the gateway sends a client only every ...
ContainerAuthority
Who simulates what is inside a container (docs/container-tree.md D6).