Core Concepts
Before writing networked gameplay, it helps to understand how GONet organizes authority, ownership, and lifecycle. This page covers the foundational building blocks you will use in every GONet project.
The Authority Model
In GONet, every connected machine -- whether it is the server or a client -- is identified by a unique authorityId (a ushort value). This ID determines which machine has authority over which objects.
- The server always has authorityId = 1023. This value is constant and never changes.
- Clients receive lower IDs assigned by the server at connection time. The first client might get ID 0, the second ID 1, and so on.
- Use GONetMain.MyAuthorityId to get the local machine's authority ID at runtime.
- Use GONetMain.IsServer and GONetMain.IsClient to check the local machine's role. These are the simplest way to branch logic based on whether your code is running on the server or a client.
The authority model is the foundation for everything else in GONet. When an object is spawned, it is assigned to the machine that created it. That machine becomes the object's authority -- the source of truth for its synchronized state.
GONetParticipant -- The Foundation
GONetParticipant is the core component that makes a GameObject visible to the network. Add it to any GameObject you want to synchronize, spawn, or reference across machines.
Each GONetParticipant is assigned a unique GONetId -- a 32-bit identifier composed of a 22-bit object ID and a 10-bit authority ID. This means every networked object in the session has a globally unique identifier that also encodes which machine owns it.
Key properties:
- IsMine -- returns true if the local machine owns (has authority over) this object. Use this to guard input processing, AI logic, or any code that should only run on the owning machine.
- OwnerAuthorityId -- the authority ID of the machine that owns this participant. Compare this to GONetMain.MyAuthorityId if you need more granular ownership checks.
- GONetId -- the unique network identifier. You can use this to look up participants from anywhere via GONetMain.TryGetGONetParticipantByGONetId().
Important: Never disable a GameObject that contains a GONetParticipant. If you need to hide or deactivate a networked object, disable individual components or renderers instead. Disabling the GameObject itself removes it from GONet's update loop and can cause synchronization errors.
A simple ownership check looks like this:
GONetParticipant participant = GetComponent<GONetParticipant>();
if (participant.IsMine)
{
// This machine owns the object -- process input, run AI, etc.
}
else
{
// Owned by another machine -- just render and interpolate
}GONetBehaviour -- Lifecycle Hooks
GONetBehaviour is a base class (extending MonoBehaviour) that provides lifecycle callbacks tied to GONet's networking state. Instead of subscribing to the EventBus manually, you can override methods to respond to network events.
Key methods to override
- OnGONetClientVsServerStatusKnown(bool isClient, bool isServer, ushort myAuthorityId) -- Called once the machine's role has been determined. At this point you know whether you are running as the server or a client, and you have your authority ID. This is a good place to initialize role-specific logic (e.g., start the game loop on the server, show a lobby UI on the client).
- OnGONetReady(GONetParticipant gonetParticipant) -- Recommended entry point. Called when a GONetParticipant is fully initialized and registered on the network. At this point the participant has a valid GONetId, sync is active, and it is safe to send RPCs.
Performance-optimized update methods
GONetBehaviour provides replacements for Unity's built-in update callbacks. These are more efficient because GONet calls them from a single internal loop rather than using Unity's per-component callback system (which has overhead for each MonoBehaviour):
- UpdateAfterGONetReady() -- Use instead of Update(). Runs every frame after networking is ready.
- FixedUpdateAfterGONetReady() -- Use instead of FixedUpdate(). Runs at fixed timestep intervals for physics-related logic.
- LateUpdateAfterGONetReady() -- Use instead of LateUpdate(). Runs after all Update calls, useful for camera follow or post-processing logic.
Using these methods instead of Unity's built-in callbacks avoids the overhead of N separate Unity callback invocations. GONet batches all registered behaviours into a single loop, which scales better as your scene grows.
GONetParticipantCompanionBehaviour -- The One You Will Use Most
GONetParticipantCompanionBehaviour extends GONetBehaviour and is designed to live on the same GameObject as (or a child of) a GONetParticipant. It is the class you will inherit from in most of your networked scripts.
What it adds over GONetBehaviour:
- Automatic participant discovery -- It finds the GONetParticipant on the same or parent GameObject automatically. You do not need to call GetComponent yourself.
- IsMine -- A convenience property that delegates to the associated GONetParticipant's ownership check.
- OnGONetReady() -- A simplified override with no parameters needed (the participant reference is already stored internally).
Here is a minimal example:
using GONet;
using UnityEngine;
public class MyNetworkedComponent : GONetParticipantCompanionBehaviour
{
public override void OnGONetReady()
{
if (IsMine)
Debug.Log("This is my object!");
else
Debug.Log("This belongs to someone else.");
}
internal override void UpdateAfterGONetReady()
{
if (!IsMine) return;
// Only the owner runs gameplay logic
// Remote copies receive state through sync
}
}In practice, almost all of your networked components will extend GONetParticipantCompanionBehaviour rather than GONetBehaviour directly. The direct GONetBehaviour base class is useful for global managers that do not belong to a specific networked object.
GONetMain -- The Central Hub
GONetMain is a static class that serves as the central access point for all networking operations. You can call its methods and read its properties from anywhere in your code without needing a reference to any specific object.
Key members:
- GONetMain.IsServer / GONetMain.IsClient -- Check the local machine's role. These are bool properties that are set once the connection is established.
- GONetMain.MyAuthorityId -- The authority ID of the local machine. Server is always 1023; clients get sequentially assigned lower IDs.
- GONetMain.EventBus -- The global publish/subscribe event system. Use EventBus.Subscribe and EventBus.Publish for custom game events that need to cross the network.
- GONetMain.SceneManager -- Handles networked scene loading. When the server loads a scene through this manager, all connected clients load it too.
- GONetMain.Instantiate(prefab, position, rotation) -- Spawns a networked object. Works like UnityEngine.Object.Instantiate but replicates the spawn to all connected machines.
- GONetMain.TryGetGONetParticipantByGONetId(id, out participant) -- Looks up a networked object by its GONetId. Returns true if found. Useful when you receive an ID from an RPC or event and need to find the corresponding GameObject.
GONetLocal -- Per-Machine State
While GONetMain gives you global access to networking operations, GONetLocal represents the state of an individual connected machine. There is one GONetLocal instance for the server and one for each connected client.
You can access any machine's GONetLocal instance using its authority ID:
// Get the GONetLocal for a specific machine
GONetLocal remote = GONetLocal.LookupByAuthorityId[someAuthorityId];This is useful for tracking who is connected, iterating over all connected machines, or accessing per-machine metadata. For example, you might use it to build a player list or determine which machines are still active.
Lifecycle Flow
Understanding the order of operations helps you know where to put your initialization logic. Here is the sequence from application start to gameplay:
- 1GONetGlobal.Awake() -- The GONet singleton initializes. Transport layer is set up, internal data structures are allocated. This happens automatically from the GONet_GlobalContext prefab.
- 2Server/Client determination -- The user presses Alt+S (server) or Alt+C (client), or your code programmatically starts the connection. The machine's role is established and an authority ID is assigned.
- 3OnGONetClientVsServerStatusKnown() fires -- All GONetBehaviours receive this callback. At this point it is safe to start role-specific game logic: lobby setup, matchmaking, UI state, etc.
- 4GONetParticipants register -- Networked objects in the scene (and any spawned objects) register with GONet and receive their unique GONetIds. Synchronization channels are established.
- 5OnGONetReady() fires -- Each GONetParticipant's companion behaviours receive this callback. The participant is fully initialized: it has a valid GONetId, sync is active, and it is safe to send RPCs. This is the recommended place to put your initialization code.
Rule of thumb: Use OnGONetClientVsServerStatusKnown for global setup that depends on the machine's role. Use OnGONetReady for per-object setup that depends on the object being networked. If in doubt, OnGONetReady is almost always the right choice.
Important Rules
These rules apply across all GONet projects. Following them will save you from the most common pitfalls:
- Never disable a parent GameObject that contains a GONetParticipant. When a GameObject is disabled, GONet loses track of it. If you need to hide a networked object, disable its Renderer, Collider, or other individual components instead. The GONetParticipant and its companion behaviours must remain active.
- Use GONetRuntimeComponentInitializer to add components at runtime. If you need to add MonoBehaviours to a networked GameObject dynamically (after it has been spawned), use GONetRuntimeComponentInitializer instead of calling AddComponent directly. This ensures GONet properly tracks and synchronizes the new component.
- The server authority ID is always 1023. This is a constant. If you need to check whether a particular object is owned by the server, compare its OwnerAuthorityId to 1023. Client IDs are always lower than this value.
- Use GONet's update methods instead of Unity's. Prefer UpdateAfterGONetReady() over Update(), FixedUpdateAfterGONetReady() over FixedUpdate(), and LateUpdateAfterGONetReady() over LateUpdate(). These are guaranteed to run only after networking is initialized, and they perform better at scale.
- Networked prefabs must be in a Resources folder. Any prefab you plan to spawn with GONetMain.Instantiate must be located in a Resources directory so GONet can find it by name across all machines.
Next Steps
With these concepts in hand, you are ready to explore GONet's core features:
- →Auto-Magical Sync -- Learn how to synchronize fields, properties, transforms, and animator parameters across the network with a single attribute.
- →Remote Procedure Calls -- Send messages between server and clients with ServerRpc, ClientRpc, and TargetRpc, including async/await support.