Upstream TheSuperHackers PR TheSuperHackers#1471 (Stubbjax, 67f50d1) made
MSG_CREATE_TEAM_N process immediately in CommandXlat on the sender while
every other player still processed it via GameLogicDispatch at the
network-delivered logic frame. That created a RUNAHEAD-sized window in
which Player::m_squads on the sender disagreed with every remote view
of the sender's m_squads.
m_squads itself isn't in the CRC, but it's read by game logic that does
feed CRC. ReplaceObjectUpgrade::upgradeImplementation calls
getSquadNumberForObject() to decide whether to emit a follow-up
MSG_CREATE_TEAM for the replacement object, and
processSelectTeamGameMessage copies m_squads[N] into m_currentSelection,
which logicMessageDispatcher reads when populating the per-message
AIGroup that goes into TheAI->m_groupList (which IS in AI::crc). Either
path turns the m_squads divergence into a CRC mismatch the next time a
CRC checkpoint runs.
Two live 4v4 LAN matches on the same Zulu build reproduced the desync
on the same player both times, with CRC divergence localized to that
one player and the divergence frame landing 15-67 logic frames after
that player issued a CreateGroup command. The repro harness in
tools/desync-repro reliably reproduces in 3-10 minutes against the
buggy build with 200ms injected latency.
Fix: remove the CommandXlat fast-path entirely, and restore the
GameLogicDispatch handler to process MSG_CREATE_TEAM_N for every
player (including the sender) at the network-delivered logic frame.
Same strategy taken upstream in TheSuperHackers PR TheSuperHackers#2694.
Generals/ copies of these files are left alone per project convention.
Local group creation is not logically safe and can cause mismatches. This PR reverts previous changes, so that group creation is only handled by the Logic and not the Client.
TODO: