Skip to Content
CrossingNet
大厅与实例

房间与结算

房间进程里发生的事:票据换座位、准备与开局、结束与结算、掉线与重连,以及投票、系列赛、观战和迟到。

房间进程只跑一局。它由大厅拉起、端口由大厅分配、票据由大厅签发;自己不做匹配、不写档案, 只把这一局的座位、过程与结果管好。

票据换座位

客户端旅行进房间时带着 JoinToken,房间用同一份 JoinTokenSecret 校验:

<instance>.<player>.<role>.<team>.<expiry>.<sig>
角色房间怎么对待
Player找空座位坐下,队伍按票据里的 team
LateJoinPlayer中途加入:按人数找有位的队伍(bAllowLateJoin)
Spectator不占座位,进观战列表(bAllowSpectators)
ReconnectPlayer按 player 找回原座位;找不到座位才算新进

票据过期(JoinTokenTtlSeconds,默认 300 秒)或签名不符 → 4002 BadToken。 票据由客户端在旅行时提交(ServerSubmitJoinToken),房间接受后回 ClientJoinTokenAccepted。

座位与准备

Login 校验 → SeatAssigned → Roster → ReadyChanged → GameStart
  • SetPlayerReady(PS, bReady):准备状态复制给所有人
  • 大厅在分配后推 ClientStartReadyCheck;bAutoAcceptReadyCheck 为真时客户端自动确认
  • ReadyCheckSeconds(默认 12 秒)内没人确认 → 6007 ReadyTimeout,这一组解散回队列

容量相关查询:

int32 Max      = Room->GetMaxPlayers();
int32 Teams    = Room->GetTeamCount();
int32 Seated   = Room->GetSeatedCount();
int32 Watching = Room->GetSpectatorCount();

结束一局

三种结束方式,区别在带不带结果:

Room->EndGame(TEXT("Aborted"));                                    // 中止,不算结果
Room->EndGameWithResult(TEXT("Completed"), ECrossingMatchResult::TeamAWin);
Room->EndGameWithWinner(TEXT("Completed"), /*Team=*/0);            // 多队模式

结束前可以把每人的数据带上:

Room->ReportPlayerStats(PlayerId, Stats);        // kills/deaths/assists/score/placement
Room->ReportPlayerOutcome(PlayerId, Outcome);    // 项目自定义个人结果
Room->MarkPlayerForfeit(PlayerId);               // 掉线判负
Room->PlayerConcede(PS);                         // 个人投降

ECrossingMatchResult:TeamAWin / TeamBWin / TeamWin(多队,胜队见 WinnerTeam)/ Draw / Remake / Aborted。

结算怎么保证不丢

EndGame → 结算 Elo / 档案 → RESULT(含 matchId)
        → 后台线程发送 → 大厅落盘 SettlementJournal 并回 ACK
        → 房间收到 ACK 停止重试(最多 3 次)
        → 大厅重启后从 Settlements.log 恢复,按 matchId 幂等
行为日志
发出结果[Room] event=SettlementPush
收到 ACK[Room] event=SettlementAcked
ACK 超时[Room] event=SettlementAckTimeout
大厅侧落盘[Session] event=SettlementRecorded
重复结算[Session] event=SettlementDuplicate
落盘失败[Session] event=SettlementPersistFailed
房间关了没结算[Session] event=SettlementMissing(只报告)

ACK 是乐观 ACK:大厅先回 ACK 再异步落盘,所以极端情况下「ACK 已回但进程崩」仍可能丢一局, SettlementMissing 会把这种情况记下来,供人工补。

掉线与重连

玩家掉线 → 房间保留座位 + 推 DISCONNECT(带 expires)到大厅
         → 大厅登记重连表
客户端回来 → 大厅 ConsumeReconnect → 签发 role=ReconnectPlayer 的票据
         → 分配回原实例 → 旅行 → 房间 TryReclaimSeat
配置默认作用
ReconnectWindowSeconds120.0座位保留多久
bBotTakeoverOnDisconnectfalse掉线时 Bot 顶替,回来让位

窗口之外回来按新进处理;这局的对局结果里这个人是 Forfeit 还是 NoContest 由房间规则决定。

团队投降

Room->RequestSurrender(TeamId);   // 发起
Room->VoteSurrender(PlayerId, bYes); // 表决
bool bSafe = Room->IsSafeToLeave();
bEnableSurrenderVote=True
SurrenderVoteMinSeconds=900.0     ; 开局多少秒后才允许发起
SurrenderVoteYesRatio=0.7         ; 通过比例

日志:SurrenderVoteStarted → SurrenderVote → SurrenderPassed / SurrenderRejected。

Remake、安全离开、AFK

机制配置日志
开局减员重开bEnableRemake、RemakeWindowSeconds(180)RemakeTriggered
可安全离开bSafeToLeaveOnAbandon、IsSafeToLeave()SafeToLeave
AFK 检测bEnableAfkDetection、AfkTimeoutSeconds(120)AfkDetectionArmed / PlayerAfk

客户端用 ServerReportActivity 上报活动(输入、操作时调用)。

系列赛

Room->StartSeries(ECrossingSeriesFormat::BestOf, 3);
Room->EndRound(WinnerTeam);
int32 Wins = Room->GetTeamWins(0);
格式说明
Auto按配置推断
BestOfBO3/BO5,先到 WinsNeeded
PointsRace积分赛,目标分
RoundRobin循环赛
SingleElim单败淘汰

相关配置在「07 赛季」与「05 对局规则」两类里。日志:SeriesArmed → RoundEnded → RoundAdvanced → SeriesFinished。

观战与迟到

能力配置入口
观战bAllowSpectators、MaxSpectators客户端 ServerRequestSpectate
中途加入bAllowLateJoin、bLateJoinRated、bLateJoinReplaceBots客户端 ServerRequestLateJoin

观战只做座位隔离,相机与输入由项目实现;迟到按人数找位,不按 Elo。

健康与自退

房间在 GetHealthPort() 上监听,回 OK;<players>;<state>;<uptime>。 大厅超过 LobbyLostTimeoutSeconds 不在,房间自退(LobbyLostArmed → LobbyLost), 不让实例变成孤儿。

上一页:大厅与实例 · 下一页:协议。

On this page