Skip to content

API: Game Events

Lyraedan edited this page Sep 24, 2026 · 2 revisions

ONI Together raises events on Klei's global Game event bus using hashed identifiers in Shared.MP_HASHES. Subscribe with Game.Instance.Subscribe(...) and unsubscribe with Game.Instance.Unsubscribe(...).

MP_HASHES lives in the Shared assembly, which is merged into ONI_Together_API.dll, so you can use it directly from a mod that references the API. Each ModHashes implicitly converts to GameHashes / int, so it can be passed straight to the game's event API. Hashes are derived from a stable string name, so the same MP_HASHES constant resolves to the same id on every peer.

These are local process events, not network broadcasts. Each peer raises them from its own session state, so keep your handler null-safe and guard with inSession / isServer where appropriate.

Namespaces:

  • Shared → MP_HASHES

Subscribing

using Shared;
using UnityEngine;

public class MyEventHandler : KMonoBehaviour
{
    public override void OnSpawn()
    {
        base.OnSpawn();
        Game.Instance?.Subscribe(MP_HASHES.OnPlayerJoined, OnPlayerJoined);
        Game.Instance?.Subscribe(MP_HASHES.OnInSessionChanged, OnSessionChanged);
    }

    public override void OnCleanUp()
    {
        Game.Instance?.Unsubscribe(MP_HASHES.OnPlayerJoined, OnPlayerJoined);
        Game.Instance?.Unsubscribe(MP_HASHES.OnInSessionChanged, OnSessionChanged);
        base.OnCleanUp();
    }

    private void OnPlayerJoined(object data)
    {
        ulong playerId = Boxed<ulong>.Unbox(data);
        // ...
    }

    private void OnSessionChanged(object data)
    {
        bool inSession = ((Boxed<bool>)data).value;
        // ...
    }
}

Handlers take a single object argument and must be the exact same method reference used for both Subscribe and Unsubscribe.

Event reference

Constant Raised in Payload When
GameServer_OnStateChanged GameServer.SetState none Host: GameServer.State changed
GameServer_OnServerStarted GameServer.Start none Host: server finished starting
OnConnected GameServer.Start, client transports none Transport connected (host or client)
GameClient_OnConnectedInGame GameClient none Client: finished joining and loading into the game
OnMultiplayerGameSessionInitialized NetworkConfig none Host: Steam/LAN session finished initialising
OnInSessionChanged MultiplayerSession.InActiveSession Boxed<bool> Session active state changed
OnDisconnected NetworkConfig.Stop none Session stopped / disconnected
OnPlayerJoined SteamLobby, RiptideServer, RiptideClient Boxed<ulong> player id A peer joins
OnPlayerLeft SteamLobby, RiptideServer, RiptideClient Boxed<ulong> player id A peer leaves
OnPlayerCursorCreated MultiplayerSession.CreateNewPlayerCursor Boxed<ulong> player id A player's cursor object is created

Payloads

Payloads are pooled boxed values from the game's assemblies:

  • Boxed<ulong> — a player/user id. Read it with Boxed<ulong>.Unbox(data). (Producers use Boxed<ulong>.Get(id) and .Release(); consumers only need to unbox.)
  • Boxed<bool> — used by OnInSessionChanged. BoxedBools.True / BoxedBools.False are Boxed<bool>, read via ((Boxed<bool>)data).value.
  • Several events carry no payload; their data argument is null.

Notes

  • Always Unsubscribe (e.g. in OnCleanUp) to avoid leaked handlers across session/game reloads.
  • Use the MP_HASHES constants — never hardcode integer hashes.
  • In-repo examples: UnityChatBoxUI subscribes to OnInSessionChanged; AnimResyncRequester to GameClient_OnConnectedInGame and OnMultiplayerGameSessionInitialized; OxySyncChat to OnPlayerJoined.

Clone this wiki locally