Skip to content

fix(coop): null-base arrival crash + owner labels - #109

Merged
NonPolynomialTim merged 1 commit into
mainfrom
fix/coop-shared-arrival-owner-labels
Jul 31, 2026
Merged

fix(coop): null-base arrival crash + owner labels#109
NonPolynomialTim merged 1 commit into
mainfrom
fix/coop-shared-arrival-owner-labels

Conversation

@NonPolynomialTim

Copy link
Copy Markdown
Collaborator

Summary

Fixes a SHARED-coop crash a player reported ("order soldiers in a shared base as host → the 2nd player crashes on arrival"), and adds owner-labelled arrival lists.

Root cause (from the player's crash dump): on arrival the ItemsArrivingState popup reaches the client via SharedEcon::hostAlert with a null _base — a replica's own transfers are frozen (PRD-J04), so the popup's ctor finds no hour-0 transfer. Pressing "Go to Base" then built BasescapeState(nullptr), whose coop ctor block if (_base->_coopBase == true) dereferenced the null base → 0xC0000005 read at [null+0x1d0].

Changes

  • A (crash fix): guard the BasescapeState ctor's early _base dereferences (the coop block ran before init()/setBase() could normalize a null base).
  • B: ItemsArrivingState "Go to Base" falls back to a real base when _base is unresolved.
  • C (feature): both players now see the full arrival list; a soldier not owned by the viewing player is prefixed with the owner's username, e.g. [HostPlayer] Sergey Moronova. The host builds authoritative rows in its (unchanged) scan-path popup and ships them on the existing alert lane (hostAlert gains a rows param); the client rebuilds the popup from them via a display-only ctor. The prefix is applied per-viewer using the stable, machine-independent seat→username roster (SavedGame::_coopPlayers).

Behavior change

A rows-less ItemsArrivingState alert no longer pops — the empty phantom popup on the replica is gone (and the host won't pop an empty one either). Real arrivals always carry rows.

Tests (all green)

  • tools/coop_test/test_shared_arrival_owner_labels.py (new) — host-hires + client-hires; asserts the owner sees a bare name and the peer sees [Owner] name, both directions.
  • tools/coop_test/test_shared_soldier_arrival_crash.py (new) — end-to-end hire → arrival → Go-to-Base, plus an unresolved-base alert; both no-crash. Went RED against a no-fix build (client process died, WinError 10054), GREEN after A+B.
  • tools/coop_test/test_shared_alerts.py — updated for the rows-based ItemsArrivingState; all 8 alert classes still replicate.

🤖 Generated with Claude Code

SHARED "ordered soldiers arrive -> 2nd player crashes": the arrival
popup (ItemsArrivingState) reached the client via hostAlert with a
null _base (a replica's own transfers are frozen), and "Go to Base"
built BasescapeState(nullptr), whose coop ctor block dereferenced it
(0xC0000005 read at [null+0x1d0]).

A: guard the BasescapeState ctor's early _base dereferences.
B: ItemsArrivingState "Go to Base" falls back to a real base when
   _base is unresolved.
C: both players now see the full arrival list; soldiers not owned by
   the viewing player are prefixed with the owner's username, e.g.
   "[HostPlayer] Sergey Moronova". The host builds authoritative rows
   and ships them on the existing alert lane; the client rebuilds the
   popup from them via a display-only ctor. A rows-less arrival alert
   no longer pops (no empty phantom popup on either machine).

Tests (all green): test_shared_arrival_owner_labels.py (new),
test_shared_soldier_arrival_crash.py (new),
test_shared_alerts.py updated for the rows-based ItemsArrivingState.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@NonPolynomialTim
NonPolynomialTim enabled auto-merge (squash) July 31, 2026 03:31
@NonPolynomialTim
NonPolynomialTim merged commit f15d306 into main Jul 31, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant