Skip to content

Use native engine for hosted P2P games - #6515

Merged
matthewevans merged 3 commits into
mainfrom
ship/native-p2p-engine
Jul 22, 2026
Merged

Use native engine for hosted P2P games#6515
matthewevans merged 3 commits into
mainfrom
ship/native-p2p-engine

Conversation

@matthewevans

@matthewevans matthewevans commented Jul 22, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features
    • Native engine support now extends to locally hosted multiplayer games, including native pregame transport and automatic fallback.
    • Improved session resume/reconnect flows for hosts and guests.
    • Hosts can permanently abandon active games and fully clean up session state.
    • State update snapshots now carry consistent revisioning across players and spectators.
  • Bug Fixes
    • Improved reconciliation of pregame seat status when guests are rejected or disconnect before game start.
  • Localization
    • Added the “Command Zone” setting label and refreshed native-engine descriptions across supported languages.

@matthewevans
matthewevans enabled auto-merge July 22, 2026 20:51
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This change adds native P2P pregame transport and optional native host authority, introduces revisioned state protocol messages and host abandonment, updates persistence and resume flows, and revises gameplay settings translations.

Changes

Native P2P protocol and hosting

Layer / File(s) Summary
Revisioned protocol and session state
crates/server-core/..., crates/lobby-broker/..., fixtures/adapter-contract/*, scripts/check-protocol-version.mjs
Protocol version 21, monotonic state revisions, persisted revision state, and updated wire fixtures and tests are added.
Phase-server revisions and abandonment
crates/phase-server/src/main.rs, crates/server-core/src/client_message_wire_guard.rs
State revisions are propagated through game, action, AI, reconnect, waiting, and takeback updates; hosts can abandon games with cleanup and acknowledgement.
Native pregame WebSocket transport
client/src/adapter/ws-adapter.ts, client/src/adapter/__tests__/ws-adapter.test.ts
Native attachment, reconnect, seat mutation, slot synchronization, game start, abandonment, revision handling, teardown, and corresponding tests are added.
Native host authority and resume
client/src/adapter/p2p-adapter.ts, client/src/providers/GameProvider.tsx, client/src/stores/*, client/src/services/gamePersistence.ts
P2P hosting can delegate actions, snapshots, persistence, reconnects, and revisions to NativeP2PBridge, with native resume metadata and WASM fallback handling.
Native engine settings text
client/src/i18n/locales/*/settings.json, client/src/components/settings/*
Gameplay settings add the Command Zone label, updated native-engine descriptions, localized Italian priority-window text, and related UI styling and coverage.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Host
  participant P2PHostAdapter
  participant NativeP2PBridge
  participant phase-server
  Host->>P2PHostAdapter: Start P2P hosting
  P2PHostAdapter->>NativeP2PBridge: Initialize native authority
  NativeP2PBridge->>phase-server: Attach loopback seat sockets
  phase-server-->>NativeP2PBridge: SessionAttached and slot updates
  P2PHostAdapter->>NativeP2PBridge: Start game or submit action
  NativeP2PBridge->>phase-server: Forward native command
  phase-server-->>NativeP2PBridge: Revisioned state update
  NativeP2PBridge-->>P2PHostAdapter: Fan out authoritative state
Loading

Suggested labels: feature

Suggested reviewers: parthmishra

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: enabling the native engine for hosted P2P games.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ship/native-p2p-engine

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
client/src/i18n/locales/de/settings.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

client/src/i18n/locales/es/settings.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

client/src/i18n/locales/fr/settings.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

  • 3 others

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
client/src/adapter/ws-adapter.ts (1)

1329-1342: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Reject initialization on Error messages. This branch leaves pregameReject and gameStartedReject pending on native pregame/reconnect flows; call rejectInitialization(...) here so all lifecycle waiters settle on a server Error.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/src/adapter/ws-adapter.ts` around lines 1329 - 1342, Update the
"Error" message case to call rejectInitialization(...) with the server error
details, ensuring pending pregame and game-start/reconnect lifecycle waiters
settle on native server errors. Keep the existing mutation, abandon, event
emission, and deck-rejection handling unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@client/src/i18n/locales/de/settings.json`:
- Around line 27-28: Translate both skipLowUsePriorityWindows and
skipLowUsePriorityWindowsDescription in client/src/i18n/locales/de/settings.json
lines 27-28 into German, client/src/i18n/locales/es/settings.json lines 27-28
into Spanish, client/src/i18n/locales/fr/settings.json lines 27-28 into French,
client/src/i18n/locales/it/settings.json lines 27-28 into Italian,
client/src/i18n/locales/pl/settings.json lines 27-28 into Polish, and
client/src/i18n/locales/pt/settings.json lines 27-28 into Portuguese, preserving
the existing keys and meaning.

In `@client/src/providers/GameProvider.tsx`:
- Around line 820-840: Gate the native engine setup around ensureNativeEngine
and nativeP2P assignment so it does not run for an isWasmResume, even when
shouldUseNativeP2P is true. Preserve native setup for native resumes and
non-resume sessions, allowing WASM resumes to continue with the persisted WASM
snapshot and non-native adapter.

In `@client/src/stores/multiplayerStore.ts`:
- Around line 1034-1050: Add an attempt-generation or abort mechanism to the
hosting flow around startP2PHostingSession, invalidating the current attempt in
cancelHosting and whenever a newer hosting attempt replaces it. After every
await, including ensureNativeEngine and room initialization, verify the attempt
is still current before creating rooms or publishing state such as
hostingStatus: "waiting"; stale attempts must exit without side effects.

In `@crates/lobby-broker/src/protocol.rs`:
- Around line 374-375: Update the `MIN_SUPPORTED_PROTOCOL` assertion in the
protocol version test to expect 20, matching
`PROTOCOL_VERSION.saturating_sub(1)` when `PROTOCOL_VERSION` is 21; leave the
`PROTOCOL_VERSION` assertion unchanged.

---

Outside diff comments:
In `@client/src/adapter/ws-adapter.ts`:
- Around line 1329-1342: Update the "Error" message case to call
rejectInitialization(...) with the server error details, ensuring pending
pregame and game-start/reconnect lifecycle waiters settle on native server
errors. Keep the existing mutation, abandon, event emission, and deck-rejection
handling unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 305a5079-4d5a-4aef-b694-8be89b6833c0

📥 Commits

Reviewing files that changed from the base of the PR and between 4074fcf and de8934d.

📒 Files selected for processing (24)
  • client/src/adapter/__tests__/ws-adapter.test.ts
  • client/src/adapter/p2p-adapter.ts
  • client/src/adapter/ws-adapter.ts
  • client/src/components/settings/__tests__/PreferencesModal.priorityPassing.test.tsx
  • client/src/i18n/locales/de/settings.json
  • client/src/i18n/locales/en/settings.json
  • client/src/i18n/locales/es/settings.json
  • client/src/i18n/locales/fr/settings.json
  • client/src/i18n/locales/it/settings.json
  • client/src/i18n/locales/pl/settings.json
  • client/src/i18n/locales/pt/settings.json
  • client/src/providers/GameProvider.tsx
  • client/src/services/gamePersistence.ts
  • client/src/stores/multiplayerStore.ts
  • client/src/stores/preferencesStore.ts
  • crates/lobby-broker/src/protocol.rs
  • crates/phase-server/src/main.rs
  • crates/server-core/src/client_message_wire_guard.rs
  • crates/server-core/src/persist.rs
  • crates/server-core/src/protocol.rs
  • crates/server-core/src/session.rs
  • fixtures/adapter-contract/game_started.json
  • fixtures/adapter-contract/state_update.json
  • scripts/check-protocol-version.mjs

Comment thread client/src/i18n/locales/de/settings.json Outdated
Comment thread client/src/providers/GameProvider.tsx
Comment thread client/src/stores/multiplayerStore.ts
Comment thread crates/lobby-broker/src/protocol.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@client/src/components/settings/PreferencesModal.tsx`:
- Line 1240: Update the range input’s styling near the existing h-2 class to
provide at least a 44pt hit area, using a minimum height such as min-h-11 while
preserving the thin, visually centered slider track through appropriate track
styling.

In `@client/src/stores/multiplayerStore.ts`:
- Around line 992-993: Increment p2pHostingAttempt at the beginning of
startHosting, before any resource cleanup or awaited server-hosting operations,
so pending P2P setup callbacks fail their isCurrentAttempt check and cannot
overwrite server-host state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d39c1a69-65b1-4059-a859-ca39ee236426

📥 Commits

Reviewing files that changed from the base of the PR and between de8934d and c87dc7e.

📒 Files selected for processing (14)
  • client/src/adapter/__tests__/ws-adapter.test.ts
  • client/src/adapter/ws-adapter.ts
  • client/src/components/menu/MenuActionTile.tsx
  • client/src/components/settings/PreferencesModal.tsx
  • client/src/i18n/locales/de/settings.json
  • client/src/i18n/locales/es/settings.json
  • client/src/i18n/locales/fr/settings.json
  • client/src/i18n/locales/it/settings.json
  • client/src/i18n/locales/pl/settings.json
  • client/src/i18n/locales/pt/settings.json
  • client/src/providers/GameProvider.tsx
  • client/src/stores/multiplayerStore.ts
  • crates/lobby-broker/src/protocol.rs
  • crates/server-core/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (9)
  • client/src/i18n/locales/de/settings.json
  • crates/lobby-broker/src/protocol.rs
  • client/src/i18n/locales/es/settings.json
  • client/src/i18n/locales/pl/settings.json
  • client/src/adapter/tests/ws-adapter.test.ts
  • client/src/i18n/locales/pt/settings.json
  • client/src/i18n/locales/it/settings.json
  • client/src/providers/GameProvider.tsx
  • client/src/adapter/ws-adapter.ts

onDoubleClick={() => onChange(defaultValue)}
aria-label={label}
className="flex-1 accent-cyan-500"
className="h-2 flex-1 cursor-pointer rounded-full bg-slate-700 accent-cyan-500 focus-visible:ring-2 focus-visible:ring-cyan-400/70 focus-visible:outline-none"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve a 44pt touch target for the slider.

h-2 makes the range input itself roughly 8px tall, so the control falls well below the required 44pt touch target. Keep the visual track thin while giving the input a larger hit area, for example with min-h-11 and centered track styling.

Proposed fix
-          className="h-2 flex-1 cursor-pointer rounded-full bg-slate-700 accent-cyan-500 focus-visible:ring-2 focus-visible:ring-cyan-400/70 focus-visible:outline-none"
+          className="min-h-11 flex-1 cursor-pointer rounded-full bg-slate-700 accent-cyan-500 focus-visible:ring-2 focus-visible:ring-cyan-400/70 focus-visible:outline-none"

As per path instructions, touch targets must be at least 44pt.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
className="h-2 flex-1 cursor-pointer rounded-full bg-slate-700 accent-cyan-500 focus-visible:ring-2 focus-visible:ring-cyan-400/70 focus-visible:outline-none"
className="min-h-11 flex-1 cursor-pointer rounded-full bg-slate-700 accent-cyan-500 focus-visible:ring-2 focus-visible:ring-cyan-400/70 focus-visible:outline-none"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/src/components/settings/PreferencesModal.tsx` at line 1240, Update the
range input’s styling near the existing h-2 class to provide at least a 44pt hit
area, using a minimum height such as min-h-11 while preserving the thin,
visually centered slider track through appropriate track styling.

Source: Path instructions

Comment on lines +992 to +993
const attempt = ++p2pHostingAttempt;
const isCurrentAttempt = () => p2pHostingAttempt === attempt;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Invalidate P2P setup when switching to server hosting.

Lines 992-993 only invalidate prior P2P attempts for cancellation or another P2P start. startHosting disposes current resources but does not increment p2pHostingAttempt; a pending P2P setup can therefore resume after ensureNativeEngine, hostRoom, or broker registration and overwrite the new server-host state with hostingStatus: "waiting". Increment the attempt counter before startHosting begins cleanup.

As per path instructions, async races must be checked in this hosting flow.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/src/stores/multiplayerStore.ts` around lines 992 - 993, Increment
p2pHostingAttempt at the beginning of startHosting, before any resource cleanup
or awaited server-hosting operations, so pending P2P setup callbacks fail their
isCurrentAttempt check and cannot overwrite server-host state.

Source: Path instructions

@matthewevans
matthewevans added this pull request to the merge queue Jul 22, 2026
Merged via the queue into main with commit 85d0c23 Jul 22, 2026
15 checks passed
@matthewevans
matthewevans deleted the ship/native-p2p-engine branch July 22, 2026 22:32
jsdevninja pushed a commit to jsdevninja/phase that referenced this pull request Jul 24, 2026
* Use native engine for hosted P2P games

* Fix native P2P review findings

* Show pacing slider tracks

---------

Co-authored-by: matthewevans <matthewevans@users.noreply.github.com>
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