tag

#multiplayer

16 items (4 guides · 12 fixes)

guides
guide
Decals: projection, determinism, and performance in s&box

The practical patterns for Sandbox.Decal: orienting the projection box to a hit normal, keeping a decal byte-identical across multiplayer peers, making paint follow an animated character, and scaling to thousands of decals without a performance cliff, plus the pitfalls that catch each one.

guide
Networking methods: spec replication + host-authority patterns

Two proven architectures on top of the engine networking primitives: replicate the generator spec (not the geometry) for deterministic worlds, and retrofit local-only gameplay systems to host-authority without breaking single-player.

guide
P2P peer-hosted servers: from working co-op code to a friend actually joining

The operational recipe for shipping player-hosted (P2P) multiplayer in s&box (lobby mechanics, invite codes, the join handshake liveness contract, replication traps, and the three-rung testing ladder), covering the layer the official docs don't document and where live multi-peer sessions actually break.

guide
Proximity voice chat: the built-in Sandbox.Voice component

The complete method for wiring s&box's built-in Voice component into a networked game (push-to-talk, 3D positional playback, custom falloff curves, speaking indicators, and lip-sync), with no third-party voice SDK.

fixes
26.07.15a
"A -joinlocal dev-host client CAN read the host's Networking.SetData lobby metadata"

A second editor instance launched with -joinlocal is not a real Steam lobby member, yet Networking.GetData still resolves the host's Networking.SetData values -- they arrive over the ServerDataMsg the host sends on connect, not via lobby membership. The message can lag scene load by a few frames, so read GetData in a short poll loop.

26.08.05
"A -joinlocal peer joins whoever owns 127.0.0.1:55333, not whoever is in play mode"

A -joinlocal second instance connects to whichever process holds the loopback port 127.0.0.1:55333, so the precondition to check is socket ownership, not which editor is in play mode.

26.07.15a
"A code-built world can run TWICE on a network join and stack a second world on the first"

A joining client can build a code-generated world twice -- once on local StartupScene load, once on the networked scene handoff. A non-idempotent world author that clears its tracking lists but never destroys prior GameObjects stacks a whole second world. Make the author idempotent, and compute any sync hash from the build recipe, not a live scene scan.

26.07.15a
"Dev-host streaming skips loose data files, breaking deterministic sync"

Dev-host streaming sends assemblies and compiled assets but NOT loose data files read via FileSystem.Mounted: a joining client that loads a raw JSON manifest builds differently, silently.

26.07.15a
"Idempotent world rebuild needs DestroyImmediate, not Destroy"

Deferred Destroy() leaves the old code-built world overlapping the fresh one for a frame: use DestroyImmediate for teardown before rebuild, and pair it with a recipe hash for belt-and-suspenders join verification.

26.07.15a
"Joining client's singleton claim grabs the host's character"

A static Instance claimed behind if (!IsProxy) in OnStart grabs the host's character on a joining client: the client camera follows the wrong player forever.

26.07.22
"Local two-peer multiplayer testing with -joinlocal"

sbox.exe -joinlocal +instanceid 1 gives you a real second peer against an editor host with no publish, no second Steam account, and no lobby discovery. It has no host selector: it joins whichever local editor is in PLAY MODE, so no other editor on the machine may be playing.

26.07.22
"Networking API facts to check against the installed build before you compile"

A batch of networking API facts, verified from the installed build's source and XML, that overturn common assumptions when you plan multiplayer code before it touches the compiler. LobbyInformation is a struct, so a null guard does not compile. Networking.Connections is deprecated in favour of Connection.All and emits CS0618. Connection.MaxChunkSize is internal, so game code hard-codes the 131072 value instead of referencing the symbol. NetworkAccessor exposes Owner, OwnerTransfer, and OrphanedMode as get-only, with AssignOwnership, SetOwnerTransfer, and SetOrphanedMode called after NetworkSpawn. Networking.TryConnectSteamId exists and is public. SB1000 whitelisting is assembly-level, so the real constraint on a networking call is public versus internal accessibility, not the whitelist. A green dotnet build does not mean an editor-green result for networked types.

26.07.15a
"Push-to-talk silently dead: Voice action missing from Input.config"

The Sandbox.Voice component defaults PushToTalkInput to 'voice', but not every project ships a matching 'Voice' InputAction. PTT is a dead key with zero errors until you add it to Input.config.

26.07.08e
"Rpc.Broadcast on a non-networked GameObject runs locally only -- no warning"

An [Rpc.Broadcast] called on a component whose GameObject is not networked executes locally and silently never crosses the wire -- no warning at any log level.

26.07.15a
"Sandbox.Decal renders differently on each peer due to random self-seed"

Sandbox.Decal self-seeds with Random.Shared.Int(10000) on enable: a decal spawned identically on two peers renders differently by default.

26.07.15a
"Steam lobby metadata survives host game switch"

A Steam lobby survives its host switching to a different s&box game with stale metadata: a joiner connects and loads the wrong game's content.

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