the symptom, in your words

"CreateLobby is async — IsActive is still false on the same frame"

✓ verified on engine 26.07lane: Writing gameplayposted

▸ SYMPTOM

Two related symptoms from the same root cause:

  1. Every hosted session falls through to the offline/solo path even when hosting succeeds. A "Play" button that calls CreateLobby() then checks Networking.IsActive always takes the false branch on the same frame, causing the game to run the solo-possess path instead of waiting for the lobby to come up.

  2. The "Stop Server" button appears to do nothing. The session-end path sets the mode to idle and calls Networking.Disconnect() but never un-possesses the player — the host stays in character view with the generator UI disabled. The button fires; the state just never changes back to the pre-session view.

▸ CAUSE

Networking.CreateLobby(...) is asyncNetworking.IsActive is still false on the same frame you call it. Any code that branches on IsActive immediately after CreateLobby takes the wrong branch:

snippet
// BUG: IsActive is async-false on this frame
CreateLobby();
if ( Networking.IsActive )
    return;        // never reached
SoloPossess();     // always runs, even when hosting

The session-end side: an EndSession method that only flips a mode enum and calls Disconnect() but never un-possesses the character leaves the host stuck in the character view — the "pointer-events: none" suspicion is a red herring; the state just never returned to the authoring view.

▸ FIX

Part 1 — gate on the synchronous source of truth. Use your own mode enum (which you set on the same frame as CreateLobby) instead of Networking.IsActive:

snippet
void Play()
{
    Mode = SessionMode.Hosting;      // synchronous — set this frame
    CreateLobby();

    if ( Mode == SessionMode.Hosting )
        return;   // trust the async auto-possess poll to walk the host in

    // Fallback: solo mode
    SoloPossess();
}

Add a timed watchdog (~4 seconds): if Networking.IsActive is still false at timeout, fall back to the offline solo path so the one-click action always does something even with Steam offline.

Part 2 — un-possess on session end:

snippet
void EndSession()
{
    if ( InCharacterMode )
        ExitCharacter();          // restore the pre-session view
    Mode = SessionMode.Authoring;
    Networking.Disconnect();
}

▸ WHY IT WORKS

Your mode enum is a synchronous, immediate state change — it reflects the user's intent on the same frame. Networking.IsActive reflects the network system's state, which lags behind by at least one frame while the lobby is being created asynchronously. By gating on intent (mode) rather than network readiness, the control flow matches the user's action.

The un-possess step ensures the visual state (camera, UI, input routing) returns to the pre-session state, not just the logical mode. Without it, the host remains visually in-character with the session UI disabled.

Verified on engine 26.07 — seen in a real project.
s&box moves fast; an undated fix is a liability. Spot a stale detail?