跳至主要內容

NT-2.1|变量复制

Mr.Si大约 4 分钟unreal

前情提要

头像
前文,咱们已经解决了客户端SpawnActor服务端不显示的问题。

解决流程

BP

头像
定义一个在服务器上调用的事件,并确保Actor本身可以复制。
GIF

C++

   // .h
   UFUNCTION(Server, Reliable)
   void ServerSetHealth();

   // .cpp
   void AMyActor::ServerSetHealth_Implementation()
   {
     //spawn的代码
   }

本章导读

头像
我修改了角色的速度,也调用了服务器上执行。为什么客户端上一卡一卡的?
GIF
头像
速度是角色移动组件的属性
头像
官方并没有个速度这个变量搞成可复制的。虽然你现在RunOnServer,并没有同步给其他客户端。
GIF

BP|Multicast

头像
也就是说,RPC申请在服务器上调用,还需要广播给所有客户端?
头像
没错。

C++|Multicast

   // .h
   UFUNCTION(Server, Reliable)
   void ServerSetHealth();

   // .cpp
   void AMyActor::ServerSetHealth_Implementation()
   {
     MulticastFunction();
   }
    // 在 .h 
    UFUNCTION(NetMulticast, Reliable)
    void MulticastFunction();

    // 在 .cpp 
    void AMyActor::MulticastFunction_Implementation() 
    {
    //实现移动逻辑。
    }
   

变量复制

头像
为什么这里的速度不复制也能正常运行?
头像
速度虽然没有同步,但在所有端的变化量是一致的。
头像
现在可以将其中一个变量提取出来,设置成所谓MaxSpeed。用一个按键改变速度,你就会发现猫腻。
头像
服务器才有权威,没毛病。
变量没有复制
变量没有复制
GIF
头像
可以看到虽然客户端速度降下来了,但还是一抽一抽的。现在我们开启变量的复制功能,

BP

变量|Replicated

开启复制后,变量右上角会出现两个泡泡。

GIF
头像
可以看到抽搐消失了,请忽略我们的动作还是跑步,因为目前的角色并不是速度驱动动作的。

变量|RepNotify

头像

至于RepNotify,是指该变量发生变化时会触发一个回调函数,同时在服务器和客户端机器上执行此函数。

GIF
头像
例如OnRep_PlayerState这种就是RepNotify

C++

C++:在服务器中更改 OnRep 变量时,仅当变量的值发生更改时,才会在客户端上触发 OnRep 行为。 服务器不会触发 OnRep,这意味着如果我们希望在服务器中执行 OnRep 行为,我们必须从服务器显式调用它。

蓝图:当我们在服务器中设置 OnRep 变量时,OnRep 行为将始终在服务器上触发(即使变量的值没有更改)。 但是,仅当 OnRep 的变量发生更改时,才会在客户端上触发 OnRep 行为。此外,无法显式调用由 OnRep 变量创建的 OnRep 函数。

C++|Replicated

// 在 .h 文件中声明 MyVariable 变量
UPROPERTY(Replicated)
float MyVariable;

// 在 .cpp 文件中设置变量同步
void AMyActor::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const {
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);
    DOREPLIFETIME(AMyActor, MyVariable);
}

C++|RepNotify|OnRep

// 在 .h 文件中声明 MyVariable 变量
UPROPERTY(ReplicatedUsing = OnRep_MyVariable)
float MyVariable;

// 在 .cpp 文件中设置变量同步,并声明 OnRep_MyVariable 函数
void AMyActor::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const {
   Super::GetLifetimeReplicatedProps(OutLifetimeProps);
   DOREPLIFETIME_CONDITION_NOTIFY(AMyActor, MyVariable, COND_SkipOwner, REPNOTIFY_Always);
}

// OnRep_MyVariable 函数将在 MyVariable 发生变化时被调用
void AMyActor::OnRep_MyVariable() {
   // 在这里添加在变量改变时执行的逻辑
   UE_LOG(LogTemp, Warning, TEXT("MyVariable changed to: %f"), MyVariable);
}

C++|DOREPLIFETIME变量的复制规则

DOREPLIFETIME:

DOREPLIFETIME(ClassName, VariableName);

这个宏用于声明一个类的变量需要在网络上进行复制。它会自动生成必要的复制代码。

DOREPLIFETIME_CONDITION:

头像
当然,这里的通知可以限定一些行为,比如谁才能收到。
DOREPLIFETIME_CONDITION(ClassName, VariableName, ReplicationCondition);

这个宏也用于声明一个类的变量需要在网络上进行复制,但允许添加一个额外的条件。ReplicationCondition 是一个用于判断是否进行复制的布尔表达式。只有在这个表达式为真时,复制才会发生。

示例:

DOREPLIFETIME_CONDITION(AMyActor, MyVariable, COND_SkipOwner);
条件标签描述
COND_InitialOnly仅在初始数据组尝试发送
COND_OwnerOnly仅发送至 actor 的所有者
COND_SkipOwner发送至除所有者之外的每个连接
COND_SimulatedOnly仅发送至模拟 actor
COND_AutonomousOnly仅发送给自治 actor
COND_SimulatedOrPhysics发送至模拟或 bRepPhysics actor
COND_InitialOrOwner发送初始数据包,或者发送至 actor 所有者
COND_Custom没有特定条件,但需要通过 SetCustomIsActiveOverride 开启/关闭能力