Skip to content

Mob sync breaks on large levels (registry_mismatch -> missing_sync_id); reconnect cannot resume current run #50

Description

@luan-a2

Environment

  • Dead Cells: v35 (2026-05-19 build, non-Steam/Goldberg)
  • DCCM core: 35.12.8
  • Mod: DeadCellsMultiplayerMod 0.8.91 (release v0.4.3, commit 52f383d)
  • Network: LAN + VPN-like tunnel (Hamachi-like tunnel), TCP 1234
  • Two players, one host / one client

Bug 1 (main): mob sync breaks on large levels — registry_mismatchmissing_sync_id flood

On the client side, right after entering a large level (SewerShort, 140 tracked mobs) the log floods with paired stale-mapping warnings:

[18:19:00 WRN] [MobSync] stale tracked sync mapping syncId=44 localIndex=142 reason=registry_mismatch:45
[18:19:00 WRN] [MobSync] stale tracked sync mapping syncId=45 localIndex=142 reason=registry_mismatch:44
[18:19:00 WRN] [MobSync] stale tracked sync mapping syncId=40 localIndex=141 reason=registry_mismatch:41
[18:19:00 WRN] [MobSync] stale tracked sync mapping syncId=41 localIndex=141 reason=registry_mismatch:40
[18:19:00 WRN] [MobSync] stale tracked sync mapping syncId=142 localIndex=180 reason=registry_mismatch:143
... (142↔143, 151↔152, 158↔159 too)

Every pair has the same localIndex, i.e. the same mob is reachable under two adjacent syncIds: IdToMob[44] = mobX while MobToId[mobX] = 45. Right after that, hits on those mobs fail:

[18:19:06 WRN] [MobSync] mapping mismatch context=hit syncId=46 expectedType=Zombie|Zombie actualType= reason=missing_sync_id
[18:19:09 WRN] [MobSync] mapping mismatch context=hit syncId=38 expectedType=Scorpio|Scorpio actualType= reason=missing_sync_id
... 130+ more across the level (syncIds in host's allocated range)

Observed effect: the client sees mobs that don't take damage / desync. Leaving to the next level (rebuild resets everything) fully heals it. Small levels (PrisonStart, 35 mobs) show only a handful of benign missing_sync_id; the paired registry_mismatch only appears on big levels.

Host side (trace enabled) shows the allocator is now monotonic (35 → 175 → 263 → 313, the nextRuntimeSyncId=0 reset from the old build is gone — good), so this is a remaining bug in the bind path: during multi-round MOBREG/MOBSTATE binding on a 140-mob level, one mob ends up bound to two adjacent syncIds. Suspect TryBindUnboundMobByTypeAndSpawnLocked — it skips mobs that are already bound (MobToId check) but never checks whether the target syncId is already occupied, and the one-shot state bind (state_oneshot_bind) plus MOBREG re-broadcast can race on nearby same-type mobs.

Bug 2: client reconnect cannot resume the current run (falls back to its own stale save)

Client is non-authoritative, so SaveGuard blocks every client world save during the run:

[18:44:59] [NetMod][SaveGuard] skipped non-authoritative client world write before host-disconnect auto-exit (host_disconnect)

After a disconnect and reconnect, the client auto-starts from its own local save ([NetMod] Auto-started new game after seed, [MobSync] ... role=client), which is always an older level than the host's current one (host was in BeholderPit, client landed in PrisonCourtyard, plus [NetMod] Remote level graph not applied for PrisonCourtyard: remote graph not received). The host's Coop ghost runtime bootstrapped for continue/level hero=880 level=BeholderPit only restores the host itself — it does not steer the client to the host's level. So reconnecting mid-run cannot continue the same progress; the only reliable path is to start a brand-new run.

Also, when the host is already inside a run and the client reconnects (host did not restart), the client just sits in the lobby and never enters the run.

It would be great to have the host re-send the current level/seed state on reconnect so the client can rejoin the host's current level.

Bug 3 (minor): host opening the main menu mid-run crashes the client

[18:43:03] [NetMod] Main menu opened during run; stopping network → client goes through host-disconnect auto-exit → level dispose → game re-init → Fatal Error:

[18:45:13 FTL][GameStartup] Fatal Error
Hashlink.Marshaling.HashlinkError: Uncaught hashlink exception.Null access .isEnable
   at Haxe!hxd.App.mainLoop ...
   at ModCore.Modules.GameStartup.StartGame()

Crash happens at GameStartup.StartGame() right after the forced exit/continue bootstrap — probably a null UI/game object after the non-authoritative save was skipped.

Logs

Full trace logs (host 7.9 MB, client 96 KB) available on request — happy to share the exact files.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions