matchmaking¶
文件角色:implementation flow 投影;圖與步驟不得另建產品規則或參數 authority。
| Implementation authority | 產品 canon/流程 | 全域索引 |
|---|---|---|
| matchmaking.md | 配對 · 比賽結算 | 流程.md §2 |
配對 / 結算的技術流程圖(訊息流 / 賽後簽章 / 斷線計分 / 房主繼任)。模組實作見 matchmaking.md;配對遊戲流程(TrueSkill / 配對等待 / 房間)見 流程/配對.md。
Quick Match 既有房流程¶
sequenceDiagram
participant H as 既有房主
participant GS as Rooms GossipSub
participant Q as Quick Match 玩家
H->>GS: room-announce<br/>(public, quick enabled, waiting,<br/>無參賽密碼, rating 中位數)
GS->>Q: 已驗簽 rooms snapshot
Q->>Q: 版本・rating 窗口預篩
Q->>H: joinRoom(roomId, participant)
H->>H: 最新房態重驗<br/>active + reserved 原子保留
alt admission 成功
H-->>Q: join-verdict {accepted, roomState}
Q->>Q: 進入既有 RoomId
else 最後席次被搶或公告已過期
H-->>Q: 結構化拒絕
Q->>Q: 回 discovery 輪詢至 timeout
end
Note over H,Q: Quick Match 不建立房間、不使用 match-request/match-offer
主 peer 賽後流程¶
flowchart TD
Start([比賽結束<br/>最後一台車完賽 / 全員棄賽]) --> Collect[收齊 rounds、loadouts<br/>與 inline roundAnchors]
Collect --> Build[buildMatchResultCandidate<br/>只含 match facts<br/>含 proposerSignature 自簽]
Build --> Broadcast[經 RaceMesh ordered control<br/>廣播 match-result proposal]
Broadcast --> Timer[啟動 SETTLEMENT_TIMEOUT_SEC 計時器]
Timer --> Wait{等待回應}
Wait -->|累計簽章達 quorum| Append[appendEvent MatchResultEvent<br/>含全部 signatures]
Wait -->|剩餘可簽人數 < 需要| Cancel[廣播取消]
Wait -->|timeout 到| Fail[視為失敗]
Wait -->|收到 RejectMessage| Reject[紀錄 reason<br/>繼續等其他簽章]
Reject --> Wait
Append --> Done([結算寫入 ledger])
Cancel --> Abort([放棄結算])
Fail --> Abort
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 Done,Append local
class Build,Broadcast consensus
class Start chain
class Abort fail
proposerSignature 算 quorum 1 票,主 peer 自身也是完賽者之一。
完賽者驗算+簽章(reviewAndSignMatchResult)¶
flowchart TD
Start([收到 match-result proposal control]) --> Step1{1. 自己在 ranking?}
Step1 -->|否| R1([拒:非完賽者不可簽章])
Step1 -->|是| Step2{2. proposerSignature.signer<br/>== candidate.peerId?}
Step2 -->|否| R2([拒:signer 不一致])
Step2 -->|是| Step3{3. proposerSignature.sig<br/>驗證通過?}
Step3 -->|否| R3([拒:proposerSignature 無效])
Step3 -->|是| Step4{"4. ranking 是否等於<br/>rounds[] 重算結果?"}
Step4 -->|否| R4([拒:總名次不符])
Step4 -->|是| Step5{5. rounds/roundAnchors/loadouts<br/>與本機觀測一致?}
Step5 -->|否| R5([拒:match facts 不符])
Step5 -->|是| Step6["6. 簽 ledgerSigningDigest(ledgerAddress, candidate)<br/>覆蓋整個 MatchResultEvent"]
Step6 --> Ok([回 SignatureMessage<br/>signer, sig])
R1 --> Broadcast[廣播 RejectMessage<br/>透明審計]
R2 --> Broadcast
R3 --> Broadcast
R4 --> Broadcast
R5 --> Broadcast
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 Ok local
class Broadcast consensus
class Start chain
class R1,R2,R3,R4,R5 fail
任一驗證失敗 → 拒簽 + 廣播 RejectMessage 給所有 peer(含主 peer 與其他完賽者),達到透明審計效果。
中途斷線計分¶
flowchart TD
Race[比賽進行中] --> Voluntary{GO 後主動離場?}
Voluntary -->|是| LeaveWire[送出 leave<br/>reason voluntary]
LeaveWire --> LeaveEvent[本人單簽 RaceLeaveEvent]
LeaveEvent --> LeaveEffect[套用離場計次與信譽效果]
Voluntary -->|否| Disconnect[玩家 X 斷線]
Disconnect --> Wait[等待重連窗]
Wait --> Reconn{重連?}
Reconn -->|是| Continue[正常繼續]
Reconn -->|否| Quorum{原 active roster<br/>嚴格多數可定稿?}
Quorum -->|否| Void[partition-void<br/>不得替第三人扣分]
Quorum -->|是| MatchEffect[MatchResult disconnects<br/>套用離場效果]
LeaveEffect --> Dedup[以 matchId + peerId<br/>持久去重]
MatchEffect --> Dedup
Dedup --> Record[只累積離場效果與計次]
Record --> Later[下次合法 MatchResult<br/>更新 rating 時]
Later --> Threshold{累積次數達門檻?}
Threshold -->|是| AdjustSigma[套用 σ 下限]
Threshold -->|否| Normal[正常 TrueSkill 更新]
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 AdjustSigma consensus
class LeaveEffect chain
class Void fail
RaceLeaveEvent 只立即形成本人離場成本,不產生排名、TrueSkill、經濟或完賽效果,也不縮小 MatchResult quorum;正式 MatchResult 的其餘效果仍依原 active roster 的合法定稿正常套用。
房主繼任¶
flowchart TD
Detect[偵測房主離線] --> State{房間狀態?}
State -->|Waiting| Next[由進房順序下一位接任]
State -->|Preloading/Racing/Settling| NoOp[無作用<br/>不需繼任]
Next --> Update[Update room.hostPeerId]
Update --> Notify[廣播給房間成員]
NoOp --> Continue[比賽繼續]
classDef local fill:#e8f3ec,stroke:#3f8f5f,stroke-width:1.4px,color:#173525;
classDef chain fill:#e7eefb,stroke:#3f6bb0,stroke-width:1.4px,color:#152848;
class Update local
class NoOp chain