【UE】虚幻网络同步

UE网络官方文档链接:https://docs.unrealengine.com/5.2/zh-CN/networking-overview-for-unreal-engine/

虚幻的网络模式

【UE】虚幻网络同步_第1张图片
服务器作为游戏主机,保留一个真实授权的游戏状态。换句话说,服务器是多人游戏实际发生的地方。客户端会远程控制其在服务器上各自拥有的 Pawn,发送过程调用以使其执行游戏操作。但服务器不会将视觉效果直接流送至客户端显示器。服务器会将游戏状态信息 复制 到各客户端,告知应存在的Actor、此类Actor的行为,以及不同变量应拥有的值。然后各客户端使用此信息,对服务器上正在发生的情况进行高度模拟。
服务器是游戏真正运行的地方,但我们要让客户端的场景看似发生了相同事件。因此,需要选择性地向各客户端发送信息,以在服务器上创建场景的视觉代表。

Actor复制(Actor Replication)

Actor是实现复制的主要推动者。服务器将保留一份 Actor 列表并定期更新客户端,以便客户端保留每个 Actor (那些需要被同步的Actor)的近似复本。
要想让一个Actor参与网络复制,必须将这个Actor的bReplicates设置为true,告诉引擎你需要复制这个Actor。这相当于一个总开关。
蓝图中将Replicates勾上即可
【UE】虚幻网络同步_第2张图片

C++中要需要在构造函数中将bReplicates标记设置为true

MyClass::MyClass( const class FPostConstructInitializeProperties & PCIP ) : Super( PCIP )
{
    bReplicates = true;
}

当你设置一个Actor的bReplicates=true后,服务端会在UNetConnection中创建一个ActorChannel,从而将该Actor复制到对应的客户端。
Actor主要的更新方式有两种
1、Property Replication(属性复制)
2、RPC(远程过程调用)

  • 属性复制和 RPC 的主要区别在于,属性可以在发生变化时随时自动更新,而 RPC 只能在被执行时获得调用更新。

属性复制(Property Replication)

属性复制有两种方式,Replicated和RepNotify,属性同步的前提是已经开启Actor复制
【UE】虚幻网络同步_第3张图片

Replicated

蓝图

直接将该变量的Replicated勾选上即可
【UE】虚幻网络同步_第4张图片

C++

1、在属性的UPROPERTY中添加replicated

UPROPERTY(VisibleAnywhere, Replicated)
float health;

2、在类中重写GetLifetimeReplicatedProps函数,添加DOREPLIFETIME( 类名, 变量名 )

void ATestCppActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);
    DOREPLIFETIME(ATestCppActor, health);
}

案例

创建一个第三人称的C++UE项目
创建一个TestCppActor类,继承自Actor,添加一个health属性
将health设置为Replicated,仅在服务端修改health的值,查看客户端和服务端的值是否都被修改

// Called when the game starts or when spawned
void ATestCppActor::BeginPlay()
{
    Super::BeginPlay();
    if(HasAuthority())
    {
       health = 500.f;
    }
}
// Called every frame
void ATestCppActor::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
    if(HasAuthority())
    {
       UE_LOG(LogTemp, Log, TEXT("Server is %f"), health)
    }
    else
    {
       UE_LOG(LogTemp, Log, TEXT("Client is %f"), health)
    }
}

需要在关卡蓝图中生成一下这个Actor
【UE】虚幻网络同步_第5张图片

结果就是客户端和服务端的该数据都被同步修改了,这就是属性复制的功能
【UE】虚幻网络同步_第6张图片

RepNotify

RepNotify功能和Replicated基本相同,不同点就是RepNotify需要绑定一个属性变化后的函数,在属性发生变化后会调用绑定的函数

蓝图

选择属性复制方式为RepNotify,会自动生成OnRep_属性名 的函数,该函数会在属性发生改变后调用
【UE】虚幻网络同步_第7张图片
C++
在C++中使用对应 ReplicateUsing 说明符

    /** 玩家的当前生命值。降到0就表示死亡。*/
UPROPERTY(ReplicatedUsing=OnRep_CurrentHealth)
float CurrentHealth;

/** RepNotify,用于同步对当前生命值所做的更改。*/
UFUNCTION()
void OnRep_CurrentHealth();

ReplicateUsing表示该属性被复制,OnReq_CurrentHealth就是该属性发生变化后会调用的函数,该函数必须要有UFUNCTION()标记
注意:C++版本RepNotify仅在客户端调用函数

