UE5网络(一)—架构篇
🤯

UE5网络(一)—架构篇

Tags
UE5
C++
网络
Published
August 10, 2023
Author
Think-01

前言

其实官方文档对用网络这块写的已经比较明白和详细了,但是我还是逼逼叨几句,用于加深印象。

架构

虚幻引擎使用标准的服务器-客户端架构。这意味着服务器是权威的,所有数据必须首先从客户端发送到服务器。之后,服务器验证数据并根据您的代码做出反应。
举例来说:
  1. 当你在吃鸡(Steam游戏:绝地求生)按下WSAD移动操作时,您不会自己移动角色,而是告诉服务器您想要移动它。然后,服务器会为其他人(包括您)更新角色的变换(移动,缩放,旋转)。
  1. 当向另一个客户端发送聊天消息时,您首先将其发送到服务器,然后服务器将其传递给您想要联系的客户端。这也可以是团队、公会、团体等。
还有一点需要强调的是,不同于其他服务器-客户端架构的代码,这里服务器和客户端的代码是写在一起的,没有单独的服务器代码,一次开发,对同样的代码分别进行服务器和客户端的打包,就能得到服务器和客户端的可执行程序。

服务器-客户端

虚幻中能进行通信的GamePlay类大部分都是继承自Actor的,可以这么说,所有的通信都是建立在Actor上的。UObject也是可以复制,你将他放在Actor里面,把Actor当一个容器即可。各种组件就是最好的例子。
根据Gameplay中关于虚幻引擎常用Actor类信息,将它们分为四类:
  • Server Only -只有服务器有的Actor
  • Server & Clients - 服务器和所有的客户端都有的Actor
  • Server & Owning Client - 有的Actor仅存在于服务器和Owning Client的客户端
  • Owning Client Only - 有的Actor仅存在于Owning Client的客户端
下面两张图展示了一些常见的类以及它们存在于哪个类别中。
notion image
下图演示了具有两个客户端和一个专用服务器各自的Actor。
notion image

Owning Client是啥?

我们可以看到,在上述Gameplay的网络架构图中,有一个分类只有一个类,就是APlayerController。而且标注为Owning Client,同样是在服务器和客户端同时存在的Actor,为啥特殊标注一个拥有者客户端呢。
从类名来看,控制器类,控制啥呢?在服务器可以控制么?其实专用服务器不需要控制,服务器一般都是根据网络协议收发数据,专用的服务器需要保证24小时不停机,人为的控制反而导致服务器更不稳定,说真的,与其相信人类的手动操作,你更应该相信自动化的计算机稳定性为更好。
所以,APlayerController更多表明的是客户端控制的类(但是不要忘了,服务器同样存在APlayerController,它的作用是做一个权威的代理,看似是你直接控制客户端,实际上是你发送到服务器,然后服务器在复制到客户端),我们知道,在面向对象编程中,难免会存在依赖。很多时候我们都需要避免依赖。但是在UE的Gameplay架构下,所有与APlayContrller有依赖的,都称作Owning Client
APlayerController最多的就是控制Pawn了.所以Pawn会作为一个属性存在于AController.这便产生了依赖,恰恰是这种依赖,使得Pawn存为了Owning Client.
void AController::Possess(APawn* InPawn) { ... OnPossess(InPawn); ... } void AController::OnPossess(APawn* InPawn) { ... SetPawn(InPawn); ... }
一般来说Pawn上面会有很多组件,比如输入组件,摄像机组件,这些统统都是Owning Client,因为往上推都能推到APlayerController.
我们这里说的都是玩家能控制的,如果是AI的AController则是不算Owning Client.
为啥说这么多Owning Client,因为其有很多作用:
  • RPC 需要确定哪个客户端将执行运行于客户端的 RPC
  • Actor 复制与连接相关性
  • 在涉及所有者时的 Actor 属性复制条件
在Pawn中,可使用C++中的 IsLocallyControlled 函数,或蓝图中的 Is Locally Controlled 节点,以判断Pawn是否在其拥有客户端上。

服务器类型

为啥服务器还有类型?如果你玩过联机游戏你就晓得,比如有的游戏可以在自己的电脑上开服,你的小伙伴直接链接你自己电脑上的服务器就可以一起玩,比如经典生存游戏—-饥荒.这种在虚幻这边叫做监听服务器.而我们常玩的大部分游戏都是专用服务器,你可以在任何时候上线,因为专用服务器基本不会宕机.而如果你玩的是饥荒这种游戏,你断网了你的小伙伴就会连接不上,所有肝的游戏进度全没了.

专用服务器

专用服务器与游戏客户端分开运行,主要用于运行服务器,玩家可以随时加入/离开,而服务器不会随之关闭。
专用服务器可以针对 Windows 和 Linux 进行编译,并且可以在玩家可以通过固定 IP 地址连接到的云服务器上运行。
专用服务器没有视觉部分,因此它们不需要 UI,也没有 PlayerController。他们在游戏中也没有代表他们的角色或类似角色。

监听服务器

侦听服务器是服务器,也是客户端。
由于也是客户端,Listen-Server 需要 UI 并有一个 PlayerController,它代表客户端部分。在监听服务器上获取“PlayerController(0)”将返回该客户端的 PlayerController。
由于Listen-Server运行在客户端本身,所以其他人需要连接的IP就是客户端之一。与专用服务器相比,这通常会带来玩家没有静态 IP 的问题。
然而,使用OnlineSubsystem(后面章节解释),可以解决IP变化的问题。

Actor的网络角色和授权

在服务器-客户端的架构下,每个Actor除了根据其在服务器和客户端的存在情况,还有其他的分类方式,那就是是根据其扮演的角色和拥有的权限(也就是是授权)来区分。
Actor的 角色 将决定网络游戏期间控制Actor的机器。授权 Actor被认为可控制Actor的状态,并可将信息复制到网络多人游戏会话中的其他机器上。授权Actor就是服务器生成的,由服务器主导和控制的Actor。
远程代理 是该Actor在远程机器上的副本,其将接收授权Actor中的复制信息。这里的远程是以服务器为视角的,指客户端上的代理Actor。远程代理分为两种,一种是自主代理,这种一般是玩家自己的Pawn,也就是Owning Client的Actor。一种是模拟代理,这种指的是其他玩家控制的Pawn,以及服务器复制过来的所有不是Owning Client的Actor。
其由 Local Role 和 Remote Role 变量进行追踪,可取以下值:
网络角色
说明
Actor在网络游戏中无角色,不会复制。只存在于本地机器中
授权
Actor为授权状态,会将其信息复制到其他机器上的远程代理。
模拟代理
Actor为远程代理,由另一台机器上的授权Actor完全控制。网络游戏中如拾取物、发射物或交互对象等多数Actor将在远程客户端上显示为模拟代理。
自主代理
Actor为远程代理,能够本地执行部分功能,但会接收授权Actor中的矫正。自主代理通常为玩家直接控制的Actor所保留,如Pawn。
总结,只存在于客户端的Actor,比如UI,没有wangluo
同时存在于服务器和客户端的Actor。在服务器上角色为授权(Local Role),在客户端为代理(Remote Role)。在客户端上有Owning Client的为自主代理,没有Owning Client的为模拟代理。
网络角色枚举:
/** The network role of an actor on a local/remote network context */ UENUM() enum ENetRole { /** No role at all. */ ROLE_None, /** Locally simulated proxy of this actor. */ ROLE_SimulatedProxy, /** Locally autonomous proxy of this actor. */ ROLE_AutonomousProxy, /** Authoritative control over the actor. */ ROLE_Authority, ROLE_MAX, };