Nebula
Core

NetworkBehaviour

Base class for replicated gameplay components.

generated from the sources
Abstract class in namespace Nebula · Packages/com.1by3.nebula/Runtime/Core/NetworkBehaviour.cs
[RequireComponent(typeof(NetworkIdentity))]
public abstract class NetworkBehaviour : MonoBehaviour

Base class for replicated gameplay components. Use IsServer, IsClient, and IsOwner to inspect the current role. Use HasAuthority to check whether this worker controls the entity, and IsGhost to check whether it holds a non-authoritative copy. Override the lifecycle methods to respond to spawn, despawn, and authority changes.

Fields

DefaultAuthorityCallTimeoutSeconds

public const float DefaultAuthorityCallTimeoutSeconds = 5f;

The default wait for an AuthorityRpcWithReply outcome before it settles as AuthorityCallOutcome.TimedOut.

Properties

Identity

public NetworkIdentity Identity { get; }

BehaviourIndex

public byte BehaviourIndex { get; }

NetId

public ulong NetId { get; }

IsSpawned

public bool IsSpawned { get; }

IsServer

public bool IsServer { get; }

IsClient

public bool IsClient { get; }

IsOwner

public bool IsOwner { get; }

Client side: this is the local player's entity.

IsDriver

public bool IsDriver { get; }

Client side: this client drives the entity (NetworkIdentity.SetDriver) and predicts it.

HasAuthority

public bool HasAuthority { get; }

Server side: this worker is authoritative for the entity right now.

IsGhost

public bool IsGhost { get; }

Server side: this worker holds a non-authoritative replica driven by a neighbouring worker.

OwnerClientId

public ulong OwnerClientId { get; }

Container

public Container Container { get; }

HasSyncState

public virtual bool HasSyncState { get; }

True when this behaviour replicates through WriteSyncState/ReadSyncState.

SyncDelivery

public virtual Delivery SyncDelivery { get; }

Delivery for this behaviour's sync chunks. Unreliable (sequenced) is right for transforms: a lost delta is healed by the next keyframe. Reliable is right for anything a receiver must not miss (animator triggers).

SyncDistanceRating

public virtual SyncDistanceRating SyncDistanceRating { get; }

Whether this behaviour's sync state follows the entity's distance tier for far clients, as its transform does (docs/server-owned-entities.md D11). The default, SyncDistanceRating.Off, sends every chunk to every client that holds the entity. Keyframes (a behaviour that writes deltas) sends a client beyond the entity's every-update band only keyframes, one per window of its rate; WholeState (a behaviour whose every write is complete, so Nebula always asks for full) sends it one chunk per window. Either way, once the state has not changed for NetworkIdentity.SyncSettleTicks ticks, one reliable keyframe reaches every client that holds the entity, so a far client is never left with anything but the latest state. Only the rate changes: the audience (SyncAudience) still decides who gets it at all.

Override it with a constant: Nebula reads it once, when the entity is spawned or instantiated. It suits state that is continuous, where a far client only needs the gist: a swarm's member offsets, an animation's blend values. It does not suit events a client must see each of (a trigger); keep those in an RPC or a behaviour that is not rated. It has no effect on the root NetworkTransform, which the gateway rates already, or on NetworkVariable<T>s.

SyncAudience

public virtual SyncAudience SyncAudience { get; }

Which clients receive this behavior's sync state (WriteSyncState). The default, SyncAudience.Everyone, costs nothing. A worker that holds a ghost of the entity receives the state whatever the audience; only clients are filtered. Override it with a constant: Nebula reads it once, when the entity is spawned or instantiated, so it is configuration and not state that can change at run time. An entity's root NetworkTransform always replicates to everyone.

NetworkVariable<T>s are not covered: an entity's variables go to every client that holds it. Keep state a client must not see in sync state with a restricted audience.

SyncAudienceRefreshTicks

public virtual uint SyncAudienceRefreshTicks { get; }

For the Custom audience only: how often, in ticks, the authority evaluates the audience again without being asked. The default is 30, half a second at the 60 Hz tick rate. Return 0 to evaluate only when the entity gains authority and after MarkSyncAudienceDirty. That suits a rule that changes only on events, such as a player opening or closing a container.

Methods

OnNetworkSpawn

public virtual void OnNetworkSpawn();

OnNetworkDespawn

public virtual void OnNetworkDespawn();

OnGainedAuthority

public virtual void OnGainedAuthority();

Called on a worker when it becomes authoritative for this entity (spawn, or handover in).

