UE "Networking and Multiplayer"Document阅读笔记(未完待续)

最近需要使用UE的Multipalyer功能, 看了UE的官方笔记, 然鹅干看真的感觉没有什么收获.
因此, 也就边看边摘抄了.


Detailed Actor Replication Flow

  1. UNetDriver::ServerReplicateActors: 在此过程中,服务器会首先收集它确定与每个客户端相关的所有Actor,然后发送自上次更新每个已连接客户端以来发生变化的任何属性。
  2. UActorChannel::ReplicateActor: 处理Actor复制的详细过程

Important Properties 重要属性

Property Description
AActor::NetUpdateFrequency 复制频率
AActor::PreReplication 复制之前调用的函数
AActor::bOnlyRelevantToOwner 若此Actor仅复制到其owner, 则设置为true
AActor::IsRelevancyOwnerFor 若为true, 确定relevancy(相关性)
AActor::NetDormancy 确定Actor是否是休眠(Dormant)或者唤醒状态(awake)

Actor Replication Flow Overview(Replication的流程)

  1. 确定哪些Actor正在复制,并执行检查以确定休眠状态、更新频率和拥有连接。
    • 将通过这些检查的Actor添加到要考虑复制的列表中。
  2. 循环遍历每个连接并根据当前Actor和连接执行检查。在此步骤结束时,会出现一个考虑为每个连接进行复制的Actor列表。
    • 按每个连接的优先级对参与者进行排序
  3. 确定Actor是否与此连接相关。
  4. Replicate the actor to the current connection.
    详细流程信息请参考链接:https://docs.unrealengine.com/5.3/en-US/detailed-actor-replication-flow-in-unreal-engine/

Actor Owner and Owning Connection

Two important relationships for network replication in Unreal Engine are an actor's owner and the owner's associated owning connection(所有者的关联拥有连接).

Overview

Multiplayer in Unreal Engine uses a server-authoritative, client-server model. In this model, clients connect to a centralized server.
When a client connects to the server, a player controller is created on the server associated with the connected client(a connected client is referred to as a connection).
When the client begins play on the server, this player controller possesses a pawn that the client controls in the game. The player controller is the owner of the pawn.
The owning connection of an actor is the connection associated with the actor's owning player controller.
The owner and owning connection determine which connected client has the authority to make changes and call remote functions.

Every AActor-derived object stores a pointer to its owner.
Not every AActor-derived object has an owner. The actor's owner may be null, in which case the actor has no owner.

Uses of Owning Connection

Connection ownership is important for:

  • Actor replication
  • Property Replication
  • RPCs

An actor's owning connection is used during actor replication to determine which connections get updates for an actor, known as actor relevancy.(bOnlyRelevantToOwner == true)

Owner && Owner Connection

To determine the owner of an actor, you query for an actor's outermost owner. If the outermost owner is a player controller, then the original actor's owning connection is the same as the player controller's owning connection.

  • AActor::GetOwner : obtain an actor's owner
  • UActorComponent::GetOwner: obtain an actor component's owning actor
  • AActor::GetNetConnection:obtain an actor's owning connection

Actor Role and Remote Role

可以在虚幻编辑器的详细信息面板中查看演员的当前角色和远程角色:

Get Actor's Role | Remoter Role

1
2
3
4
5
6
AMyActor* MyActor;
...
// Once you have a valid Actor pointer...
const ENetRole LocalRole = MyActor->GetLocalRole();
const ENetRole RemoteRole = MyActor->GetRemoteRole();
...

Actor Role States

由定义在EngineTypes.h中的ENetRole enumeration 来表示. 共有四种(具体的使用情况后面有个表, 可以更好的解释):

Net Role State Description
ROLE_None 不可复制, 没有角色
ROLE_SimulatedProxy 该Actor的模拟代理。该Actor模拟真实状态,但无权更改状态或call remoter function
ROLE_AutonomousProxy 该Actor的自治代理。该Actor模拟真实状态,并有权更改状态和调用远程函数
ROLE_Authority 权威控制, 一般只能在server中

Matrix of Roles for Client-Server

四种属性各是什么意思, 看这个表就懂了:

