Skip to article Developer portalAnnounce, upload and sell your game

GAMENIGHT / DOCUMENTATION

Rust / Bevy

Use gamenight-sdk for the WebSocket connection and typed events. The SDK is engine-independent. It does not create windows, pause Bevy systems, draw faces or apply controller state for you.

Add the SDK

For a project in this workspace, use the workspace dependency. For a separate project, pin a reviewed public repository commit:

[dependencies]
gamenight-sdk = { git = "https://github.com/ontola/gamenight", rev = "YOUR_REVIEWED_COMMIT" }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

Replace YOUR_REVIEWED_COMMIT with an actual commit hash. Do not treat the placeholder as a published release.

Receive lifecycle events

This compilable example shows the connection and session transitions. It has no renderer or simulation, so it reports Ready only for its empty sample session. Put your real loading and first-frame work before Ready.

//! Protocol-only skeleton, compiled by the documentation CI.
use gamenight_sdk::{GameEvent, GameNight, SdkError};

#[tokio::main]
async fn main() -> Result<(), SdkError> {
    if !GameNight::launched_by_daemon() {
        println!("Standalone mode: open your game's menu here.");
        return Ok(());
    }
    let mut host = GameNight::connect_from_env().await?;
    while let Some(event) = host.next_event().await? {
        match event {
            GameEvent::Prepare {
                session,
                seats,
                players,
            } => {
                // Replace this with hidden loading, roster setup and first-frame work.
                println!(
                    "Prepare {} seats and {} profiles",
                    seats.len(),
                    players.len()
                );
                host.participation(session, false).await?;
                host.ready(session).await?;
            }
            GameEvent::Start { .. } | GameEvent::Resume { .. } => {
                // Show the prepared window; enable simulation and audio.
            }
            GameEvent::Pause { .. } => {
                // Freeze simulation and audio, then hide the window.
            }
            GameEvent::ControllerFrame { controllers } => {
                // Store receipt time. Match controllers by token, never list order.
                println!("{} controller states", controllers.len());
            }
            GameEvent::PartyUpdated { seats, players, .. } => {
                // Apply the roster and changed profiles without restarting the round.
                println!(
                    "Update {} seats and {} profiles",
                    seats.len(),
                    players.len()
                );
            }
            GameEvent::Dispose { .. } => {
                // Release session resources. Keep listening for another Prepare.
            }
            _ => {}
        }
    }
    // Host disconnected: leave no window or background game running.
    Ok(())
}

Source: crates/gamenight-sdk/examples/docs_lifecycle.rs

Run it from the public repository with cargo run -p gamenight-sdk --example docs_lifecycle. Without a host launch it exits through the standalone branch. In a game, that branch starts your normal menu.

Connect to your game loop

Run the network task separately and pass events into your engine through a channel. Apply Prepare and PartyUpdated to the roster. Store ControllerFrame data with a receipt time, then have your input system look up each seat’s exact controller token.

In Bevy, gate simulation systems on your session state. Do not pause the network task or the systems that receive Resume. Drain messages every frame, including while loading, paused or displaying results. Send Ready after assets and a rendered frame are ready, not immediately after receiving Prepare.

Controllers and faces

GameEvent::ControllerFrame contains Vec<ControllerState>. Clear input after 250 ms without a frame, on an empty frame, or when a token disappears. Controllers & players covers axes, button bits and ownership.

Use gamenight_protocol::Avatar::parse, to_rgba() and head_layout() for artwork. Draw a skin-coloured circle underneath and use the head centre as the texture origin. Faces & colours describes the coordinates.

Validate the result

cargo check -p gamenight-sdk --example docs_lifecycle
cargo test -p gamenight-sdk

These check the SDK and example. They do not certify your window, audio, controller mapping or renderer. Run the packaged-game integration checks too.

Optional performance diagnostics

Call GameNight::performance(session, sample) with a gamenight_protocol::PerformanceSample built from your own active frame measurements. The Rust SDK does not assume an engine update loop or sample automatically. See the protocol reference for counters, limits and missing-data semantics. These diagnostics contain no accounts, behavioral history or recommendation logic.