Bootstrap

UE4 RPC

  • 复制是单向的,S—>C;
  • RPC客户端调用是需要有Net Owner(PlayerController,Pawn/Character(被PlayerController控制),PlayerState)

(1)游戏架构

参考: https://docs.unrealengine.com/4.26/zh-CN/InteractiveExperiences/Networking/Blueprints/

    ●GameInstance: 不参与网络复制,作为游戏实例而存在,在关卡切换载入时依然存在,可以用于存储用户本身的数据

    ●GameMode: 只存在于Server上,核心逻辑存在于这里

    ●GameState: 在Server和所有Client之间复制,用于存储当前游戏相关的数据

    ●PlayerController: 每个Client只持有自己的PlayerController,并与Server进行同步

    ●PlayerState: 存储每个Player的信息,会同步到所有的Client。

    ●Pawns: 与所有的Client同步,但是与PlayerController以及PlayerState不同的是,Pawn死亡之后会被销毁,直到Respawn为止。

(2)Role与同步

Server和Client都可以使用Role系统来判断持有的Actor状态,Role被分为四种

    ●ROLE_Authority:对Actor拥有控制权

    ●ROLE_None:不参与网络复制

    ●ROLE_SimulatedProxy:接受来自服务器更新的模拟控制器,使用已知信息进行预判

    ●ROLE_AutonomousProxy:接受来自玩家的直接控制,配合玩家输入进行预判

    客户端的模拟预判可以有效防止网络延迟引起的Lag,但是在处理角色动作,尤其是Blink之类的操作时,依然会导致奇怪的现象。

    为了防止这些现象,官方对CharacterMovmentComponent作了增强,这个类会维护一个动作列表,在同步时,Client会被要求进行动作列表的重放,而不是直接更新位置。参考:https://docs.unrealengine.com/4.26/zh-CN/InteractiveExperiences/Networking/CharacterMovementComponent/

(3)所有权

 

(4)属性回调与RPC

属性回调一定会执行;

RPC可能因为同步问题得不到执行。

(5)RPC与Actor同步谁先执行?

问题:服务器ActorA在创建一个新的ActorB的函数里同时执行自身的一个Client的RPC函数,RPC与ActorB的同步哪个先执行?(原答案不准确已修改)

答案是不确定。

我们可以通过设置控制台变量net.DelayUnmappedRPCs 1允许客户端等到这个对象生成的时候再去执行,但是仅限于可靠的RPC。

(5.1)拥有连接

        一定是客户端第一次链接到服务器,服务器同步过来的这个PlayerController(也就是拥有连接的PlayerController)。进一步来说,这个Controller里面包含着相关的NetDriver,Connection以及Session信息。

       一旦Actor(客户端上)有连接,他的Role(控制权限)就是ROLE_AutonomousProxy,如果没有连接,他的Role(控制权限)就是ROLE_SimulatedProxy 。

参考:

http://www.cppblog.com/flyindark/archive/2017/01/14/214596.html

(6)角色 Net Role

        AActor.Role描述了角色的网络属性,从而决定了rpc和replicated时的行为表现。这3个网络Role属性分别是:

       *ROLE_Authority,

       *ROLE_AutonomousProxy,

       *ROLE_SimulatedProxy

ROLE_Authority,在服务器上的所有角色都是Authority属性;

ROLE_AutonomousProxy,客户端上的本地角色;

ROLE_SimulatedProxy,客户端上的网络角色;

so

服务器上的所有角色都是Authority属性,当前控制的角色可以用IsLocalControlled区分

客户上当前控制的角色具有Autonomous属性,

客户端上的远程角色具有SimulatedProxy属性;

(7)网络模式 Net Mode

       ENetMode AActor.GetNetMode()

NM_Standalone, /** 单机游戏,无网络链接,可以是多玩家,类似于单服务器 */

NM_DedicatedServer, /** 专用服务器,没有本地玩家 */

NM_ListenServer, /** 监听服务器,拥有一个本地玩家. */

NM_Client, /** 客户端,连接到一个服务器;枚举值NetMode < NM_Client即为某种服务器 */

(8)Replicated Data

       Actor中的Replicated数据自动复制到所有客户端上

客户端数据不能复制到服务器,只会在客户端本地生效

so

如果数据定义为replicated,最好仅在server上进心更新,在client上只读,避免引起不必要的混淆。

这样判断端的属性:

    在C++中判断是否为服务器:Role == ROLE_Authority(必要不充分);NetMode < NM_Client(充分必要);

    在BP中判断是否为服务器:HasAuthority(必要不充分);IsServer(充分必要);

(8.1)Replicated Data in C++

#include "Net/UnrealNetwork.h"

UPROPERTY(BlueprintReadOnly,Replicated)

float Health;

------

voidATestNetworkCharacter::GetLifetimeReplicatedProps(TArray< FLifetimeProperty> & OutLifetimeProps) const

{

Super::GetLifetimeReplicatedProps(OutLifetimeProps);

DOREPLIFETIME(ATestNetworkCharacter, Health);

}

如果不包含头文件UnrealNetwork.h会报错:

error C3861: 'DOREPLIFETIME': identifier not found

(9)RPC

事件有3种replication方式

Multicast---在服务器调用,然后自动转到客户端;

Server---被客户端调用,仅在服务器执行;必须在有Net Owner的Actor上使用;

Client---被服务器调用,仅在其所有者客户端执行;必须在有Net Owner的Actor上使用;

(10)Net Owner

       Actor如果是Player controller或被Player Controller所拥有,则此actor有Net Owner;

也就是说除了多播,RPC函数如果想调用成功必须有以下限制条件:

*Actor是一个Player Controller类型;

*Actor被一个Player Controller所拥有(Pawn、Character、PlayerState);

(10.1)您必须满足一些要求才能充分发挥 RPC 的作用:https://docs.unrealengine.com/latest/CHN/Gameplay/Networking/Actors/RPCs/index.html

*它们必须从 Actor 上调用。

*Actor 必须被复制。

*如果 RPC 是从服务器调用并在客户端上执行,则只有实际拥有这个 Actor 的客户端才会执行函数。

*如果 RPC 是从客户端调用并在服务器上执行,客户端就必须拥有(Net Owner)调用 RPC 的 Actor。

;