Local Role Remoter Role Server or Client Description
ROLE_Authority ROLE_AutonomousProxy Server 服务器上查local是Authority, 客户端是自治
ROLE_AutonomousRroxy ROLE_Authority Client 客户端控制Pawn, 服务器更新这个Pawn, 类似于玩家直接操作的角色
ROLE_SimulatedProxy RPLE_Authority Client 这个客户端上别人的角色
ROLE_Authority ROLE_None Client 特定的NPC, 每个客户端维护自己的NPC, 压根不上传

Actor Replication Simulation

简单来说, 按照AActor::NetUpdateFrequency中设置的频率, actor每次更新之间客户端会经历一段时间, 这段时间内服务器会模拟Actor的角色.

详细参考Networked Movement in the Character Movement Component

Role and Remote Role Reference

参考https://docs.unrealengine.com/5.3/en-US/actor-role-and-remote-role-in-unreal-engine/最后部分.

Actor Netwrok Dormancy(休眠)

合理运用Dormancy机制, 是多人游戏项目的重要优化.

Note: 唤醒休眠的 Actor 会通过复制其复制属性的所有当前值来重新初始化 Actor 的shadow state(用于比较哪些属性已更改且需要复制的状态)。这也是为什么 Actor 的复制状态在休眠时不应更改,因为当 Actor 被唤醒时,在比较其复制属性时不会检测到这些更改。

How to Use

  1. Set the actor in its constructor:
    1
    NetDormancy = ENetDormancy::DORM_DormantAll;
  2. Set the actor if the actor is placed in the map:
    1
    NetDormancy = ENetDormancy::DORM_DORM_Initial;
  3. while Dormancy, will not replicate
  4. To Replicate the actor, befor that, call AActor::FlushNetDormancy, AActor::ForceNetUpdate or AActor::SetNetDormancy::DORM_Awake
  5. 对于复制的comp或者actor, 必须要先刷新或者唤醒拥有的Actor, 才能改变复制的属性

NOTE:
1. actor的复制状态在休眠时不应更改,因为当actor被唤醒时,这些更改可能会丢失。 这意味着不经常改变其复制属性的参与者是休眠的良好候选者。 需要频繁更新的 Actor(例如 pawn)不太可能受益,并且由于更改或刷新 Actor 的休眠状态的额外开销,过于频繁地执行此操作可能比仅保持 Actor 清醒的性能更低。

2.虽然复制的 Actor 的 Actor 通道在休眠时会关闭,但休眠的 Actor 仍然存在于服务器和客户端上。 这与 Actor 相关性(Actor Relevancy)的处理方式不同:动态、复制的 Actor 在不再相关时会在客户端上被销毁. 值得注意的是,不会检查休眠 Actor 的相关性,因此,如果休眠 Actor 在客户端上失去相关性,它不会在该客户端上被销毁(除非您使用带有 Net.RepGraph.DormantDynamicActorsDestructionReplication Graph控制台变量已启用)。

Network Dormancy States

In EngineTypes.h -> ENetDormancy:
- DORM_Never: 从不休眠
- DORM_Awake: 清醒
- DORM_DormantPartial: 在某些连接上休眠, 使用AActor::GetNetDormancy确定连接状态
- DORM_Initial: Actor最初在所有连接上都处于休眠状态, 只能用于一开始就在地图上的Actor.
- DORM_DormantAll: 该Actor在所有连接上都处于休眠状态.

Wake a Dromant Actor

