"Dev-host streaming skips loose data files, breaking deterministic sync"
▸ SYMPTOM
A joining client in a dev-host session (editor or -joinlocal) produces a different world or game state than the host. The client's content is missing pieces — props, terrain features, or layout elements that the host has. Both peers play without errors, but one is in a half-empty world. If you exchange and compare world hashes, they differ.
▸ CAUSE
Dev-host streaming sends assemblies (compiled code) and referenced compiled assets to joiners, but not loose data files read via FileSystem.Mounted. A world generator that loads a raw JSON manifest (e.g. models/playground/playground_manifest.json) at build time works on the host but the file is missing on the joining client — the client builds with zero items from that manifest.
The divergence is silent: no missing-file exception (the file-read returns empty/null and the generator skips it), no network error, no visual warning. Both peers play normally, just in different worlds.
▸ FIX
Two options:
-
Move world-defining data into code constants or compiled assets that travel with the assembly stream. Anything the world generator reads at build time must be reachable on every peer.
-
Make the world build host-computed and network-spawned — the host builds the world and replicates the result, so clients never need the source data.
Always exchange and assert the world hash at join time regardless of approach:
// After the client finishes its regen:
var clientHash = ComputeWorldHash();
SendHashToHost(clientHash);
// Host-side:
if (clientHash != hostHash)
RejectJoin("World hash mismatch — content diverged");Without the hash check, the divergence is undetectable — both peers play, one in a broken world.
▸ WHY IT WORKS
The dev-host streaming protocol is designed for code and compiled resources, not arbitrary file I/O. Loose files under FileSystem.Mounted are project-local filesystem reads that have no corresponding entry in the network table. By putting world data into the compilation pipeline (or computing it host-side and replicating), you ensure every peer works from the same inputs. The hash assertion is the safety net that catches any remaining divergence before it becomes a silent gameplay difference.