匹配
队列、维度、Elo 窗口、多队与 Party:匹配器每秒做一次决定,决定的是谁和谁一组,不是谁进哪个房间。
匹配器只回答一个问题:现在队列里,哪些人应该被配成一组? 它不关心房间在哪、谁去开, 那是大厅的事。配好之后把这一组交给大厅:认领预热实例,或者新拉起一个。
队列里有什么
每个排队的人一张 ticket:
PlayerId Mode Elo EnqueueTime PartyId TeamSize FullPartyTeam RecentOpponents| 入口 | 说明 |
|---|---|
ServerEnqueueMatch(Mode) | 客户端 RPC,单人入队 |
Matcher->Enqueue(PC, Mode, PartyId, EloOverride, bFullPartyTeam) | 服务端入口 |
Matcher->AutoParty(PC, PartySize, Mode) | 测试用:凑一个 N 人队 |
Matcher->CancelEnqueue(PC) / ServerCancelMatch() | 取消 |
GetQueueCount() | 当前人数 |
队列变化通过 OnQueueChanged 广播;每次入队都生成一条 trace。
维度
ICrossingMatchDimension 是扩展点:实现一个维度,注册进匹配器,它每一轮参与筛选。
Dimensions.Add(MakeShared<FMyRegionDimension>());
Dimensions.Add(MakeShared<FMyInputDeviceDimension>());维度拿到候选集合,返回它能接受的子集;多个维度按注册顺序串联。常见维度:
| 维度 | 用途 |
|---|---|
| 区域 | 同区域才配(跨区延迟) |
| 输入设备 | 手柄/键鼠分开 |
| 段位模式 | 排位与休闲分开池 |
| 预组队 | 单排与多排是否同池 |
Elo 窗口
窗口不固定,随时间线性放宽:
MatchBaseEloWindow=100.0
MatchEloGrowthPerSecond=20.0
MatchMaxWaitSeconds=180.0
MatchTickSeconds=1.0等待 0 秒窗口 ±100;等 3 秒 ±160;等到 MatchMaxWaitSeconds 还没配到,这张票判
6001 MatchTimeout 并从队列移除。
bAllowEloOverride 与 EloOverride 允许某个入口无视窗口(测试、活动局)。
模式
模式是一组容量参数:
+ModeConfigs=(Mode="1v1",TeamSize=1,TeamCount=2)
+ModeConfigs=(Mode="2v2",TeamSize=2,TeamCount=2)
+ModeConfigs=(Mode="3v3",TeamSize=3,TeamCount=2)
+ModeConfigs=(Mode="FFA4",TeamSize=1,TeamCount=4)
+ModeConfigs=(Mode="3T2",TeamSize=2,TeamCount=3)FCrossingModeConfig 默认 1v1 / TeamSize=1 / TeamCount=2。
多队匹配走 TryFormMultiTeamMatches,胜负按队伍号(EndGameWithWinner(Reason, Team))。
模式还可以带阵营定义(Factions),为空时默认「阵营 = 队伍」。
预热池
bEnableWarmPool=False
WarmPoolMode=1v1
WarmPoolSize=1
WarmPoolCooldownSeconds=15.0池里常备 Ready 空实例:匹配成立时 ClaimWarmInstance 认领,SETMATCH 写入 matchId,
等 CMD_ACK 后登记玩家。认领失败退回 SpawnInstance。
预热池是一次「把开局等待挪到配到之前」的交易:它让配到的人立刻进房,代价是空闲时也占着进程。 有 Bot 的对局不走预热池。
Party 整队
UCrossingPartySubsystem 管队伍,匹配器只看 PartyId:
| 能力 | 服务端入口 |
|---|---|
| 建队 | CreateParty(PC) |
| 加入 / 离开 | JoinParty(PC, PartyId)、LeaveParty(PlayerId, Reason) |
| 踢人 / 移交队长 | KickMember(Leader, Target)、TransferLeader(Leader, Target) |
| 模式 / 排位标记 | SetPartyMode、SetPartyRanked |
| 准备 | SetMemberReady(PlayerId, bReady) |
| 开始匹配 | StartPartyMatch(Leader) |
| 赛后返回 / 再开 | ReturnFromMatch、Rematch |
| 邀请 | InviteMember / AcceptInvite / DeclineInvite(30 秒 TTL) |
客户端对应 RPC 在 ACrossingPlayerController(ServerCreateParty … ServerPartyRematch)。
队伍 Elo 取法:
PartyMatchEloMode=Max ; Max / Average / Weighted
PartyCasualEloMode=Average
PartyMaxEloSpread=0
bFullPartyOnlyVsFullParty=FalsebFullPartyOnlyVsFullParty=True 时满编队只撞满编队(王者的做法);Max 让高段位的人拉高整队匹配池。
Bot 补位
bEnableBotFill=False
BotFillSeconds=60.0
bBotFillRequireHumanEachSide=True等太久就塞 Bot:bBotFillRequireHumanEachSide 保证两边都有真人。
Bot 也可以接管掉线玩家的座位(bBotTakeoverOnDisconnect),玩家回来时让位(BotReplaced)。
秒退惩罚
bEnableDodgePenalty=True
DodgeCooldownSeconds=60.0离队/秒退后再入队会被挡 6006 PenaltyCooldown,ApplyDodgePenalty / IsOnDodgeCooldown
是查询与施加的入口。
匹配策略
默认 FGreedyWindowPolicy,按 Elo 窗口贪心配对。策略可替换:
Matcher->Policy = MakeShared<FMyPolicy>(); // 实现 IMatchPolicy策略只决定「候选集合里选谁」,不负责拉起实例、不负责发票据。
事件
| 事件 | 时机 |
|---|---|
OnQueueChanged | 队列人数变化 |
OnMatchFound | 配到一组 |
OnMatchFailed | 匹配失败(超时/取消/无实例) |
OnReadyCheckStarted | 开始确认 |
OnAssignmentReceived | 收到分配(地址、端口、票据) |
测试钩子
-CrossingNetAutoMatch 客户端进服后自动入队
-CrossingNetAutoReady 收到 ReadyCheck 自动确认
-CrossingNetAutoEndGame=8 房间 8 秒后自动结束
-CrossingNetMatchPolicySelfTest 策略自检(重叠候选去重)下一页:身份与档案。