7

UE4 ShooterGame Server研究

 3 years ago
source link: https://www.lanindex.com/ue4-shootergame-server%e7%a0%94%e7%a9%b6/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

UE4 ShooterGame Server研究

2018/01/13 · Leave a comment

以下内容都是基于Unreal Engine版本:4.18.2-0+++UE4+Release-4.18。

操作系统是:Window10 x64专业版。

编译工具:VS2017 企业版。

在上一篇文章UE4 ShooterGame Standalone Dedicated Server(Windows & Linux),主要讲述如何编译、部署一台ShooterGame服务器。这篇文章里会讲述一些UE4 Server相关的基础知识,以及如何修改ShooterGame Dedicated Server的内容为我们所用。

阅读过一点ShooterGame代码再读此文效果更加,后面Server若无特指,均表示Dedicated Server。

参考文献:https://docs.unrealengine.com/latest/CHN/Gameplay/Networking/Server/index.html

UE4关于ENetRole的解释

UE4的ClientServer公用一套代码,从编译结果的角度来看就是他们依赖同一个.pak文件。所以在UE4内部,对于如何区分Client/Server有一套完整的机制,以Dedicated Server模式为例

enum ENetRole

ROLE_None – 这个对象没有网络连接,并不需要在C/S同步;

ROLE_SimulatedProxy – 模拟对象,仅仅用于Client本地模拟,它的状态不能在本地主动被改变(只能被动改变);

ROLE_AutonomousProxy – 自治对象,在Client接受各种输入,并且主动与Server通信;

ROLE_Authority – Server权威,它表示一个真正的对象(为什么这么说呢?UE4官方建议:只有Server(包含Listen Server后文会提及)能产生需要在C/S间复制对象。如果Client自主产生了一个对象,那么它仅仅只会在创建它的Client上存在);

概念有点绕,举个实际的例子,比如我有二个客户端ClientAClinetB,他们通过Dedicated Server进行游戏,对应的ENetRole如下:

Server侧 – ClientA.Role = ROLE_Authority;ClientB.Role = ROLE_Authority;

ClientA侧 – ClientA.Role = ROLE_AutonomousProxy;ClientB.Role = ROLE_SimulatedProxy;

ClientB侧 – ClientA.Role = ROLE_SimulatedProxy;ClientB.Role = ROLE_AutonomousProxy;

简单的一句话概括就是:服务器拥有对象实体是ROLE_Authority,客户端拥有的本地对象是ROLE_AutonomousProxy,客户端展现的其他客户端对象是ROLE_SimulatedProxy。

UE4关于ENetMode的解释

ENetMode

NM_Standalone – 单机服务器模式,可以有1-n个本地客户端,无网络连接;

NM_DedicatedServer – 专用服务器模式,没有本地客户端;

NM_ListenServer – 监听服务器模式,一个本地客户端做主机;

NM_Client – 客户端,连接远程服务器;

那么问题来了,ENetRoleENetMode是不是有部分定义重复了?

不是。一些个人理解:ENetRole主要是用在和玩家角色直接相关内容上,往往会通过if (Role < ROLE_Authority)来判断代码是否需要对服务端进行RPCENetMode更宏观,提供了区分Listen ServerDedicated Server的方法例如,一些粒子效果不需要在Dedicated Server展现,但是需要在Listen Server展现时,可以依靠ENetMode区分。反过来看,ENetRole提供了区分本地操控客户端(ROLE_AutonomousProxy )与本地模拟客户端(ROLE_SimulatedProxy )的方法。

UE4 ShooterGame Server启动流程

ShooterGame Server的启动流程依附与UE4自身一套流程,UE4的一些基础类比如UGameInstanceAGameMode会暴露一些虚函数,ShooterGame继承这些类,并按需实现虚函数。实现中通过super关键字来调用基类的实现,达到嵌入ShooterGame自身逻辑的目的,附图:

ShooterGame-683x1024.png

图很简单,里面省略了很多资源的初始化与加载。实际我们需要关心的,GEngine是全局唯一的,然后创建GameInstance,确定游戏地图后才会创建GameMode,在GameMode里面初始化GameStateGameSession。可以看到核心还是Main()->Init()->Loop()的套路。

修改ShooterGame Server

先分析一下,如果目标是:

  1. 将ShooterGame Server作为一场战斗的核心逻辑;
  2. 战前匹配,战后结算放置到自定义(非UE4)的服务器;

需要解决的问题(只列了与ShooterGame 相关的):

  1. 需要一个控制服务器(ControlServer),来管理ShooterGame Server,这里包含了Socket通信,状态控制等问题;
  2. 搞清楚ShooterGame Client与Server的握手原理,因为需要加入自定义的参数,目的是为了验证客户端合法性;
  3. ShooterGame的状态扭转流程;

问题1限于篇幅后续有时间会再出一篇博文详细说明。先分析问题2、3:

UE4 Client连接Server步骤
  1. Client发送连接请求;
  2. Server如果接受请求,发送当前地图;
  3. Server等待Client加载地图;
  4. 加载完成后,Server会调用AGameMode::PreLogin;
    • ShooterGame对其进行了重载AShooterGameMode::PreLogin,你可以在这里加入自己的自定义参数进行验证
  5. 然后服务器会调用 AGameMode::Login;
    •  ShooterGame并没有重载这个函数;
    • 该函数的作用是创建一个 PlayerController,可用于在今后复制到新连接的客户端。成功接收后,这个 PlayerController 将替代客户端的临时 PlayerController (之前被用作连接过程中的占位符);
    • 此时将调用 APlayerController::BeginPlay。应当注意的是,此时调用 RPC 函数尚存在安全风险。您应当等待 AGameMode::PostLogin 被调用完成;
  6. 如果一切顺利,AGameMode::PostLogin 将被调用;
    • ShooterGame对其进行了重载AShooterGameMode::PostLogin;
    • 在这里处理一些成功Login之后的逻辑,也可以放心的让服务器在此 PlayerController 上开始调用 RPC 函数;
ShooterGame游戏状态流程

核心的处理函数是AShooterGameMode::DefaultTimer,它是一个定时器函数,每1秒会执行一次。整个流程参考下图

ShooterGame%E6%B8%B8%E6%88%8F%E6%B5%81%E7%A8%8B1.png

需要做的:

  • 在WaitToStart加入自己等待开始的逻辑;
  • 在进入WaitingPostMatch前,进行战斗结算与空闲通知,断开与玩家的socket连接;

写的比较杂,在年前看没有时间把控制服务器相关的东西整理一下总结出来。UE4总体来说是一个“坑”比较多的引擎,需要时间去积累经验,社区资源比较匮乏,有些问题官方文档说的不详细,经常导致一个问题需要解决很久的情况。不过天道酬勤,新的一年加油。

(全文结束)

转载文章请注明出处:漫漫路 - lanindex.com


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK