配對¶
participant 與 spectator 的私房 credential 都是 CSPRNG 產生的 192-bit invitation,加入只以 RFC 9807 OPAQUE 完成,不接受自訂低熵密碼。participant succession 只傳加密 OPAQUE server state,spectator succession fail closed(D-20260806-01)。
本檔角色:玩家從點「配對」到開賽倒數的完整流程。 TrueSkill 演算法見 ../算式表.md §20;房間規範見 ../賽內機制.md §1。
1. 詳細流程¶
%%{init: {"theme":"base","themeVariables":{"fontSize":"14px","primaryTextColor":"#1f2937","lineColor":"#64748b"},"flowchart":{"curve":"basis"}}}%%
flowchart TD
A(["玩家點 Quick Match/房主建房"]) --> B{"入口"}
B -->|"Quick Match"| C["讀取既有 rooms discovery<br/>公開・允許快速加入・無參賽密碼"]
C --> D["依版本・rating 窗口<br/>選擇既有 waiting 房"]
D -->|"無候選/admission 競爭失敗"| C
D -->|"逾時"| X["提示配對逾時<br/>不自動建房"]
D -->|"選中"| G["驗 expected host・建立等待房 star link"]
B -->|"房主建房"| R["房間設定<br/>可見性・Quick Match 政策・賽制"]
R --> G
G --> E["participant join-request<br/>房主原子保留席次・必要時 OPAQUE"]
G --> H["各玩家確認輪替並 Ready<br/>簽章廣播最終 carRotation"]
H --> F{"全員驗證相同 ReadySet<br/>版本・manifest・結構・起跑證明?"}
F -->|"任一不符/取消 Ready"| H
F -->|"全員通過"| K["複製 LockedStartPackage<br/>自動倒數;無開賽按鈕"]
K --> I["逐回合循環 ×MATCH_ROUND_COUNT<br/>載入・GO 屏障・競速・積分"]
I --> J["per-match 結算<br/>總名次 → 比賽結算流程"]
classDef local fill:#e8f3ec,stroke:#3f8f5f,stroke-width:1.4px,color:#173525;
classDef consensus fill:#fdf3df,stroke:#c08a2d,stroke-width:1.4px,color:#3d2c0d;
classDef chain fill:#e7eefb,stroke:#3f6bb0,stroke-width:1.4px,color:#152848;
classDef fail fill:#fae9e7,stroke:#b4544a,stroke-width:1.4px,color:#471d18;
class A,B,R local
class C,D,E,F,G,H,I,K consensus
class J chain
class X fail
步驟細目:
- 房主建房設定——明確設定 visibility 與 quickMatchEnabled;受保護角色由 UI 產生 invitation 並提供 fragment 分享連結。Quick Match 只考慮 public、quick-match-enabled、participant open 的 waiting 房。
- Quick Match discovery——讀取 rooms topic 已驗證的既有房公告;不廣播玩家配對請求,也不產生新房。公告的 player count/state/rating 中位數由房主週期更新;
signalingEndpoint提供可用 WSS 候選,gossipSignaling只宣告 scoped Gossip signaling 能力。 - 候選選擇——版本相容後套用 rating 窗口:初始 ±5,每 10 秒 +5,上限 ±30;依 rating 距離、現有人數較多、RoomId 固定排序。discovery 不承載整場
mode/rulesKey;逐回合disallowChip只從入房後的RoundConfig顯示與執行。公開廣告不含 participant roster;個人封鎖由房主 admission 拒入,或 client 接受 room-state 後顯示本機房內衝突警示(../賽內機制.md §1.7・../程式架構/matchmaking.md §3.1)。 - participant admission——加入端先從已驗簽公告/presence 找出 expected host 並建立 star link,再送 join-request。房主原子保留席次;受保護角色完成 OPAQUE 與綁 RoomId/role/epoch/雙方 PeerId 的雙向 confirmation。錯誤、逾時或斷線釋放席次。
- Ready 與集合驗證——每位 participant(含 host)選妥逐回合車輛後按 Ready,簽署房間、設定 digest、membership epoch、完整 ClientVersionInfo 與
carRotation。全員 Ready 後才形成 ReadySet;各端獨立載入實際 admitted manifests,驗簽、版本、結構、資產版本與同一 digest,再參與可驗算起跑證明。全驗證完成才複製LockedStartPackage並自動倒數;沒有「開始比賽」按鈕。 - 進入既有 room——沿用原 host、RoomId、MatchConfig 與 access policy;加入端從開始即監聽 scoped GossipSub,並依玩家順序逐一嘗試 WSS candidates,只有非本機精確 roster、已驗簽 room announcement/presence 或 signaling 入站才算找到。以首個有效路徑交換 ICE candidate(必要時走 TURN),建立等待房 star link;開賽後才建立 race mesh。
- 個人/集合失效規則——取消 Ready 後才可換車。加入或 host 移除玩家只重建集合驗證,其他人的個人 Ready 保留;場地、賽制或回合設定改變才使全員未 Ready。host Ready 時須先取消才能移除玩家。
- 逐回合循環 ×MATCH_ROUND_COUNT——等待房倒數到期後進 preloading;RaceSession 只消費 LockedStartPackage,不重讀車庫。載入該回合場地與鎖定
carRotation[i],再通過每回合 GO 前 race-ready 屏障與 3 秒 STARTUP countdown。 - 比賽結束 → per-match 結算——總名次(N 回合積分加總 → tiebreak)→ 獎金 / TrueSkill / 信譽(比賽結算流程)。
2. 配對模式¶
| 模式 | 說明 | 觸發 |
|---|---|---|
| Quick Match | 依 TrueSkill 動態窗口加入既有公開、允許快速加入且無參賽密碼的 waiting 房;逾時不建房 | 玩家點「配對」 |
| 私人房間 | 房主邀請;不套 Quick Match rating 搜尋窗口,正式結算與 TrueSkill 規則不變 | 房主建房 + 分享連結 / 邀請 |
3. TrueSkill 配對窗口¶
MATCH_RATING_WINDOW_INITIAL: 5
MATCH_RATING_WINDOW_GROWTH_PER_10SEC: 5
MATCH_RATING_WINDOW_MAX: 30
範例:等 30 秒未配到 → 窗口擴張到 ±20(5 + ⌊30/10⌋×5)。權威見 賽內機制.md §1.2 / protocol.md §6。
4. 新手保護¶
新人 σ 大、配對窗口自然較寬(見 §3),不另設新手 rating 加成。信譽下限 400(註冊 < 7 天)保護詳見 ../信譽系統.md §4.1。
5. 版本相容性¶
詳見 ../版本規範.md §5:
checkCompatibility(my, peer): boolean {
client_version.major 必須相同
protocol_version 必須相同
derive_logic_version 必須相同
builtin_assets_version 必須相同
rapier_version 必須相同 // 物理引擎版本,影響 determinism
economy_config_version 必須相同 // 即使 client 版本同,治理升級不一致仍拒
}
不符 → 提示玩家升版。
6. Signaling transport¶
配對請求本身只走 GossipSub;配對完成後的 WebRTC 握手,Gossip scope 從開始即監聽, 加入端並依設定順序嘗試 WSS candidates,跳過只含自己的空 room roster。只有已驗證的 room/peer discovery 或 signaling 入站才算找到;回覆沿最後入站 transport,冷啟動 WSS roster 不含目標時走 Gossip,跨 transport 重複訊息以 signed nonce 去除。WebRTC 建立後 立即關閉 signaling session。詳見 ../程式架構/signaling-service.md §1。
7. NAT Traversal¶
| 情境 | 處理 |
|---|---|
| 兩端皆 Open NAT | 直接 P2P |
| 一端 Symmetric NAT | TURN relay(TURN_TOKEN_TTL_SEC: 300) |
| 兩端 Symmetric NAT | 走 TURN 中繼 |
8. 房主切換規則¶
僅房間等待階段才有繼任問題(比賽中與結算階段房主皆無作用)。
| 階段 | 房主離開處理 |
|---|---|
| 房間等待 | 由進房順序的下一位玩家接任房主 |
| 比賽進行中 | 無人接任(房主在比賽中本來就無作用;計圈 / 多簽 / settlement 流程皆 P2P 平等) |
| 結算 | 無人接任(純顯示排名) |
比賽中無踢人權限(避免被當作戰術工具)。
9. 房間等待頁 UX(/room/:roomId)¶
| 模組 | 內容 |
|---|---|
| P2P 診斷 | 顯示各 peer 連線狀態(綠 / 黃 / 紅)、NAT 類型、TURN 是否啟用 |
| 資源載入 | 顯示車輛 / 場地 GLB 從 IPFS 拉取進度(含 pinning fallback 嘗試) |
| 房主切換通知 | 房主離開時 UI 即時提示「新房主:XXX」 |
| 觀戰政策 | 所有人看 allow/capacity/password 狀態;只有 host+waiting 顯示編輯器,開賽後凍結 |
| 初始/後續 roster 含封鎖對象 | 以本機封鎖交集顯示持續警示+一鍵離開(不自動退、進退自主、相同 roster 不重複提示;房主可拒其加入見 §1,../賽內機制.md §1.7) |
| 開賽前揭露提示 | 場內含廢止材質絕版品(玩家件 / 場地)→「絕版材質揭露」軟提示(../材質表.md §11.3);含降版 / schema 差異資產 → 對應提示(../版本規範.md §21)。續留房 = 默認認同該場公平(開賽前退出無懲罰) |
| Ready/倒數 | 所有人只見準備/取消準備;全 Ready 後先顯示驗證中,再顯示集中參數倒數。絕版材質提示由本機掃描實際 ReadySet manifests 產生,不把材質清單、理由或布林宣告放進共識 wire。 |
9.1 倒數中斷線¶
- participant admission 鎖定,不接受新玩家或補位。
- room link 失效必須再有 signaling presence 離開佐證;host 單方面關閉 link 不足以判定玩家斷線。
- 真正斷線者本場不重連,原起跑格留空且不重抽;剩餘者至少 2 人、並占原鎖定 roster 嚴格多數才繼續。
- 不足嚴格多數時取消本輪、移除已確認斷線者,剩餘者全部回未 Ready。
- host 斷線只有決定性繼任者能重驗同一 LockedStartPackage 時才沿用原 deadline;否則不續倒數。
10. 配對失敗 / 取消¶
| 情境 | 處理 |
|---|---|
| 配對超時(未找到可加入房) | UI 提示配對逾時;可返回 Race Config 或自行建房 |
| 玩家主動取消 | 從 matchmaking topic 退出 |
| 版本相容性檢查失敗 | 提示「升級」+ 重新進入配對 |
| ICE 握手失敗 | 自動 fallback 到下一個 signaling provider |
| active signaling session 意外關閉 | 原子停用舊 session、釋放 transport,單次重跑已設定 provider chain 並換綁同一 room presence;重連期間握手操作回 offline,離房/明示關閉不重連 |
| 載入資產失敗(IPFS unavailable) | 自動 retry + pinning fallback |
11. 跨模組對接¶
| 模組 | 內容 |
|---|---|
matchmaking/ |
TrueSkill 演算法 |
signaling-service/ |
握手 + provider fallback |
peer-discovery/ |
libp2p DHT + GossipSub |
network-sync/ |
mesh DataChannel |
key-manager/ |
PeerId + Race Sign Key |
versioning/ |
ClientVersionInfo 交換 |
ledger/ |
economy_config_version 取值 |
| IPFS / Helia | 資產載入 |