OnLostAuthority

public virtual void OnLostAuthority();

Called on a worker when authority moves to a neighbour. The object stays alive as a ghost.

OnSleep

public virtual void OnSleep();

Called on the worker that has authority when the entity falls asleep (NetworkIdentity.Sleep, or NetworkIdentity.SleepWhenUnobserved): stop what runs outside NetworkTick here, such as a coroutine or an animation. Not called when a dormant entity arrives by handover; check NetworkIdentity.IsDormant in OnGainedAuthority.

OnWake

public virtual void OnWake();

Called on the worker that has authority when a dormant entity wakes (NetworkIdentity.Wake, or a gateway watching it).

OnContainerChanged

public virtual void OnContainerChanged(Container previous, Container current);

OnOriginShifted

public virtual void OnOriginShifted(Vector3 delta);

Partitioned worlds: the floating origin moved by delta. The transform was moved with its container; add the delta to any frame position this behaviour caches itself (a target, a path, a history buffer). Not called in single-scene games.

NetworkTick

public virtual void NetworkTick(uint tick, float deltaTime);

Authoritative simulation step at the network tick rate. Not called for ghosts or on clients.

WriteHandoverState

public virtual void WriteHandoverState(NetworkWriter writer);

Called on the outgoing worker while building an authority transfer, before OnLostAuthority. Write any state the next owner needs that is not already replicated (angular velocity, timers, RNG state...). Travels only with the handover, never in the per-tick stream. Must be mirrored exactly by ReadHandoverState.

ReadHandoverState

public virtual void ReadHandoverState(NetworkReader reader);

Called on the incoming worker after the entity's pose, velocity and NetworkVariables have been applied and before OnGainedAuthority. Read exactly what WriteHandoverState wrote.

WritePersistentState

public virtual void WritePersistentState(NetworkWriter writer);

Called while the worker builds this entity's persistence record. Write what the entity needs to come back as it was and that no PersistAttribute variable already covers. Must be mirrored exactly by ReadPersistentState. Writing nothing (the default) costs nothing: an entry is only added when bytes were written.

Unlike WriteHandoverState, this is read back by a later run and possibly a later build, so treat it as a save format and version it yourself if you expect it to change.

ReadPersistentState

public virtual void ReadPersistentState(NetworkReader reader);

Called on a restored entity before it is spawned, with exactly what WritePersistentState wrote. The reader is bounded to this behaviour's own chunk, so reading too much fails here (and is logged) instead of corrupting the rest of the record.

MarkPersistDirty

protected void MarkPersistDirty();

Ask for a checkpoint soon: something worth saving changed that Nebula cannot see by itself (state written by WritePersistentState). A no-op on an entity with no PersistentEntity.

MarkSyncDirty

protected void MarkSyncDirty();

Ask the worker to send this behaviour's sync state at the end of the tick.

IsInSyncAudience

protected virtual bool IsInSyncAudience(ulong clientId, NetworkIdentity pawn);

For the Custom audience only, on the authoritative worker: whether the client with session ID clientId should receive this behavior's sync state. pawn is that client's player entity as this worker holds it (simulated here or a ghost), so a rule can measure the distance to it. Nebula asks about every client whose pawn this worker holds: when the entity gains authority, every SyncAudienceRefreshTicks ticks, and at the next tick after MarkSyncAudienceDirty. A client whose pawn this worker does not hold is not asked, and is not in the audience. Keep it cheap and free of side effects. By default it returns false for every client.

ParameterDescription
clientIdThe client's session ID. It stays the same when the client reconnects (NetworkIdentity.OwnerClientId).
pawnThat client's player entity on this worker.

MarkSyncAudienceDirty

protected void MarkSyncAudienceDirty();

For the Custom audience only, on the authority: the answer of IsInSyncAudience may have changed, so evaluate it at the next tick instead of waiting for the refresh. Calling it often is cheap: the audience is evaluated at most once per tick.

OnSyncStateCleared

public virtual void OnSyncStateCleared();

Client side: this client has just left the behavior's audience. For example, it no longer owns the entity, or a Custom rule stopped choosing it. None of the behavior's sync state arrives until the client joins again, and then a keyframe arrives through ReadSyncState. Drop what you hold of that state and clear any UI that shows it. Not called when the entity itself leaves the client (see OnNetworkDespawn).

WriteSyncState

public virtual void WriteSyncState(NetworkWriter writer, bool full);

