menu_bookDocumentation

Sandbox: CleanupSystem — full scene cleanup and per-player cleanup with Ownable

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

Sandbox CleanupSystem — Scene Cleanup and Per-Player Cleanup

CleanupSystem is a GameObjectSystem that handles cleaning up spawned objects. It distinguishes between "baseline" objects (part of the original scene) and "spawned" objects (added at runtime).

Full scene cleanup

CSHARP
// Removes all spawned objects and restores destroyed baseline objects
// Players and their belongings are preserved
public void Cleanup()
{
    // 1. Destroy all objects tagged "removable" that aren't player-owned
    // 2. Restore any baseline objects that were destroyed
    // 3. Fire ICleanupEvents.OnCleanup
}

Per-player cleanup

CSHARP
// Admin-only: clean up a specific player's objects
[Rpc.Host]
public static void CleanupPlayer( Connection caller )
{
    Assert.True( Networking.IsHost );

    var removable = Game.ActiveScene.GetAllComponents<Ownable>()
        .Where( o => o.Owner == caller );

    var count = 0;
    foreach ( var ownable in removable.ToArray() )
    {
        ownable.GameObject.Destroy();
        count++;
    }

    Notices.SendNotice( caller, "cleaning_services", Color.Green, $"Cleaned up {count} objects" );
}

Baseline preservation for save/load

CSHARP
// Call before Game.ChangeScene() when loading a save
// Captures the current scene's baseline so it can be restored after load
public static void PreserveBaselineForSaveLoad() { ... }

IsPlayerObject check

The cleanup system uses a recursive parent walk to determine if a GameObject belongs to a player:

CSHARP
private static bool IsPlayerObject( GameObject go )
{
    if ( go.Components.Get<Player>( true ) is not null ) return true;
    if ( go.Components.Get<PlayerData>( true ) is not null ) return true;

    var parent = go.Parent;
    while ( parent is not null && parent != go.Scene )
    {
        if ( parent.Components.Get<Player>( true ) is not null ) return true;
        parent = parent.Parent;
    }
    return false;
}

ICleanupEvents

CSHARP
public interface ICleanupEvents : ISceneEvent<ICleanupEvents>
{
    void OnCleanup() { }
}

Implement on a GameObjectSystem or Component to receive cleanup notifications.

Key points

Was this helpful?