Skip to content

feat: migrate multiplayer to PeerJS P2P and add 3-4 player support#10

Draft
schaoss wants to merge 30 commits intomainfrom
feat/p2p-multiplayer
Draft

feat: migrate multiplayer to PeerJS P2P and add 3-4 player support#10
schaoss wants to merge 30 commits intomainfrom
feat/p2p-multiplayer

Conversation

@schaoss
Copy link
Owner

@schaoss schaoss commented Jan 20, 2026

Changes in this PR (automated update)\n\n- Fix: module alias resolution in tests (tsconfig/vite/vitest aligned)\n- Fix: store.applyActionSequence actor detection and atomic application\n- Fix: TurnManager now ignores late AI replies using requestId and cancels agents on timeout\n- Fix: Agents (RandomAgent, MinimaxAgent) clean worker handlers on resolution/rejection to avoid late handlers\n- Style: ran eslint --fix against UI/test files to satisfy pre-commit hooks\n\nCI summary:\n- bun run build: passed\n- bun test: 66 tests passed, 0 failed\n\nNotes:\n- No new dependencies added.\n- Agent.cancel() must be respected by any new agent implementations to avoid late replies.

@gemini-code-assist
Copy link

Summary of Changes

Hello @schaoss, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant architectural shift for the game's multiplayer functionality, transitioning from a centralized server approach to a peer-to-peer model. This change not only enhances the robustness and directness of online interactions but also expands the game's capacity to include 3 and 4 players. The underlying state management and user interface components have been thoroughly revised to support these new capabilities, removing obsolete server-side elements in the process.

Highlights

  • Multiplayer Architecture Overhaul: The multiplayer system has been completely refactored from a Socket.io server-client model to a PeerJS-based Peer-to-Peer (P2P) architecture, enabling direct client communication.
  • Expanded Player Support: Online multiplayer now supports 3-player and 4-player game modes, alongside the existing 2-player option.
  • Multiplayer State Management: The multiplayerStore has been updated to handle host/guest logic, room creation with deterministic IDs, and state synchronization across connected peers.
  • Dynamic Player Count Selection: A player count selector has been added to the MultiplayerMenu to allow hosts to choose between 2, 3, or 4 players for their online rooms.
  • Dependency Streamlining: The server/ directory and socket.io-client dependency have been removed, reflecting the shift to a client-side P2P model.
  • AI Compatibility for New Player Counts: Type errors in MinimaxAI related to 3 and 4 player support have been addressed, ensuring the AI functions correctly in expanded game modes.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request is a major architectural change, migrating the multiplayer functionality from a server-based Socket.io implementation to a client-side P2P model using PeerJS. It also successfully introduces support for 3 and 4 player games. The changes are extensive, touching everything from the core game state management in Zustand to the UI components and game logic utilities. The addition of a dedicated multiplayerStore is a clean way to encapsulate the P2P logic. I've identified one high-severity bug in the move calculation that should be addressed.

const newSteps = stepsTaken + dist
const newSteps = stepsTaken + dist // Approximation. `pathResult.path.length - 1` is better.
// Use path length if available
const actualSteps = pathResult ? pathResult.path.length : newSteps

Choose a reason for hiding this comment

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

high

There's a small but important bug here in calculating the number of steps taken. pathResult.path.length includes the starting node, so the number of steps is actually path.length - 1. Using path.length will incorrectly calculate one extra step, which will affect the calculation for any subsequent moves within the same turn (e.g., it will prevent a second step when it should be allowed).

For example, a path from A -> B has a length of 2, but represents 1 step.

Suggested change
const actualSteps = pathResult ? pathResult.path.length : newSteps
const actualSteps = pathResult ? pathResult.path.length - 1 : newSteps

gary.chu and others added 14 commits January 21, 2026 12:06
- Rewrite MinimaxAI evaluation to support 3/4 player modes:
  - evaluateZOCDistance() now calculates for all players dynamically
  - evaluateTerritoryPotential() compares current player vs all opponents
  - actionHeuristic() considers all opponents
  - Zobrist hashing supports Y and G player stones
  - Move ordering added at all minimax levels

- Improve PeerJS connection reliability:
  - Add 8 STUN servers for better NAT traversal
  - Add retry mechanism with exponential backoff (3 retries)
  - Increase join timeout to 30 seconds
  - Add connection status tracking

- Improve multiplayer error handling:
  - Add ERROR_MESSAGES with i18n keys and suggestions
  - Add new error types: PEER_UNAVAILABLE, NETWORK_ERROR, TIMEOUT
  - Update all 6 locale files with descriptive error messages

- Add comprehensive test coverage:
  - minimax-ai.multiplayer.test.ts (8 tests)
  - multiplayerStore.error.test.ts (8 tests)
  - multiplayerStore.ice.test.ts (5 tests)
  - ai.action.test.ts (8 tests)
  - ai.multiplayer.test.ts (8 tests)

All 65 tests passing, build successful.
fix(store): applyActionSequence actor detection & test cleanup
Add unit tests verifying TurnManager correctly handles late AI replies:
- turnmanager.race.test.ts: Tests delayed agent responses are ignored after timeout
- turnmanager.worker.test.ts: Tests worker simulation with FakeWorker for timing scenarios

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
gary.chu and others added 2 commits January 22, 2026 10:36
Verifies MinimaxAI.getBestMove correctly selects from getLegalActions and handles claimed territory filtering.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…ate AI replies

Prevents race condition where delayed AI worker responses could be applied after timeout:

- TurnManager: Pass requestId to agent.getAction(); verify returned requestId matches
- AIWorker: Include requestId in postMessage response
- PlayerAgent: Extend interface to accept optional requestId parameter
- RandomAgent/MinimaxAgent: Add cancel flag, ignore late messages, implement cancel()
- HumanAgent: Conform to updated PlayerAgent interface

This ensures late AI replies (arriving after timeout/cancellation) are discarded.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
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