主要有两种方法:

  1. Set the Net Dormancy Property:
    1
    2
    3
    // This is useful in cases where a dormant actor is going to begin changing every frame, such as a stationary object beginning to move.
    AActor::SetNetDormancy(ENetDormancy::DORM_Awake); // 唤醒
    AActor::SetNetDormancy(ENetDormancy::DORM_DormantAll); // 重新休眠
  2. Call the Flush Net Dormancy Function:
    > 通过调用 Actor 上的 AActor::FlushNetDormancy 来复制休眠 Actor 的更改。这迫使Actor将至少一个更新复制到与其相关的所有连接,而不实际更改其休眠状态. 有一个例外,如果您在 AActor::NetDormancy 设置为 ENetDormancy::DORM_Initial 的 actor 上调用 AActor::FlushNetDormancy ,则调用 AActor::FlushNetDormancy 将 actor 的休眠状态更改为 ENetDormancy::DORM_DormantAll
    > 在休眠 Actor 上调用 AActor::ForceNetUpdate 也会调用 AActor::FlushNetDormancy,同时还确保在下一次网络更新时考虑复制该Actor。这对于在单个帧中发生的演员的不频繁、一次性更新非常有用。
    > 在清除 Actor 的休眠状态后(或者在唤醒后将其设置为休眠时),Actor 可能会发送多个更新,因为它不会立即变为休眠状态。相反,参与者会继续复制,直到它及其子对象不再有应发送的未确认的更改为止。如果启用休眠迟滞,它还会阻止 actor 立即进入休眠状态(请参阅 UActorChannel::ReadyForDormancyFObjectReplicator::ReadyForDormancy )。

Actor Priority

虚幻引擎不保证所有 actor 在网络更新期间进行复制。当网络带宽不足时, 首要满足高优先级Actor的Replicate.

Obtain an Actor's Priority

默认AActor优先级为1.0, APawn && APlayerController优先级为3.0 每个参与者都有一个浮点 AActor::NetPriority 属性。但NetPriority 是用于低带宽或饱和连接的Baseline。 AActor:GetNetPriority 根据许多因素确定演员的当前优先级,包括NetPriority 、与观看者的距离以及自上次复制以来的时间。

您可以通过重写 AActor 派生类中的 GetNetPriority 以及使用 NetPriority 更改基本网络优先级来自定义参与者优先级。(特殊情况下才改, 需要对源码的理解).

How Priority is Determined

Actor network priority is based on the following input parameters:

  • ViewPos: 观察者的位置
  • ViewDir: 观察者面对的方向
  • Viewer: twork object owned by the client for whom network priority is being determined. This is usually a Player Controller.
  • ViewTarget: Actor currently viewed or controlled by Viewer. This is usually a Pawn.
  • InChannel: Channel on which this actor is being replicated.
  • Time: 自上次复制该Actor以来的时间
  • bLowBandwidth: True if the viewer has low bandwidth.

Priority Logic
AActor::GetNetPriority的大部分工作是根据观察者的距离和视线以及自当前参与者上次复制以来的时间来计算常数AActor::NetPriority的乘法因子:

  1. 如果以下两个条件都成立,则当前参与者使用其所有者的网络优先级:
    • The current actor has an owner.
    • The current actor is set to use its owner's network relevancy
  2. 如果至少满足以下条件之一,则当前参与者的网络优先级增加:
    • The current actor is the current connection's pawn.
    • The current connection's pawn is the instigator of some action.
  3. 如果前两点都不是这种情况,则执行基于距离的计算以确定当前参与者的网络优先级:
    • 如果当前Actor位于viewer前面,则优先级与设定距离成反比降低。(这个前面怎么定义?)
      • 如果当前actor和观看者之间的距离大于 CLOSEPROXIMITY 但小于 NEARSIGHTTHRESHOLD ,则优先级乘以 0.2
      • 如果当前actor和视图之间的距离大于NEARSIGHTTHRESHOLD,则优先级乘以 0.4 。
    • 如果当前演员和观看者之间的距离小于 FARSIGHTTHRESHOLD 并且观看者正在看着当前演员,则优先级乘以 2.0
    • 如果当前角色和视图之间的距离大于 MEDSIGHTTHRESHOLD ,则优先级乘以 0.4

Threshold constants(NetWorkingDistanceConstants.h):

  • CLOSEPROXIMITY: 500
  • NEARSIGHTTHRESHOLD: 2000
  • MEDISGHTTHRESHOLD: 3162
  • FARSIGHTTHERESHOLD: 8000

Actor Relevancy

当动态生成的复制Actor不再相关时,它们将在客户端被销毁。这就是为什么在这种情况下次要参与者对主要参与者不再可见。

在逻辑性判断中: The Game Network Manager (AGameNetworkManager) is set to use distance-based relevancy.

自定义相关性设置:

参考连接https://docs.unrealengine.com/5.3/en-US/actor-relevancy-in-unreal-engine/