AgentNetwork
Network behaviour that synchronizes agent possession state across all clients. Listens to the local Possessor events and replicates possess/release operations to remote clients via RPCs. Handles late-joiner synchronization by serializing the full possession list.
Definition
Namespace: Paragon.Townskeep.AgentSystem
Assembly: Townskeep.dll
public class AgentNetwork : ParagonNetworkBehaviourInheritance: NetworkBehaviour → ParagonNetworkBehaviour → AgentNetwork
Remarks
AgentNetwork ensures that when the host agent possesses or releases a character, all remote clients replicate the same relationship. It uses two mechanisms:
1. Real-Time RPCs (Ongoing Changes)
When the Possessor fires Possessed or Released events on the authority (host):
OnPossessed()→SendPossessedRpc()— tells all non-authority clients to possessOnReleased()→SendReleasedRpc()— tells all non-authority clients to release
Both RPCs use [Rpc(SendTo.NotAuthority)] so they are sent to all clients except the host. The RPCs receive a NetworkObjectReference, resolve it to a NetworkObject, then extract the IPossessable component and call agent.Possess() or agent.Release().
2. State Serialization (Late Joiners)
OnSynchronize() handles the initial state sync when a new client joins:
Writer (host) — Serializes the count of possessions followed by each possession's
NetworkObjectReferenceReader (client) — Reads the count and references, then waits until end of frame (
Yield.WaitForEndOfFrame()) before resolving them. The delay ensures the referencedNetworkObjectinstances have been spawned on the client.
Lifecycle
OnNetworkSpawn — Subscribes to
possessor.Possessedandpossessor.ReleasedeventsOnNetworkDespawn — Unsubscribes from both events
Quick Lookup
Access from agent
agent.Network
Check if network spawned
agentNetwork.IsSpawned
Check if host/authority
agentNetwork.IsOwner
Methods
OnNetworkSpawn (override)
Subscribes to Possessor.Possessed and Possessor.Released events for RPC replication.
OnNetworkDespawn (override)
Unsubscribes from possession events.
OnSynchronize (protected override)
Serializes or deserializes the full possession state for late-joining clients.
Writer behavior (host):
Gets all possessions from the
PossessorWrites the count as
intWrites each possession as a
NetworkObjectReference
Reader behavior (client):
Reads the possession count
Reads each
NetworkObjectReferenceWaits until end of frame (async) to ensure network objects are spawned
Resolves each reference and calls
agent.Possess(possessable)
SendPossessedRpc (private)
RPC sent to all non-authority clients when the agent possesses a new entity.
SendReleasedRpc (private)
RPC sent to all non-authority clients when the agent releases a possessed entity.
Common Pitfalls
Late-joiner async delay
OnSynchronize uses await Yield.WaitForEndOfFrame() on the reader side via an async void local function. If the referenced NetworkObject is still not spawned by end of frame, reference.TryGet() will return false and networkObject will be null, causing a NullReferenceException on the next line.
RPCs only sent when IsOwner
The OnPossessed and OnReleased callbacks check IsOwner before sending RPCs. If possession events fire on a non-authority client (which shouldn't happen in normal flow), RPCs are silently skipped.
No null check on TryGet in RPCs
SendPossessedRpc and SendReleasedRpc use if (reference.TryGet(...) && object.TryGetComponent(...)) with a compound condition. If the network object exists but doesn't have IPossessable, the call is silently skipped — no error is logged.
Agent and Possessor must be on the same GameObject
Awake() uses GetComponent<Agent>() and GetComponent<Possessor>(). Both components must be on the same GameObject as AgentNetwork, or the references will be null.
See Also
Agent — the AI brain whose possession state is synchronized
Network Overview — subsystem architecture
Agent System Overview — full system architecture
Last updated