menu_bookDocumentation

GameObjectSystem: Auto-Instantiation, Host-Controlled [Sync], RPCs, Stage Hooks, and Configuration Priority

calendar_today May 4, 2026 schedule ~1 min read person patrickjr verified 50

GameObjectSystem: Auto-Instantiation, [Sync] Properties, and RPCs

GameObjectSystem is a scene-level singleton that is automatically instantiated once per scene. Every non-abstract subclass is created when the scene initializes via Scene.InitSystems().

Auto-Instantiation

CSHARP
// This system is automatically created for every scene
public class MyGameSystem : GameObjectSystem<MyGameSystem>
{
    public MyGameSystem( Scene scene ) : base( scene ) { }
}

// Access from anywhere
var system = MyGameSystem.Current;
var system = MyGameSystem.Get( someScene );
var system = Scene.GetSystem<MyGameSystem>();

[Sync] Properties on GameObjectSystems

GameObjectSystem supports [Sync] properties. However, there is a critical difference from component sync: all [Sync] properties on a GameObjectSystem are always host-controlled. The ControlCondition is always c => c.IsHost, regardless of SyncFlags.FromHost.
CSHARP
public class MyGameSystem : GameObjectSystem<MyGameSystem>
{
    public MyGameSystem( Scene scene ) : base( scene ) { }

    // Always host-controlled, even without SyncFlags.FromHost
    [Sync] public int RoundNumber { get; set; }
    [Sync] public float TimeRemaining { get; set; }
}

RPCs on GameObjectSystems

RPCs work on GameObjectSystem just like on components. They are routed by the system's Guid rather than a GameObject Guid.

CSHARP
public class MyGameSystem : GameObjectSystem<MyGameSystem>
{
    public MyGameSystem( Scene scene ) : base( scene ) { }

    [Rpc.Broadcast]
    public void AnnounceWinner( string playerName )
    {
        Log.Info( $"Winner: {playerName}" );
    }

    [Rpc.Host]
    public void RequestRespawn()
    {
        // Only runs on host
        SpawnPlayer( Rpc.Caller );
    }
}

Stage Hooks

CSHARP
public class MyGameSystem : GameObjectSystem<MyGameSystem>
{
    public MyGameSystem( Scene scene ) : base( scene )
    {
        Listen( Stage.StartUpdate, 0, OnStartUpdate, "MyGameSystem.OnStartUpdate" );
        Listen( Stage.PhysicsStep, 0, OnPhysicsStep, "MyGameSystem.OnPhysicsStep" );
        Listen( Stage.SceneLoaded, 0, OnSceneLoaded, "MyGameSystem.OnSceneLoaded" );
    }

    void OnStartUpdate() { /* runs before all component OnUpdate calls */ }
    void OnPhysicsStep() { /* runs during fixed update, after component FixedUpdate */ }
    void OnSceneLoaded() { /* runs after the scene finishes loading */ }
}

Configuration Priority

[Property] fields on a GameObjectSystem are configured in this order:
  1. Project-wide value from ProjectSettings.Systems
  2. Default value from property initializer
  3. Scene-specific override (from the scene file's GameObjectSystems JSON block)
Was this helpful?