Skip to content

feat: 8-player multiplayer support with command relay#1170

Merged
braedonsaunders merged 1 commit into
mainfrom
claude/audit-dead-code-Kwa8p
Jan 31, 2026
Merged

feat: 8-player multiplayer support with command relay#1170
braedonsaunders merged 1 commit into
mainfrom
claude/audit-dead-code-Kwa8p

Conversation

@braedonsaunders

Copy link
Copy Markdown
Owner
  • Update multiplayerStore.ts with multi-peer infrastructure:

    • Add peerChannels Map for tracking multiple connections
    • Add remotePeerIds array for all connected peers
    • Implement addPeer/removePeer for managing connections
    • Add broadcastMessage() for sending to all peers
    • Add sendToPeer() for targeted messages
    • Host automatically relays commands to other guests
  • Update Game.ts lockstep barrier for N players:

    • getExpectedPlayerIds() now returns all peer IDs
    • Supports 2-8 players in lockstep synchronization
  • Update useMultiplayer.ts for multi-peer sync:

    • Sync ALL guest data channels using addPeer()
    • Guest mode also uses addPeer for consistency
  • Delete dead code (~1400 lines):

    • src/hooks/useP2P.ts (superseded by useMultiplayer.ts)
    • src/engine/network/p2p/ConnectionCode.ts (not used)
    • src/rendering/GroundDetail.ts (CrystalField never imported)
    • tests/engine/network/connectionCode.test.ts

https://claude.ai/code/session_01V7DKiAVN3pWV2NxZ7iYsjb

- Update multiplayerStore.ts with multi-peer infrastructure:
  - Add peerChannels Map for tracking multiple connections
  - Add remotePeerIds array for all connected peers
  - Implement addPeer/removePeer for managing connections
  - Add broadcastMessage() for sending to all peers
  - Add sendToPeer() for targeted messages
  - Host automatically relays commands to other guests

- Update Game.ts lockstep barrier for N players:
  - getExpectedPlayerIds() now returns all peer IDs
  - Supports 2-8 players in lockstep synchronization

- Update useMultiplayer.ts for multi-peer sync:
  - Sync ALL guest data channels using addPeer()
  - Guest mode also uses addPeer for consistency

- Delete dead code (~1400 lines):
  - src/hooks/useP2P.ts (superseded by useMultiplayer.ts)
  - src/engine/network/p2p/ConnectionCode.ts (not used)
  - src/rendering/GroundDetail.ts (CrystalField never imported)
  - tests/engine/network/connectionCode.test.ts

https://claude.ai/code/session_01V7DKiAVN3pWV2NxZ7iYsjb

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 39137cfea5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/engine/core/Game.ts
Comment on lines +479 to +483
// Get all remote peer IDs (supports 2-8 players)
const remotePeerIds = getAllPeerIds();
for (const peerId of remotePeerIds) {
if (!players.includes(peerId)) {
players.push(peerId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Align lockstep expected IDs with command player IDs

In multiplayer, getExpectedPlayerIds() now appends getAllPeerIds() (Game.ts 479-483), but those IDs are populated from network peer identifiers (addPeer(guest.pubkey, ...) and the synthetic host-... in useMultiplayer.ts 850-858, 875-881). Lockstep receipts are recorded under command.playerId (Game.ts 639-643), which is sourced from getLocalPlayerId()/slot IDs (useWorkerBridge.ts 136-149). In a normal lobby where player IDs are player1/player2, the peer IDs will never match the command receipts, so hasAllCommandsForTick() will wait indefinitely and the lockstep barrier can stall or desync.

Useful? React with 👍 / 👎.

Comment on lines +307 to +311
peerChannels: newPeerChannels,
remotePeerIds: newPeerIds,
// Set legacy fields to first peer for backwards compatibility
remotePeerId: state.remotePeerId || peerId,
dataChannel: state.dataChannel || dataChannel,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Accept commands from all connected peers

addPeer() still only sets the legacy remotePeerId to the first connected peer (multiplayerStore.ts 307-311), but Game.setupMultiplayerMessageHandler() rejects any command where command.playerId doesn’t match that single remotePeerId (Game.ts 170-176). In 3+ player lobbies, commands from any peer other than the first will be flagged as spoofed and dropped on every client, so those players’ actions never apply.

Useful? React with 👍 / 👎.

@braedonsaunders braedonsaunders merged commit 685098a into main Jan 31, 2026
4 checks passed
@braedonsaunders braedonsaunders deleted the claude/audit-dead-code-Kwa8p branch January 31, 2026 05:18
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.

2 participants