← World map and portals · all tasks
Meeting yourself in the Badlands — one account, one body, per world
world-map-and-portals/013 · created 2026-08-16 · updated 2026-08-18
What prompted it
Kris, exploring v5 with the portals finally working, walked into The Badlands and found a second William 3rd standing beside him — same name, same character, both idle.
Not a leftover verifier character. Both rows in that world’s snapshot carried his account id.
What was actually wrong
Entity ids are minted per world, and there are two ways to leave an Area:
- Through a portal — transfer step 1 erases you from the origin. Clean.
- By closing the game — your body stays standing where you left it. Also correct; that is the persistent world working as intended.
Come back into that Area later through a portal and you arrive carrying the id you hold in
the world you came from. _handle_hydrate_entity pointed entities_by_account at the
arriving body and simply left the old one sitting in entities — still broadcast to every
peer, still written into every snapshot, and never looked at again by anything, because the
account index only ever points at one. A body with no way back to its owner.
Kris’s own path was exactly this: he had been in the Village, closed the game, then come back in through his own front door. The Badlands twin was the same shape one hop further out.
The fix
_drop_other_entities_for_account(), enforcing one invariant — one account, one body, per
world — at both points where an entity enters a world:
- on arrival through a portal: the arriving body is the only one that account gets here, and any older one goes with it;
- on hydrating a snapshot: last-one-wins, and earlier bodies for the same account are dropped rather than loaded. That is what heals the snapshots already carrying duplicates, on their next spawn, with no migration to write.
Kris’s actual duplicate row was also deleted from production directly, so he didn’t have to wait for the Badlands to next spawn.
Verified
New test walks his exact path — be in the Village, close the game, come back in through your
own front door — and asserts one body in the Village afterwards. Confirmed it fails without
the fix (expected length 1, got 2), which is the only thing that makes a regression test
worth having. Director 154 tests, Godot 116. verify-home-door and verify-world-map both
10/10 against the droplet after deploying.
Server-side only — world_server.gd runs on the droplet, so no new APK and no web re-export.
v5 on the phone is still current.
View source in repository · also available as raw markdown.