"Local two-peer multiplayer testing with -joinlocal"
▸ SYMPTOM
You need to test multiplayer behavior with two real peers but don't want to publish, set up a dedicated server, or use a second Steam account.
▸ CAUSE
The engine has a built-in local two-peer testing mode, but it's not prominently documented. While an editor play session is hosting, it opens a TCP socket on 127.0.0.1:55333 that accepts direct-connect clients.
▸ FIX
While an editor play session is hosting (lobby created, networking active):
sbox.exe -joinlocal +instanceid 1 -sw -720The instance auto-connects to the local host at bootstrap, presents a fake per-instance SteamId with a random persona (e.g. "Wiggum"), completes the dev-host handshake (assemblies stream from the host's network table), and spawns as a genuine second player. This is the same mechanism the editor's "new game instance" toolbar button uses.
Key traps
- Launch after the host is live. Verify the host's networking is active first — rapid re-host iteration can transiently fail
CreateLobby(~15-20 s settle clears it). - Invite-code verification rejects the
-joinlocalpeer — it TCP-connects directly and never runs the code-entry UI, so it presents an empty code. Add a dev-only seam (accept empty code whenApplication.IsEditorand the caller is loopback) rather than weakening the shipped gate. - The client truncates
logs/sbox.log— host evidence must come from re-fetchable probes or the editor console, not the shared log file. - A failed join permanently wedges the editor's game package mount — plan an editor restart after every failed attempt.
- Eyeball the client window at least once. Host-side probes structurally cannot see a client whose camera/UI is wrong.
Blind spots
A -joinlocal peer never enters an invite code, never exercises the assembly reload (same process), and never tests FileSystem.Data carry. Bugs that only bite on a real published join are invisible here. Multiple live-proven bugs have sailed through green local runs for this reason — always follow up with a real published-build test (rung 3).
▸ WHY IT WORKS
The editor host advertises dev-host=true, which lets clients tolerate a missing local package and stream assemblies instead. The +instanceid flag gives each client a unique fake SteamId so the engine treats them as separate players. This is loopback-only (same machine), which is both its strength (zero setup) and its limitation (can't test real network conditions or Steam backend behavior).