Scene Management

GONet provides server-authoritative scene management that keeps all clients in sync. Late-joining clients automatically load the correct scene, and the system supports both BuildSettings scenes and Unity Addressables.

Loading Scenes (Server-side)

The server controls which scene is active. Use GONetMain.SceneManager to load scenes from either Build Settings or Unity Addressables, and to unload scenes that are no longer needed.

// Load from Build Settings
GONetMain.SceneManager.LoadSceneFromBuildSettings("BattleArena", LoadSceneMode.Single);

// Load from Addressables
GONetMain.SceneManager.LoadSceneFromAddressables("DynamicLevel", LoadSceneMode.Additive);

// Unload
GONetMain.SceneManager.UnloadScene("DynamicLevel");

When the server loads a scene, all connected clients automatically receive the instruction and load the same scene. The server waits for confirmation from each client before proceeding.

Client Scene Requests

Clients cannot load scenes directly. Instead, they can request that the server load a scene. The server must approve the request before any scene transition occurs.

// Client can request (requires server approval)
GONetMain.SceneManager.RequestLoadScene("Arena");

This keeps the server in full control of the game flow. If the server does not have a validation hook registered, the request is denied by default.

Server-Side Validation

Register a validation hook on the server to approve or deny client scene load requests. This is where you enforce access control -- for example, preventing non-admin players from loading restricted levels.

GONetMain.SceneManager.OnValidateSceneLoad += (sceneName, mode, clientAuth) =>
{
    if (sceneName == "AdminLevel" && !IsAdmin(clientAuth))
        return false;  // Deny
    return true;       // Approve
};

The callback receives the requested scene name, the load mode, and the requesting client's authority identifier. Return true to approve the load or false to deny it.

Late-Joiner Sync

When a new client connects after a scene is already loaded, GONet handles synchronization automatically:

  • 1.Scene loading -- The new client automatically loads the server's current scene. No manual intervention is required.
  • 2.GONetId assignment -- Scene-defined GONetParticipant objects get their GONetIds assigned automatically as part of the sync process.
  • 3.No race conditions -- If GONetId assignments arrive before the scene has finished loading on the client, they are buffered and applied once the scene is ready. This prevents the common race condition where network data arrives for objects that do not exist yet.

GONetId Sync: Proactive vs Reactive

Scene-defined GONetParticipant objects need their GONetIds synchronized to late-joining clients. GONet supports two strategies:

Proactive Sync

The server sends GONetId assignments to the client immediately as part of the scene load process. This is the default behavior and ensures objects are ready as soon as the scene finishes loading.

Reactive Sync

GONetId assignments arrive as they are needed (e.g., when state updates reference an unknown ID). This is used for dynamically spawned objects and as a fallback for edge cases.

DontDestroyOnLoad Handling

GONetParticipant objects marked with DontDestroyOnLoad persist across scene transitions. GONet handles this automatically:

  • Persistent objects retain their GONetId across scene loads.
  • State synchronization continues uninterrupted during scene transitions.
  • Late-joining clients receive persistent objects along with the scene state.

Retry Mechanism

Network operations during scene transitions can fail due to timing issues (e.g., the client is still loading when the server sends state). GONet includes automatic retry logic:

  • GONetId assignments that arrive before the scene is ready are buffered and applied once loading completes.
  • Failed scene load acknowledgments are retried automatically until the server confirms receipt.
  • If a scene load fails on a client, the server is notified and can take corrective action (e.g., retry the load command or disconnect the client).

Querying Scene State

You can check the current scene state at any time using the scene manager's query methods. These are useful for UI elements, loading screens, and conditional logic that depends on which scene is active.

bool loading = GONetMain.SceneManager.IsSceneLoading("Arena");
string current = GONetMain.SceneManager.GetCurrentScene();
List<string> loadingScenes = GONetMain.SceneManager.GetLoadingScenes();

Best Practices

  • Only the server should initiate scene loads -- While clients can request scene changes, the server should be the sole decision-maker. This prevents desynchronization and ensures all clients experience the same game flow.
  • Use validation hooks to control client access -- Always register an OnValidateSceneLoad handler if you allow client scene requests. Without one, all requests are denied by default.
  • Use Additive mode for dynamic sub-areas -- When loading supplementary areas (arenas, dungeons, instanced zones), use LoadSceneMode.Additive to layer them on top of the base scene. This avoids unloading shared infrastructure and allows smoother transitions.

Next Steps

Now that you understand scene management, explore these related topics:

  • Performance -- Optimize bandwidth, CPU usage, and memory with quantization, velocity sync, SoA blending, and object pooling.
  • API Reference -- Quick reference for all major classes, attributes, configuration options, and constants.
Scene Management | GONet Docs