案例

创建一个ARepNotify类,继承自Actor,添加如下图功能
设置Health为属性同步,OnRep_Health为属性改变后的调用函数,在Server端的Tick中不停改变Health的值,在调用函数中打印改变后的值
【UE】虚幻网络同步_第8张图片

同样,需要先在关卡蓝图中生成下Actor,运行结果显示仅调用了Client端的函数,符合C++版本的预期(C++版本RepNotify仅在客户端调用函数)
【UE】虚幻网络同步_第9张图片

Actor权限说明

Server中有个Actor(黄色笑脸),Client A中有个Actor(蓝色笑脸),Client B中有个Actor(绿色笑脸),这些Actor在服务端和客户端的权限如下图
【UE】虚幻网络同步_第10张图片

三种ROLE(本地角色)
Authority: 权威(有对Actor的控制权)
各个Actor在服务端的状态
SimulatedProxy: 模拟代理
当前客户端Actor在其他客户端的状态
AutonomousProxy: 自主代理
当前客户端Actor在当前客户端的状态
Remote_ROLE(远端角色)

远程调用(RPC)

【UE】虚幻网络同步_第11张图片

【UE】虚幻网络同步_第12张图片

蓝图

CustomEvent可以设置RPC,普通函数不可以

  • 蓝图中通过设置函数的Replicates属性
    【UE】虚幻网络同步_第13张图片

C++

任何UFUNCTION都可以指定为Client,Server或者NetMulticast使得一个函数变成一个RPC。

UFUNCTION( Client, Reliable )
void ClientRPCFunction();

可靠性

RPC同时可以声明为可靠的(Reliable)或者不可靠的(Unreliable),可靠RPC在带宽饱和的情况下不会被丢弃,保证按调用顺序发送到,适用于比较重要的函数调用。不可靠的RPC不能保证被发送到,更不能保证按顺序发送到。
不可靠RPC虽然无法保证必会到达预定目的地,但其发送速度和频率高于可靠的RPC。其最适用于对gameplay而言不重要或经常调用的函数。例如,由于Actor移动每帧都可能变换,因此使用不可靠RPC复制该Actor移动。
可靠的RPC保证到达预定目的地,并在成功接收之前一直保留在队列中。其最适合用于对gameplay很关键或者不经常调用的函数。相关例子包括碰撞事件、武器发射的开始或结束,或生成Actor。

案例

以下的案例都是LS模式,3个玩家
【UE】虚幻网络同步_第14张图片

Server

客户端调用,在服务端运行
首先创建一个BP_CubeActor,继承自Actor,添加一个SkenetalMesh,并在SkeletalMesh上添加一个任意骨架(只要能看到就行),再将Actor复制打开
【UE】虚幻网络同步_第15张图片

先在服务端的角色头部位置生成一个CubeActor,参考下方第二个图,因为服务端有所有角色的控制器,如果只想在服务端控制的角色生成Cube,则需要通过IsLocallyControlled判断一下
【UE】虚幻网络同步_第16张图片

【UE】虚幻网络同步_第17张图片

我们知道,在客户端生成Actor的时候,服务端和其他客户端时看不见的,因为没有同步这个信息给服务端

如果要在客户端控制的角色的头部位置生成CubeActor的话,需要使用RPC中的Server,先判断角色是不是ROLE_AutonomousProxy权限(原因同上),然后执行SpawnCube函数,SpawnCube函数需要时RunOnServer模式,这样客户端角色需要生成CubeActor的时候,会告诉服务端,服务端去帮忙生成CubeActor
【UE】虚幻网络同步_第18张图片

Multicast

服务端运行,发送给所有客户端
创建一个自定义事件Multicast_Test,设置为Multicast
【UE】虚幻网络同步_第19张图片

为了方便测试,直接搞个AnyKey,调用Multicast_Test
【UE】虚幻网络同步_第20张图片

运行项目后,在服务端点击右键,你会发现所有客户端和服务端都执行了该函数
【UE】虚幻网络同步_第21张图片

Client

客户端调用,服务端运行,发送给拥有此Actor的客户端
和Multicast一样,创建一个自定义事件Client_Test,设置为Run on owning Client
【UE】虚幻网络同步_第22张图片

运行项目后,在 客户端/服务端 点击右键,你会发现仅有你点击右键的 客户端 执行了该函数
[图片]

你可能感兴趣的:(虚幻引擎,虚幻引擎,ue5)