《虚幻引擎网络纲要》笔记
~~~~~~~~~~~~~~~~~~~~~前~~~~言~~~~~~~~~~~~~~~~~~~~~
UE4 使用标准服务器-客户端架构。
例1:当某一个客户端角色移动时,把这个移动消息发给服务端,服务端再通知所有客户端(包含这个客户端)。
为了防止“滞后”,一般会让这个客户端先在本地做出移动,同时偏差值超过一定数值,允许服务器“纠正”这个客户端的位置。
例2:客户端A给客户端B发送消息,实际上是客户端A发送给服务器,服务器再发送给客户端B。
TIPS:以服务器的数据为准,永远不要相信客户端。
~~~~~~~~~~~~~~~~~~~~基~~~~础~~~~~~~~~~~~~~~~~~~~~~
1. Game Mode 游戏模式
类名:AGameMode
作用:定义游戏的规则 (单人/组队?获胜条件?)
作用域:仅在服务器上可用,客户端去获取只能得到空指针。
--------------可重写的方法-------------------
检查是否所有玩家都准备好了
Ready to start Match 的 C++写法 ReadyToStartMatch_Implementation
有新玩家加入并获取改玩家的Player Controller
OnPostLogin 的C++写法 PostLogin
--------------控制比赛状态的事件-------------------
当对应的Ready to函数返回true时,会自动调用。你也可以手动调用。
可以在客户端调用这些事件获取比赛状态。
--------------------重要变量-----------------------
Default Player Name:给每个连接进来的玩家一个默认玩家名,以便在 PlayerState 里访问。
通过Option String获取最大玩家数量
Option String 的C++写法BeginPlay
2. Game State 游戏状态
类名:AGameState
作用:记录当前游戏状态。(已连接玩家的列表)
作用域:可同步的,每个客户端都可以访问。
例如:GameMode规定了要五杀才能赢,GameState就负责跟踪每个玩家的击杀量。
3. Player State 玩家状态
类名:APlayerState
作用:记录玩家的当前状态。
作用域:可同步的,每个客户端都有。
这些蓝图是可同步的,也能在所有客户端保持同步、
4. Pawn
子类:ACharacter
作用:记录玩家的位置、旋转等信息
作用域:不是客户端在移动角色,而是客户端把移动消息传给服务器,服务器移动并同步角色。
玩家掉血
设置血条
5. Player Controller
子类:APlayerController
作用:玩家的输入信息
作用域:每个客户端有自己的玩家控制器,存在于自己和服务器。客户端之间不能互相获取。
Q.怎样获取正确的PlayerController?
node: GetPlayerController(0)
code: UGameplayerController(GetWorld(),0);
- 在监听服务器中,会得到监听服务器的玩家控制器;
- 在客户端调用,会得到客户端的玩家控制器;
- 在专属服务器调用,会得到第一个客户端的玩家控制器;
分屏游戏才需要使用0以外的值。
~~~~~~~~~~~~~~~网~~~络~~~框~~~架~~~~~~~~~~~~~~~~~~~~~
我们可以把网络框架分为四个部分:
- Server Only:单服务器,这些对象只存在于服务端
- Server & Clinets:单服务器多客户端,这些对象存在于服务器和所有客户端
- Server & Owning Client:单服务器单客户端,这些对象存在于服务器和客户端,Owning Client 就是指客户端自己。
- Owning Client Only:单客户端,这些对象只存在于客户端
服务器和两个客户端:
~~~~~~~~~~~~~~专属服务器 VS 监听服务器~~~~~~~~~~~~~~~~~~
专属服务器 Dedicated Server
专属服务器是独立的服务器不依赖于客户端。
通常用来持续运行以便客户端可以随时加入。
专属服务器可以被编译成Windows和Linux版本,通过固定的IP地址连接。
专属服务器没有可视化部分,不需要UI,没有玩家控制器,没有角色。
监听服务器 Listen Server
至少有1个客户端,这1个客户端同时也是服务端。这个客户端断开连接,服务端也就关闭了。
监听服务器有UI,有玩家控制器(代表客户端)。
因为监听服务器运行在客户端本身,所以其他客户端需要连接这个客户端的IP,但是客户端没有静态IP地址。要靠OnlineSubsystem解决变化的IP问题。
~~~~~~~~~~~~~~~~~同~~步 ~~ Replication~~~~~~~~~~~~~~~~~~~
Q. 什么是同步?
A. 同步是服务器向客户端传递信息/数据的行为。
Q. 哪些数据可以同步?
A. Actor和继承Actor的类
Q. 怎么激活同步属性?
A. 属性框里勾选;C++里代码设置属性为true。
Q. 设置同步的位置不同显示不同
A. 在服务端设置Actor同步,会在所有客户端同步;在客户端设置Actor同步,Actor只会存在于这个客户端上。
设置变量可同步:
不仅可以同步给所有客户端,还可以指定同步给谁。
条件 | 描述 |
COND_InitialOnly | 这个属性只发送给初始簇(initial bunch) |
COND_OwnerOnly | 这个属性只发送给Actor的所有者 |
COND_SkipOwner | 这个属性发送给每个连接者除了拥有者 |
COND_SimulatedOnly | 这个属性只发送给模拟Actor(simulated Actors) |
COND_AutonomousOnly | 这个属性只发送给有自主权的Actor |
COND_SimulatedOrPhysics | 这个属性发送给simulated或bRepPhysics Actors |
COND_Custom | 这个属性没有特定条件,但是想要通过SetCustomIsActiveOverride切换开关 |
~~~~~~~~~~~~~~~~~RPC~~~~~~~~~~~~~~~~~~~
全称:Remote Procedure Call 远程过程调用
作用:客户端调用服务端的方法、服务端调用客户端的方法、服务端调用一个特定群组的方法。
注意,远程过程调用没有返回值!
使用RPC的要求:
- 必须由Actor发起RPC;
- 发起的Actor必须可同步;
- 对于多播RPCs:
- 在服务器调用RPC,在服务器和所有已连接的客户端上都会执行。
- 如果从客户端调用RPC,将只在本地执行,而不会在服务器上执行。
从服务器调用:
Actor的拥有者 | 不同步 | 多播网路 | 服务器 | 客户端 |
客户端 | 在服务器上运行 | 在服务器和所有客户端运行 | 在服务器上运行 | 在客户端上运行 |
服务端 | 在服务器上运行 | 在服务器和所有客户端运行 | 在服务器上运行 | 在服务器上运行 |
无主引用 | 在服务器上运行 | 在服务器和所有客户端运行 | 在服务器上运行 | 在服务器上运行 |
从客户端调用:
Actor的拥有者 | 不同步 | 多播网路 | 服务器 | 客户端 |
客户端自己调用 | 在调用客户端上运行 | 在调用客户端上运行 | 在服务器运行 | 在调用客户端上运行 |
另一个客户端调用 | 在调用客户端上运行 | 在调用客户端上运行 | 丢包 | 在调用客户端上运行 |
服务端 | 在调用客户端上运行 | 在调用客户端上运行 | 丢包 | 在调用客户端上运行 |
无主引用 | 在调用客户端上运行 | 在调用客户端上运行 | 丢包 | 在调用客户端上运行 |
在蓝图中调用:
创建CustomEvents,并设置为同步。
勾选Reliable复选框,可以确保RPC一定会执行。但不要滥用!
在C++中调用:
要使用整个网络组件,需要包含头文件 UnrealNetwork.h
c++中的rpc相对容易创建,我们只需要将说明符添加到UFUNCTION()宏。
这个RPC被标记为不可靠的,需要验证。
CPP文件要实现两个函数:
客户端调用RPC,需要被标记为不可靠的或可靠的:
WithValidation这个参数表示需要验证,验证函数需要自己写,如下:如果返回false,就会断开与调用者的连接。
~~~~~~~~~~~~~~~~~所有权~~~~~~~~~~~~~~~~~~~
七、Actor相关性和优先级
八、Actor Role 和 RemoteRole
九、Traveling in Multiplayer
十、Online Subsystem
十一、怎样开始一个多人游戏
————————————————————————
参考文献:
https://cedric-neukirchen.net/Downloads/Compendium/UE4_Network_Compendium_by_Cedric_eXi_Neukirchen.pdf