学习路径
按顺序走完九章:从装进项目、看懂设置,到在大厅、房间、匹配、局域网和封禁之间独立排查问题。每章有一个可执行的案例和一条完成判据。
这一页是走法,不是参考。按下面的顺序做,每章产出一个能看见的东西;九章走完, 你可以独立起一套大厅 + 房间、跑通一次匹配、用局域网开一局、并在出问题时知道先看哪条日志。
学完能得到什么(九项能力,覆盖矩阵在页末):
- 把 CrossingNet 放进项目并让它编译通过
- 看懂并配好插件设置里拉起房间必须的那几项(
RoomMapPackage等) - 起一个大厅进程,读得懂
CrossingNet.Status - 手工拉起一个房间,认出
Spawning → Ready - 让客户端带着票据进房,看到座位分配
- 结束一局并确认结算被 ACK
- 跑通一次自动匹配
- 在同一个网段开房并被发现
- 用日志、命令和设备注册表排查一局为什么没成
不教什么:玩法规则、UI、账号与登录系统、打包发布流程、性能调优。这些要么在别处,要么还没有。
路径总表
| # | 章节 | 前置 | 你会做出什么 | 完成判据 | 实测案例 | 预计耗时 |
|---|---|---|---|---|---|---|
| 1 | 装进项目 | 无 | 能编译的工程 | 编辑器 Plugins 里 CrossingNet 已启用,无编译错误 | 案例 1-A | 10 min |
| 2 | 认识设置 | 第 1 章 | 一份不会被拉起报错的配置 | DefaultGame.ini 里 ServerExePath(服务器可执行文件) / ServerArgsPrefix(服务器前置参数) / RoomMapPackage(房间地图) / LobbyControlAddress(大厅控制地址) 四项非空 | 案例 2-A | 10 min |
| 3 | 起大厅 | 第 2 章 | 一个跑着的大厅进程 | CrossingNet.Status 返回实例表(可以为空) | 案例 3-A | 15 min |
| 4 | 拉起房间 | 第 3 章 | 一个 Ready 的实例 | 大厅日志出现 HealthFirstOK port=... | 案例 4-A | 10 min |
| 5 | 客户端进房 | 第 4 章 | 一个坐在房间里的玩家 | 房间日志出现 SeatAssigned | 案例 5-A | 15 min |
| 6 | 结束与结算 | 第 5 章 | 一局结算记录 | 大厅日志出现 SettlementRecorded 与 SettlementAcked | 案例 6-A | 10 min |
| 7 | 自动匹配 | 第 6 章 | 两个客户端被配到同一局 | 大厅日志出现 MatchFound | 案例 7-A | 20 min |
| 8 | 局域网开房 | 第 2 章(不需要大厅) | 另一台机器在列表里看见房间 | CrossingNet.LANList 后日志出现 [LAN] rooms=1 | 案例 8-A | 20 min |
| 9 | 运维与封禁 | 第 6 章 | 一条封禁记录与一条可检索的日志 | CrossingNet.DeviceList banned 输出里有该设备 | 案例 9-A | 15 min |
⚠️ 案例状态:全部
未验证。 这些命令与字段来自插件源码与README.md,但没有在本机实跑过 (插件由作者自行编译,本轮未编译)。每条案例都写明了"要验证它需要什么"。按WRT-LP-S06, 不标实测的案例不得被引用成"已验证"。
前置与环境
| 项 | 要求 |
|---|---|
| 版本 | Unreal Engine 5.8.2(源码版);CrossingNet 0.1.0 |
| 平台 | Windows x64(其余平台未验证) |
| 依赖 | 无外部依赖;工程需要已经能正常编译和启动 |
| 起点目录 | 一个能打开编辑器的 UE 工程。下文用 <Project> 指工程名、<Project目录> 指工程所在目录、<UE> 指引擎根目录(那一层里直接能看到 Engine 文件夹) |
本页命令分两种:标
powershell的在 Windows 终端(PowerShell/CMD)里执行;标text的是 UE 控制台,只有存在游戏视口时按~才能打开——PIE 的 Listen Server 游戏窗口可以,-server进程没有视口,按不出来。两者不能互换。还有一件事:
CrossingNet.*命令只写日志,不会在输入行下面回显。执行完去编辑器底部的 Output Log(或-log窗口、Saved/Logs/)里找[Status]、[Session]开头的行。
案例 1-A · 装进项目
本章产出:编辑器插件列表里出现 CrossingNet,且工程能编译通过。
<Project>/Plugins/CrossingNet/ ← 整个插件目录放这里
CrossingNet.uplugin
Source/
Config/Presets/打开工程 → Edit ▸ Plugins → 搜索 CrossingNet → 勾选 → 重启编辑器;确认没有编译错误。
插件目录里有什么:
| 路径 | 内容 |
|---|---|
Source/CrossingNet/ | 运行时模块:身份、大厅、房间、匹配、档案、事件、网络、局域网、设备 |
Source/CrossingNetEditor/ | 编辑器模块:设置面板与编辑器工具 |
Config/Presets/ | 6 份设置预设(LoL / 王者 / 守望 / 三角洲 / 四队积分 / 1v1 BO3) |
README.md | 功能矩阵、接口表、日志与错误码速查 |
为什么这样工作:插件按 .uplugin 描述文件加载两个模块(CrossingNet、CrossingNetEditor),
目录名与插件名一致最省事。
常见失败
| 症状 | 原因 | 修 |
|---|---|---|
| 插件列表里没有 CrossingNet | 放错了层级(例如 Plugins/Plugins/...) | 确保 Plugins/CrossingNet/CrossingNet.uplugin 存在 |
| 编译报缺少模块 | 项目模块没依赖 CrossingNet | 在项目 Build.cs 的 PublicDependencyModuleNames 加 "CrossingNet" |
自测:把插件目录改名再改回来,编辑器是否仍能识别?(考的是插件名由 .uplugin 决定,不是目录名)
下一章用它:设置项就长在这个插件上,先认清它再来配。
案例 2-A · 认识设置
本章产出:一份不会被拉起报错的配置。
前置检查:第 1 章的插件已经启用、能编译。
在哪看:编辑器 Project Settings ▸ Plugins ▸ CrossingNet(面板标题是 CrossingNet 联机设置;所有项都在 Config/DefaultGame.ini 的
[/Script/CrossingNet.CrossingNetSettings] 段里)。设置分成 13 类:
01 模式与基础 02 服务器与房间 03 匹配与队列 04 身份与令牌
05 对局规则 06 结算与段位 07 赛季 08 组队
09 观战与迟到 10 存档与身份 11 运维与指标 12 网络与控制
13 局域网开房第一次只需要看懂四类里的五项——其余都可以先留默认值:
| 项 | 类别 | 填什么 | 空着会怎样 |
|---|---|---|---|
ServerExePath(服务器可执行文件) | 02 服务器与房间 | 拉起房间进程的可执行文件。开发期指向引擎的 UnrealEditor.exe;生产指向打包的 Server.exe | DebugAssign/匹配都会拉不起实例 |
ServerArgsPrefix(服务器前置参数) | 02 服务器与房间 | 跟在可执行文件后的整行参数,含 <Project>.uproject -server -game | 房间进程起不来,实例卡在 Spawning |
RoomMapPackage(房间地图) | 02 服务器与房间 | 房间进程加载的地图,常用 /Engine/Maps/Entry;自己的图写 /Game/... | DebugAssign 直接报 RoomMapPackage 未配置 |
LobbyControlAddress(大厅控制地址) + LobbyControlPort(大厅控制端口) | 12 网络与控制 | 大厅控制通道地址,例如 127.0.0.1:57300 | 房间回传不了状态与结算 |
JoinTokenSecret(令牌密钥) | 04 身份与令牌 | 票据签名密钥,开发用默认、生产必须换 | 客户端进房被拒(BadToken) |
写进 Config/DefaultGame.ini 的样子:
[/Script/CrossingNet.CrossingNetSettings]
; 服务器可执行文件
ServerExePath=<UE>/Engine/Binaries/Win64/UnrealEditor.exe
; 服务器前置参数
ServerArgsPrefix="<Project目录>/<Project>.uproject -server -game -unattended -nullrhi"
; 房间地图
RoomMapPackage=/Engine/Maps/Entry
; 大厅控制地址
LobbyControlAddress=127.0.0.1:57300
<UE>是引擎根目录(里面能看到Engine文件夹),<Project目录>是工程所在目录; 别漏<UE>\Engine那一层。
输出在哪:改完启动一次大厅,日志里会有配置摘要:
[Config] event=Summary mode=1v1 warmPool=false maxInstances=8如果某项空着,第一次用到它的命令会报错,例如:
[Session] event=DebugAssignFailed mode=1v1 error=RoomMapPackage 未配置(Project Settings -> CrossingNet)为什么这样工作:大厅要靠这几项拉起房间进程并把地址发回客户端;它们不是可选项,只是有默认值的项
(RoomMapPackage 没有默认值,所以必须手填)。
常见失败
| 症状 | 原因 | 修 |
|---|---|---|
DebugAssign 报 RoomMapPackage 未配置 | 这一项是空的 | 填 /Engine/Maps/Entry 或 /Game/...,重启大厅 |
实例卡在 Spawning 后超时 | ServerExePath(服务器可执行文件) / ServerArgsPrefix(服务器前置参数) 不对 | 手动在终端执行这两项拼出来的命令,看进程为什么退出 |
客户端 BadToken | 大厅与房间的 JoinTokenSecret(令牌密钥) 不一致 | 两边读同一份 ini,改完重启 |
自测:把 RoomMapPackage 清空再 DebugAssign,日志里报的是什么错?恢复后再试一次。
下一章用它:设置对了,大厅才拉得起房间。
案例 3-A · 起大厅
本章产出:一个能接收控制台命令、并且看得到实例表的大厅。
前置检查:第 2 章的五项配置非空。
⚠️ 先说清楚
~这件事:~打开的是视口控制台,只有存在游戏视口时才有。 用-server启动的是无窗口的权威进程,它没有视口,所以没有~,也敲不进任何命令。 想在控制台里敲CrossingNet.Status,要么用下面方式 A(有视口),要么用方式 B(启动时一次性执行)。
方式 A(推荐,能交互):在编辑器里跑 Listen Server
插件判断「是不是服务端」用的是 World->GetNetMode() != NM_Client,所以 Listen Server 也会被当成服务端,
大厅逻辑照常跑。这条路径尚未实跑验证,但它是目前唯一能一边跑一边敲命令的方式。
- 用编辑器打开你的地图(大厅用什么图都可以,
/Engine/Maps/Entry也行) - 编辑器工具栏 Play 按钮右边的小三角 → Net Mode 选 Play As Listen Server
- 点 Play,游戏窗口出现后点一下窗口
- 按
~,打开控制台,输入:
CrossingNet.Status输出在哪:不会在输入行下面回显——输出是日志行,去编辑器底部的 Output Log(输出日志) 里看。预期多出:
[Status] event=Snapshot netmode=2 instances=0 queue=0每有一个实例,还会多一行:
[Status] event=Instance id=A1B2C3 state=Ready reason=None pid=1234 game=57000 health=58100 players=0+0/2 mode=1v1 age=3s winner=0 rated=0netmode 取值:0=Standalone、1=DedicatedServer、2=ListenServer、3=Client。
方式 A 下应该是 2;instances=0 表示还没有房间,正常。
从这一章往后,凡写着「在控制台里输入」的地方,都是在这个游戏窗口里按 ~。
方式 B(无窗口,接近生产):-ExecCmds 一次性执行
在 PowerShell 里(把 <UE> 与 <Project目录> 换成你自己的路径,注意中间那层 Engine):
& "<UE>\Engine\Binaries\Win64\UnrealEditor.exe" "<Project目录>\<Project>.uproject" /Engine/Maps/Entry -server -game -nullrhi -unattended -ExecCmds="CrossingNet.Status" -log -PORT=57200例如:
& "D:\UnrealEngine-5.8.2\Engine\Binaries\Win64\UnrealEditor.exe" "D:\MyGame\MyGame.uproject" /Engine/Maps/Entry -server -game -nullrhi -unattended -ExecCmds="CrossingNet.Status" -log -PORT=57200-ExecCmds在启动时执行一次,多个命令用逗号分隔;输出在日志窗口(-log)与Saved/Logs/里- 这种方式不能交互:想再执行一条,就得改
-ExecCmds重启,状态也从头开始 - 生产环境的大厅就是这样跑的:命令靠启动参数与外部工具发,不靠手敲
为什么这样工作:大厅是一个权威进程,额外监听控制端口(默认 57300);
Status 只是读这层的数据。渲染设备有无(-nullrhi)不影响大厅逻辑,但没有渲染就没有视口,也就没有 ~。
常见失败
| 症状 | 原因 | 修 |
|---|---|---|
按 ~ 没反应 / 敲不了字 | 跑的是 -server 进程,没有视口 | 用方式 A;或改用 -ExecCmds(方式 B) |
UnrealEditor.exe 不是内部或外部命令 | 路径漏了 Engine 这一层,或工程路径写错 | 用绝对路径并以 & "路径" 开头,形如 <UE>\Engine\Binaries\Win64\UnrealEditor.exe |
| 敲了回车没反应 | 输出在日志里,不在输入行下面;若日志里也没有 [Status] event=Snapshot,多半是在编辑器底部的 Cmd 输入框里敲的——那是编辑器世界,没有 GameInstance,函数直接返回 | 到 PIE 的 Listen Server 游戏窗口里按 ~ 再试 |
控制台里 CrossingNet.Status 报未知命令 | 插件没加载(第 1 章没做完) | 看日志里有没有 [Session] event=ControlReady |
| 端口被占 | -PORT 与别的进程冲突 | 换端口;同时确认 LobbyControlPort(大厅控制端口) 没被占 |
自测:方式 A 里不点 Play(只开编辑器)时,Status 能看到什么?为什么?
下一章用它:大厅负责拉起并盯住房间进程。
案例 4-A · 拉起房间
本章产出:一个 Ready 的实例。
前置检查:上一章的大厅还在跑,CrossingNet.Status 能打出 [Status] event=Snapshot。
在哪输入:CrossingNet.* 是 UE 控制台命令,两种给法挑一种:
- 方式 A(PIE Listen Server):在那个游戏窗口里按
~,输入下面这行 - 方式 B(无窗口大厅):把命令写进启动参数
-ExecCmds="CrossingNet.DebugAssign 1v1",重启大厅
CrossingNet.DebugAssign 1v1输出在哪:大厅的日志——编辑器的 Output Log、-log 弹出的日志窗口,或 Saved/Logs/<Project>.log。
预期依次出现:
[Session] event=SpawnStart mode=1v1 port=57000
[Session] event=HealthFirstOK port=57000为什么这样工作:DebugAssign 跳过匹配,直接 SpawnInstance 拉起一个实例,
进程起来后房间在健康端口回 OK;…,大厅才把它从 Spawning 挪到 Ready。
常见失败
| 症状 | 原因 | 修 |
|---|---|---|
DebugAssignFailed,error 里写着 RoomMapPackage 未配置 | 第 2 章那一项没填 | 填 /Engine/Maps/Entry 或 /Game/...,重启大厅 |
敲了命令,日志里没有 SpawnStart | 命令在大厅以外的世界执行了(例如编辑器的 Cmd 输入框),或大厅没跑 | 在 PIE 游戏窗口按 ~,或确认大厅进程在跑 |
卡在 Spawning | ServerExePath(服务器可执行文件) / ServerArgsPrefix(服务器前置参数) 写的可执行文件拉不起来 | 看 Saved/CrossingNet/Logs/instance_<端口>.log 有没有生成 |
| 超时关闭 | StartupTimeoutSeconds(启动超时,秒) 内没回健康 | 查健康端口段与防火墙 |
自测:把 GamePortRange 改窄到只剩一个端口,连开两个实例会发生什么?
下一章用它:Ready 的实例才能坐人。
案例 5-A · 客户端进房
本章产出:房间里有一个玩家。
前置检查:上一章拉起的实例仍是 Ready(大厅日志里最后一次是 HealthFirstOK)。
在哪输入:Windows 终端(PowerShell)。这是一条启动客户端进程的命令,不是 UE 控制台命令:
& "<UE>\Engine\Binaries\Win64\UnrealEditor.exe" "<Project目录>\<Project>.uproject" 127.0.0.1:57200 -game -log -CrossingNetGuestSlot=1<UE>、<Project目录>换成你自己的路径-log让客户端也有日志窗口;不加就只能去Saved/Logs/找-CrossingNetGuestSlot=1给这台机器上的第一个客户端一个固定身份槽位,避免同机多开冲突
输出在哪:房间侧的分座位结果在房间进程的日志 Saved/CrossingNet/Logs/instance_<端口>.log;
客户端自己的旅行日志在它的输出日志里。预期房间日志:
[Room] event=JoinTokenAccepted player=<guid> role=Player team=0
[Room] event=SeatAssigned player=<guid> seat=0为什么这样工作:大厅签发票据,客户端带着票据旅行;房间用同一个 JoinTokenSecret 校验后分座位。
常见失败
| 症状 | 原因 | 修 |
|---|---|---|
| 客户端窗口一闪就没了 / 连不上 | 地址或端口写错,或大厅没在 57200 上监听 | 看客户端日志里的 [Travel] 行 |
| 旅行超时 | 分配地址是 127.0.0.1 但客户端在另一台机器 | 配 PublicAddress(对外地址) |
JoinTokenRejected | 两边 JoinTokenSecret(令牌密钥) 不一致 | 改 ini 并重启大厅与房间 |
自测:把 JoinTokenTtlSeconds 改成 1,隔几秒再进房,日志会是什么?
下一章用它:有人才能开局、结束、结算。
案例 6-A · 结束与结算
本章产出:一条落地并回了 ACK 的结算记录。
前置检查:按第 5 章让一个客户端进了房,房间日志里出现过 SeatAssigned。
在哪输入:自动结束参数写进 ini;CrossingNet.ForceSettle 是 UE 控制台命令(方式 A 在游戏窗口按 ~,方式 B 写进 -ExecCmds 重启)。
做法一(不用命令):给房间加自动结束参数,房间到点自己结束。参数配在大厅的
DefaultGame.ini 里:
; 额外服务器参数
ExtraServerArgs=-CrossingNetAutoEndGame=8做法二(用命令):在大厅的 UE 控制台里强制结算——方式 A 在游戏窗口按 ~,方式 B 写进
-ExecCmds="CrossingNet.ForceSettle" 重启:
CrossingNet.ForceSettle输出在哪:大厅日志。预期:
[Session] event=SettlementRecorded match=<id>
[Session] event=SettlementAcked match=<id>为什么这样工作:房间把结果带 matchId 发给大厅,大厅先回 ACK 再异步落盘,按 matchId 幂等。
常见失败
| 症状 | 原因 | 修 |
|---|---|---|
一直 SettlementPush 无 ACK | 控制通道不通(57300) | 查端口与防火墙 |
SettlementDuplicate | 同一局被结算两次 | 正常保护,不用处理 |
自测:大厅重启后,用同一个 matchId 再发一次结果会发生什么?
下一章用它:自动匹配最终也会走到这条结算链路。
案例 7-A · 自动匹配
本章产出:两个客户端被配到同一局。
前置检查:大厅还在跑,而且第 5 章能进房、第 6 章能结算。
在哪输入:Windows 终端,开两个窗口各跑一条(换成你自己的路径):
& "<UE>\Engine\Binaries\Win64\UnrealEditor.exe" "<Project目录>\<Project>.uproject" 127.0.0.1:57200 -game -log -CrossingNetGuestSlot=1 -CrossingNetAutoMatch -CrossingNetAutoReady
& "<UE>\Engine\Binaries\Win64\UnrealEditor.exe" "<Project目录>\<Project>.uproject" 127.0.0.1:57200 -game -log -CrossingNetGuestSlot=2 -CrossingNetAutoMatch -CrossingNetAutoReady输出在哪:大厅日志里出现 QueueJoin → MatchFound,随后是 ReadyCheck 与分配;
两个客户端的日志里各有一条 [Assign] 与 [Travel]。
为什么这样工作:两个客户端各自入队,匹配器按 MatchBaseEloWindow 聚合;
配到后进 ReadyCheck,确认后才分配实例与票据。
常见失败
| 症状 | 原因 | 修 |
|---|---|---|
| 一直排队 | 模式与 ModeConfigs(模式配置) 不匹配(例如排 2v2 但只配了 1v1) | 检查 +ModeConfigs |
| 排队超时 | MatchMaxWaitSeconds(最大匹配等待,秒) 到了还没配到 | 放宽窗口或检查人数 |
自测:只开一个客户端时,它会在什么时候以什么错误码结束排队?
下一章用它:没有大厅,局域网也能开一局。
案例 8-A · 局域网开房
本章产出:另一台机器在局域网列表里看见房间。
前置检查:两台机器接在同一个路由器或交换机下(同一网段),并且不需要大厅。
先在两台机器上各开一个带窗口的游戏(局域网发现要在游戏里执行,不需要 -server):
& "<UE>\Engine\Binaries\Win64\UnrealEditor.exe" "<Project目录>\<Project>.uproject" /Engine/Maps/Entry -game -log在哪输入:两台机器各自的游戏窗口里按 ~(这是 UE 控制台命令)。
机器 A(当房主):
CrossingNet.LANHost 我的房间 /Engine/Maps/Entry 57100机器 B(找房间):
CrossingNet.LANDiscover
CrossingNet.LANList输出在哪:机器 B 的日志里出现
[LAN] rooms=1随后加入:
CrossingNet.LANJoin 192.168.1.23:57100为什么这样工作:房主每 LANAnnounceInterval 秒发 OFFER,客户端收包后按 HostId 去重,
地址只取 UDP 源地址。
常见失败
| 症状 | 原因 | 修 |
|---|---|---|
[LAN] rooms=0 | 两台机器不在同一网段,或组播被交换机拦了 | 关 LANUseMulticast(使用组播),只用广播 |
| 列表有但连不上 | 防火墙挡住游戏端口 | 放行 LANGamePortRange(局域网游戏端口范围) |
自测:把 LANUseMulticast 关掉后,LANDiscover 的行为有什么变化?
下一章用它:知道怎么开房,也要知道怎么把人挡在门外。
案例 9-A · 运维与封禁
本章产出:一条设备封禁记录,和一条能按 trace 检索的日志。
前置检查:至少有一个客户端连过大厅(这样才登记过设备)。
在哪输入:大厅的 UE 控制台——方式 A 在游戏窗口按 ~,方式 B 写进
-ExecCmds="CrossingNet.DeviceList" 重启(多条命令用逗号分隔)。
CrossingNet.DeviceList
CrossingNet.DeviceBan <deviceKey> 0 测试
CrossingNet.DeviceList banned<deviceKey> 从第一条命令的输出里抄——[Device] 行开头那 8 位。
输出在哪:大厅日志。预期:
[Device] list bannedOnly=0 count=1
[Device] A1B2C3D4 platform=Win64 banned=0 until=0 accounts=1
[Device] list bannedOnly=1 count=1同时 Saved/CrossingNet/Devices.json 里会出现该设备的记录。
为什么这样工作:设备注册表只在大厅服务端初始化,DeviceBan 只封精确硬件指纹;
弱指纹与候选只记录不自动封。
常见失败
| 症状 | 原因 | 修 |
|---|---|---|
| 命令被拒绝 | 在客户端执行了 | 到大厅(服务端)执行 |
| 封了但还能进 | 登录拒绝点在项目登录层 | 插件只给信号,接入点要项目自己接 |
自测:minutes=0 与 minutes=60 的区别在哪张表、哪个字段上看?
下一章:没有下一章;从这里开始,按你要做的事去查参考页。
覆盖矩阵
| 能力 | 章节 | 验证方式 |
|---|---|---|
| 装进项目并编译通过 | 1 | 案例 1-A 的完成判据 |
| 看懂并配好必填设置 | 2 | 案例 2-A 的四项非空 + [Config] event=Summary |
| 起大厅并读懂实例表 | 3 | 案例 3-A |
拉起房间并认出 Ready | 4 | 案例 4-A |
| 客户端带票据进房 | 5 | 案例 5-A |
| 结束一局并确认 ACK | 6 | 案例 6-A |
| 跑通自动匹配 | 7 | 案例 7-A |
| 局域网开房与发现 | 8 | 案例 8-A |
| 用命令与日志排查 | 9 | 案例 9-A |
没有覆盖什么:玩法规则的实现、UI 与表现层、账号与登录、打包与发布、性能与容量、 观战与迟到的实际体验、系列赛与赛季的配置调优。这些在事件参考、 配置参考与各专题页里,但没有配套案例。