Authority only. Write the state to replicate. When full is true write everything (a keyframe: this is what a late joiner or a fresh ghost will start from); otherwise only what changed since the last write is needed, though writing everything is always correct.

ReadSyncState

public virtual void ReadSyncState(NetworkReader reader, uint tick, bool full);

Non-authoritative copies. tick is the simulation tick the state belongs to (0 for a spawn snapshot); buffer it and present it from RemoteTick, or apply it at once.

OnSyncStateSent

protected internal virtual void OnSyncStateSent();

The tick's sends are done (every peer and gateway got this tick's chunk): drop per-tick pending deltas. Called from NetworkIdentity.ClearDirty; the owning client calls it after its own send.

RemoteTick

public virtual void RemoteTick(double renderTick);

Called on every copy this process does not simulate (ghosts on a worker: once per tick before physics syncs; entities on a client: once per frame) with the tick to present. Interpolating behaviours sample their buffers here. See NetworkTime.RenderTick.

ClientRpc

protected void ClientRpc(Action method);
protected void ClientRpc<T1>(Action<T1> method, T1 a1);
protected void ClientRpc<T1, T2>(Action<T1, T2> method, T1 a1, T2 a2);
protected void ClientRpc<T1, T2, T3>(Action<T1, T2, T3> method, T1 a1, T2 a2, T3 a3);
protected void ClientRpc<T1, T2, T3, T4>(Action<T1, T2, T3, T4> method, T1 a1, T2 a2, T3 a3, T4 a4);

OwnerRpc

protected void OwnerRpc(Action method);
protected void OwnerRpc<T1>(Action<T1> method, T1 a1);
protected void OwnerRpc<T1, T2>(Action<T1, T2> method, T1 a1, T2 a2);
protected void OwnerRpc<T1, T2, T3>(Action<T1, T2, T3> method, T1 a1, T2 a2, T3 a3);

A ClientRpc delivered only to the entity's owning client.

ServerRpc

protected void ServerRpc(Action method);
protected void ServerRpc<T1>(Action<T1> method, T1 a1);
protected void ServerRpc<T1, T2>(Action<T1, T2> method, T1 a1, T2 a2);
protected void ServerRpc<T1, T2, T3>(Action<T1, T2, T3> method, T1 a1, T2 a2, T3 a3);

AuthorityRpc

protected void AuthorityRpc(Action method);
protected void AuthorityRpc<T1>(Action<T1> method, T1 a1);
protected void AuthorityRpc<T1, T2>(Action<T1, T2> method, T1 a1, T2 a2);
protected void AuthorityRpc<T1, T2, T3>(Action<T1, T2, T3> method, T1 a1, T2 a2, T3 a3);
protected void AuthorityRpc<T1, T2, T3, T4>(Action<T1, T2, T3, T4> method, T1 a1, T2 a2, T3 a3, T4 a4);

AuthorityRpcWithReply

protected ulong AuthorityRpcWithReply(Action method, Action<AuthorityCallResult> onDone, float timeoutSeconds = DefaultAuthorityCallTimeoutSeconds);
protected ulong AuthorityRpcWithReply<T1>(Action<T1> method, T1 a1, Action<AuthorityCallResult> onDone, float timeoutSeconds = DefaultAuthorityCallTimeoutSeconds);
protected ulong AuthorityRpcWithReply<T1, T2>(Action<T1, T2> method, T1 a1, T2 a2, Action<AuthorityCallResult> onDone, float timeoutSeconds = DefaultAuthorityCallTimeoutSeconds);
protected ulong AuthorityRpcWithReply<T1, T2, T3>(Action<T1, T2, T3> method, T1 a1, T2 a2, T3 a3, Action<AuthorityCallResult> onDone, float timeoutSeconds = DefaultAuthorityCallTimeoutSeconds);
protected ulong AuthorityRpcWithReply<T1, T2, T3, T4>(Action<T1, T2, T3, T4> method, T1 a1, T2 a2, T3 a3, T4 a4, Action<AuthorityCallResult> onDone, float timeoutSeconds = DefaultAuthorityCallTimeoutSeconds);

As AuthorityRpc, and also tells you what became of the call. onDone runs exactly once, on the worker's main thread: with AuthorityCallOutcome.Accepted once the worker with authority has run the method, with the reason when a worker on the path rejected it, or with AuthorityCallOutcome.TimedOut when no answer arrived within timeoutSeconds. Returns the call id, or 0 when the call was applied locally or refused before it was sent. The delivery contract is described in the RPC guide.

On this page