Skip to content

Fix multiplayer crash when a remote client controls an opponent#11006

Open
MostCromulent wants to merge 1 commit into
Card-Forge:masterfrom
MostCromulent:NetworkPlay/control-player-crash
Open

Fix multiplayer crash when a remote client controls an opponent#11006
MostCromulent wants to merge 1 commit into
Card-Forge:masterfrom
MostCromulent:NetworkPlay/control-player-crash

Conversation

@MostCromulent

Copy link
Copy Markdown
Contributor

Summary

Control-an-opponent effects (e.g. Secret of Bloodbending) crash the game in multiplayer when the controlling player is a remote client. Reproduction: in a network game, the remote client casts Secret of Bloodbending targeting the host; the game thread dies with IllegalArgumentException at AbstractGuiGame.setCurrentPlayer as soon as control takes effect on the host's turn.

Root cause: the controlled player's priority runs through the controller's shared InputProxy, so InputProxy.update calls setCurrentPlayer on the controller's GUI. On the host, that GUI's FControlGameEventHandler registers the controlled player as local when GameEventPlayerControl fires, so the call succeeds. The server-side RemoteClientGuiGame instead uses a GameEventForwarder that only relays events to the client and never updates its own gameControllers map — so the controlled player is never registered server-side and setCurrentPlayer throws.

The fix mirrors the host-side bookkeeping in RemoteClientGuiGame: on each GameEventPlayerControl, register or unregister the controlled player in the proxy's gameControllers, identifying the controller via the controlled player's mind-slave master and isLocalPlayer (not by name) so only the actual controller's proxy registers the player.


🤖 Generated with Claude Code

Control-an-opponent effects (e.g. Secret of Bloodbending) crashed the
game in multiplayer when the controlling player was a remote client. The
controlled player's priority is driven through the controller's shared
InputProxy, so InputProxy.update calls setCurrentPlayer on the
controller's GUI. On the host that GUI is a CMatchUI whose
FControlGameEventHandler registers the controlled player as local when
GameEventPlayerControl fires, so the call succeeds. The server-side
RemoteClientGuiGame instead uses a GameEventForwarder that only relays
events to the client and never updates its own gameControllers map, so
setCurrentPlayer threw IllegalArgumentException and killed the game
thread.

Mirror the host-side bookkeeping in RemoteClientGuiGame: on each
GameEventPlayerControl, register or unregister the controlled player in
the proxy's gameControllers. Identify the controller via the controlled
player's mind-slave master and isLocalPlayer rather than by name, so only
the actual controller's proxy registers the player.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Development

Successfully merging this pull request may close these issues.

1 participant