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)的两条路线

  1. OSS 内建匹配:Steam/EOS 提供的匹配服务(基于 ticket 队列)。省事但受平台限制。
  2. 自建匹配服务:玩家客户端连接你的 Web 匹配服务(Redis 队列等),服务分配 DS 地址并下发给两端。大型项目的主流做法——灵活、跨平台、可控。

会话层通常还是用 OSS(统一邀请、好友、Presence),匹配逻辑放自建服务。

心得:会话层的抽象和业务层要划清界限。早期项目常犯的错是把「房间内游戏逻辑」写进 Session 回调里,导致换 OSS 平台时连带重构游戏逻辑。正确姿势:Session 只管「连接建立/断开/成员变化」,游戏逻辑监听游戏框架的 GameMode/PlayerController 事件(OnPostLogin、Logout),两者通过标准事件桥接。