第二十一章:专用服务器设置与托管

1. 本章核心目标

本章的目标分为两个层面:为玩家实现的显性功能,以及为项目奠定基础的隐性战略目标。

  • 显性目标 (Player-Facing Goals):

    1. 游戏打包与测试: 将项目打包成可执行文件 (.exe),使非开发人员也能运行游戏。

    2. 监听服务器功能验证: 测试并验证玩家作为主机(Listen Server)创建和加入游戏的功能,确保基于Steam的会话系统在打包后正常工作。

    3. 专用服务器连接: 实现玩家客户端能够发现并成功加入一个在云端或本地托管的专用服务器会话。

    4. 体验优化: 增加加载屏幕(Loading Screen)和世界边界(World Border),提升游戏完整度和玩家体验。

  • 隐性/战略目标 (Technical & Strategic Goals):

    1. 建立标准部署流程: 确立从源码编译引擎、打包客户端/服务器到最终托管的完整技术管线,为后续的持续集成/持续部署(CI/CD)打下基础。

    2. 掌握网络基础设施: 深入理解并实践多人游戏所需的基础网络知识,包括IP地址(公网/私网、静态/动态)、端口转发和防火墙配置,这是实现非局域网联机的核心。

    3. 源码编译能力: 成功编译虚幻引擎(Unreal Engine)源码版本,这是打包专用服务器的必要前提,也是团队掌握引擎底层、进行深度定制的开端。

    4. 云服务部署实践: 掌握使用主流云服务平台(如Amazon Web Services, AWS)部署游戏服务器的能力,为项目未来的可扩展性、稳定性和全球化运营提供技术储备。


2. 系统与功能实现

本章实现了多个关键系统,将游戏从开发阶段推向了可部署的在线产品阶段。

系统/功能模块 详细描述 与前期系统的交互/依赖
游戏打包系统 将项目内容(蓝图、模型、C++代码等)编译和打包成独立的客户端(Client)和服务器(Server)可执行文件。 依赖于项目内所有已完成的资产和代码。打包前需修复特定插件(如Fab)和资产引发的错误,并确保项目中至少包含一个C++类以支持Steam会话插件的正常工作。
监听服务器会话 修正了前期Host Game Menu中的Create Advanced Session节点。将Use Presence参数设为true,解决了监听服务器模式下建房即崩溃的严重BUG。 直接修正和完善了第20章中UI菜单的创建会话逻辑,确保客户端作为主机的多人功能闭环。
专用服务器会话逻辑 SurvivalGameInstance这个持久化类中,增加了服务器启动时自动创建会话的逻辑。通过Is Dedicated Server节点判断,若为真,则自动执行Create Advanced Session,并设置Use Presencefalse 依赖: 前期的Advanced Sessions插件。
交互: 将服务器创建逻辑从UI层(Host Game Menu)分离,实现了服务器的“无人值守”自动化。
加载屏幕系统 创建了一个名为W_LoadingScreen的UI控件,在客户端加入会话时(Join Session)和创建会话时(Create Session)显示,并在玩家角色数据初始化完成后隐藏。 交互:GameInstance和角色蓝图(BP_PlayerCharacter)交互。GameInstance负责创建和销毁加载界面实例,角色蓝图在合适的时机调用隐藏逻辑。
世界边界与出生点 在地图(IslandMap)中,使用多个Blocking Volume构建了不可穿越的世界边界,防止玩家掉出地图。同时,将默认的Player Start移至一个独立的、与主场景隔离的区域,作为新玩家的初始“大厅”。 交互: 直接作用于游戏地图,影响玩家的移动范围和初始生成位置。
云托管部署 (AWS) 完整演示了在AWS EC2上创建、配置和部署专用服务器的流程。包括:
1. 创建Windows Server实例。
2. 配置安全组,开放所需的游戏端口(TCP/UDP 7777, 27015等)。
3. 将包含Steam运行库的服务器文件上传至云实例。
4. 在云端通过命令行参数启动服务器并成功连接。
这是将整个项目推向公网的最终环节,不依赖于前期系统,而是前期所有系统成果的最终部署平台。

3. 关键设计思想

本章在架构和实现上体现了清晰的设计思想。

  • 设计模式 (Design Patterns):

    • 客户端-服务器架构 (Client-Server Architecture): 本章是该架构的集中体现,明确区分了监听服务器(客户端兼任服务器)和专用服务器(独立进程)两种模式,并分别实现了它们的托管逻辑。

    • 单例模式 (Singleton): Game Instance类的使用是单例模式的体现。它在游戏生命周期中全局唯一且持久存在,使其成为管理加载屏幕、处理专用服务器启动逻辑等全局状态和功能的理想场所。

  • 设计原则 (Design Principles):

    • 职责分离原则 (Single Responsibility Principle): 将专用服务器的会话创建逻辑从UI控件(Host Game Menu)中剥离,移至Game Instance中实现。这使得UI只负责处理客户端发起的行为,而Game Instance则负责处理更底层的、与游戏会话生命周期相关的逻辑,职责更加清晰。

    • 开闭原则 (Open/Closed Principle): 通过引入Is Dedicated Server分支,系统在不修改原有监听服务器逻辑(对修改关闭)的基础上,扩展了对专用服务器模式的支持(对扩展开放),体现了良好的可扩展性。


