the symptom, in your words

"A -joinlocal test peer presents an empty invite code, so a wire-verified code gate rejects it"

✓ verified on 26.07.15
lane Writing gameplayposted

▸ SYMPTOM

You test local two-peer networking by launching a second instance with -joinlocal. Every hop looks healthy — the peer connects, exchanges a world hash — but the join fails with something like "invite code rejected," and it never completes a full handshake. A real friend joining through the in-game Join box works fine. Verified on engine 26.07.15.

▸ CAUSE

A -joinlocal second instance never runs the in-game Join UI. It TCP-connects straight to the editor's loopback dev-host socket, so it arrives with an empty invite code.

If your host verifies the code on the wire — for example a visible-lobby design where the host checks a hashed code against what the joiner sends — it will (correctly) reject a peer that presents no code. So the local -joinlocal test can't complete the handshake even though nothing else is wrong.

This is a test-harness artifact, not a product bug. A real friend joins through the Join box, which sets the code, so the wire-verify never rejects them. In a live repro, the -joinlocal client reached the host's world-hash report step and then got a code-verify verdict=REJECT reason=no invite code presented; the client cleanly showed "invite code rejected" and recovered to authoring. The wire-verify was doing its job — the joiner simply had no code to present.

▸ FIX

Don't weaken the shipped gate to make the local test pass. Add a tight, clearly-commented dev-only exception that accepts an empty code only when both conditions hold host-side:

  • Application.IsEditor on the host — a published host is never IsEditor, so this can't affect shipped builds; and
  • the caller is a loopback peerConnection.Address resolves to a loopback address for a -joinlocal peer, giving you a usable host-side signal.
snippet
// Host-side, when verifying the presented invite code:
bool devLoopback = Application.IsEditor
    && connection.Address is not null
    && IsLoopback( connection.Address );   // matches the local loopback address

if ( presentedCode.Length == 0 && !devLoopback )
    return Reject( "no invite code presented" );
// else accept: real friend via Join box (has a code) or a local dev loopback peer

With that seam in place, a live run went DEV-HOST ACCEPT → code-verify OK → hash MATCH → handshake ready → joiner JOINED with correct proxy flags.

(If your design later accepts code-less joins everywhere — e.g. to support platform-invited friends who connect with no typed code — the loopback exception becomes redundant, but it's still a good reference for the loopback-detection idiom.)

▸ WHY IT WORKS

The rejection is a false negative caused entirely by how the test peer connects, not by a fault in your networking. -joinlocal bypasses the UI that would set the code, so it can never satisfy a wire code-check. Gating the exception on IsEditor and a loopback address means it can only ever fire for a local development test — a published host fails the IsEditor check, and a remote attacker fails the loopback check — so the shipped verification stays intact while your local two-peer test can complete.

Verified on engine 26.07.15: seen in a real project.
s&box moves fast; an undated fix is a liability. Spot a stale detail?
changelog
  • Published.

Want to know when new guides or fixes drop? Join the community to help build this out. Report gotchas, flag outdated fixes, or just lurk.

Join the Discord