5.1 OnlineSubsystemSession:会话与匹配框架
会话(Session)是什么
「会话」是 UE OnlineSubsystem(OSS)抽象的一层「对局/房间」概念:
- 一台专用服务器 + 若干玩家 = 一个 Dedicated Server Session
- 「一起开黑的好友队伍」= 一个 Party Session(可不含游戏服务器)
- 玩家的「在线状态」= Presence Session
它把「创建房间、查找房间、加入、邀请、踢人」这些操作抽象成统一接口,底层可切到 Steam / Epic Online Services / 自建(Null/CLI)等不同实现,业务代码同一套。官方文档见「Online Subsystem 会话接口」(https://www.wanxiangyundang.top/read/unreal-engine-5-8-docs/online-subsystem-session-inter-ec94)。
典型流程:一次匹配的生命周期
创建会话(CreateSession) ← 主机/匹配服务器调用
↓
注册服务器(RegisterServer) ← 让会话出现在「可查找列表」里
↓
查找/接受加入(FindSessions / JoinSession) ← 玩家客户端
↓
客户端 Connect 到会话里的服务器地址
↓
游戏中:会话状态更新(人数/进度)
↓
结束(EndSession)/ 销毁(DestroySession)
代码骨架
// 创建会话
auto Sessions = OnlineSub->GetSessionInterface();
FOnlineSessionSettings Settings;
Settings.NumPublicConnections = 8;
Settings.bShouldAdvertise = true;
Settings.bUsesPresence = false; // 专用服通常 false
Settings.bAllowJoinViaPresence = true;
Sessions->CreateSession(0, SESSION_NAME, Settings);
// 查找
Sessions->FindSessions(0, SessionSearch.ToSharedRef()); // 委托 OnFindSessionsComplete
// 加入
Sessions->JoinSession(0, SESSION_NAME, SearchResult); // 委托返回 ConnectString
// 连接
APlayerController* PC = ...;
PC->ClientTravel(ConnectString, TRAVEL_Absolute); // 见 5.2
所有接口都是异步 + 委托的:别在调用后立刻读结果,绑委托。
常见坑
| 坑 | 说明 | 规避 |
|---|---|---|
| 委托没绑全就调用 | 异步结果永远不回调 | 用前检查 OnlineSub/Session/Identity 三者非空 + 委托注册 |
| 会话名冲突 | CreateSession 的名字重复导致覆盖 | 用 FName 约定(GameSession / PartySession 分开) |
| 专用服务器上的 Presence | 云端服务器没 Presence,开启反而失败 | DS 上关 bUsesPresence |
| 平台差异 | Steam/EOS 行为不同(如邀请、好友列表) | 关键路径做 #if 平台分支,或只依赖抽象接口 |
| Null 子系统的「假装在线」 | 默认 Null OSS 本地可用,屋里连真实的平台 SDK | 开发期用 Null,发布前必须切到目标 OSS 验证 |
匹配(Matchmaking)的两条路线
- OSS 内建匹配:Steam/EOS 提供的匹配服务(基于 ticket 队列)。省事但受平台限制。
- 自建匹配服务:玩家客户端连接你的 Web 匹配服务(Redis 队列等),服务分配 DS 地址并下发给两端。大型项目的主流做法——灵活、跨平台、可控。
会话层通常还是用 OSS(统一邀请、好友、Presence),匹配逻辑放自建服务。
心得:会话层的抽象和业务层要划清界限。早期项目常犯的错是把「房间内游戏逻辑」写进 Session 回调里,导致换 OSS 平台时连带重构游戏逻辑。正确姿势:Session 只管「连接建立/断开/成员变化」,游戏逻辑监听游戏框架的 GameMode/PlayerController 事件(OnPostLogin、Logout),两者通过标准事件桥接。