4. 核心技术点与难点

本章涉及了大量硬核技术点,是项目工程化的关键。

类别 核心技术点/难点 解决方案
引擎与编译 虚幻引擎源码编译: 无法通过启动器安装的二进制版引擎打包专用服务器。 1. 关联Epic Games与GitHub账户,下载引擎源码。
2. 配置正确的Visual Studio组件(SDKs, MSVC)。
3. 运行Setup.batGenerateProjectFiles.bat
4. 成功编译项目,生成可运行的编辑器版本。
创建服务器Target: 需要为项目创建专门的服务器编译目标文件。 1. 复制UnrealServer.Target.cs文件并重命名为[ProjectName]Server.Target.cs
2. 修改文件内容,指定项目名并添加Steam支持等编译定义。
网络配置 公网连接: 本地或云端服务器需要正确配置网络,才能被外网玩家发现和连接。 本地托管: 设置本地PC的静态IP地址,并在路由器上配置端口转发,将游戏所需端口(如UDP/TCP 7777)映射到该PC。
云端托管(AWS): 在EC2实例的安全组(Security Group)中配置入站(Inbound)和出站(Outbound)规则,开放所有游戏和Steam所需端口。
打包与部署 打包失败: 过程中遇到因插件、资产或配置不当导致的打包失败问题。 逐一排查Output Log中的错误信息。例如,禁用有问题的插件(Fab),清理或修复损坏的资产,以及为项目添加C++空类以解决依赖问题。
服务器启动与日志: 专用服务器是无UI进程,直接运行看不到任何信息。 使用命令行参数启动服务器可执行文件:
[MapName] -log -server -port=7777
其中 -log 参数会弹出一个显示实时日志的命令行窗口,便于调试和监控。
Steam库依赖: 部署到未安装Steam的云服务器上时,会因缺少Steam的DLL文件而无法创建会话。 手动从本地Steam安装目录中复制steam_api64.dll等四个核心DLL文件,并将其放置在服务器打包目录的.../Binaries/Win64下。

5. 自我批判与重构

本章的学习过程也是一个不断发现问题、反思和优化的过程。

  • 遇到的’坑’与关键问题:

    1. Use Presence的误用:Create Advanced Session节点中,Use Presence参数对于监听服务器和专用服务器是互斥的。错误的设置是导致监听服务器打包后崩溃的直接原因。这是一个非常隐蔽且致命的错误。

    2. C++类依赖: 对于纯蓝图项目,Steam会话系统在打包后需要一个C++类的存在才能正常编译和链接。这是一个文档中不甚明确,但实践中必须遵守的规则。

    3. 源码编译环境坑: Visual Studio的组件版本、Windows SDK版本必须与引擎源码版本严格对应,任何不匹配都可能导致编译失败,排查过程非常耗时。

    4. 服务器文件不完整: 在向AWS部署时,忘记附带Steam的运行库DLL,导致服务器在云端无法正常初始化Steam会话。

  • 对前期设计的反思与修正:

    • 重构会话创建逻辑: 前期将所有会话创建逻辑都放在Host Game UI控件中是不够健壮的。本章将其重构,将专用服务器的逻辑移入Game Instance,这是更合理的设计。因为服务器的启动不应依赖于任何UI交互,而Game Instance的生命周期与应用本身一致,是执行此类初始化任务的最佳位置。
  • 如果重来一次的优化方案:

    1. 尽早引入C++与源码: 如果项目立项时就确定为多人在线游戏,应在项目初期就转换为C++项目并搭建好源码编译环境。这样可以避免在项目后期引入所带来的巨大迁移和调试成本。

    2. 建立部署检查清单 (Deployment Checklist): 创建一个详细的清单,内容包括:必须禁用的插件、打包前需要清理的资产、客户端/服务器各自需要的编译配置、部署时必须携带的第三方库文件(如Steam DLLs)等。这将极大提升打包和部署的成功率和效率。

    3. 实现更专业的加载流程: 当前的加载屏幕只是一个简单的UI遮罩,无法应对复杂的关卡异步加载(Async Loading)。如果重来,会考虑从一开始就集成或自研一套基于异步加载的无缝世界加载方案,为玩家提供更流畅的过渡体验。

    4. 抽象网络配置: 将服务器名称、最大玩家数等配置项提取到配置文件(如DefaultGame.ini)中,而不是硬编码在蓝图里。这样在部署多台不同配置的服务器时,只需修改配置文件,无需重新打包。