UE4 | 多人游戏装备#5 | 服务器与客户端之间的信息传输


在本文中,我们将考虑使用C ++实现的虚幻引擎4中的服务器和客户端之间的数据传输。 从一开始,对于一个没有受过专业教育的人来说,这似乎是一件难以理解的事情。 尽管有大量的示例和分析,但对我个人而言,很难对此过程进行完整的描述。 但是,当达到通过阅读和测试所获得的关键信息量时,就可以理解这一切是如何工作的。




首先,您需要清楚地了解游戏中的所有对象(极少数例外)都可以具有多个副本。 原始对象位于服务器上。 原来总是在那里。 副本可以存在于客户端上,但根本不存在,即 他们可能不是。 所有重要事件都发生在服务器上,由谁来决定谁需要了解它,而谁则不知道。

除客户端外,其他任何人都不知道客户端上发生的所有事情。

例子

我们从两个客户开始游戏。 舞台上有一个多维数据集,此多维数据集的原始文件位于服务器上。 他是最重要的。 第一个副本将位于第一个客户端上,第二个副本将位于第二个客户端上。 如果我们在其任何客户上对对象进行复制,那么原始对象将不会受到影响 。 更改将完全是本地的,仅适用于此客户。 如果您更改原始文档,则有两种主要方案:


  1. 客户的副本将保持不变。
  2. 客户的副本将与原始副本同步。



既然游戏的基本规则已经明确,我们可以考虑为服务器和客户端之间传输信息提供哪些选择。 我知道3种方法,但是我们只考虑前两种方法,因为 第三个允许您随时随地传输任何内容,并且仅在您受前两个限制的情况下才适用。


  1. 复写
  2. RPC( 远程过程调用 )。
  3. TCP协议


    复写


首先要无条件接受:

复制是单向的,只能从服务器到客户端。
您需要知道的第二件事:
只能复制对象或类变量。
第三,重要条件:
仅当服务器上发生更改时,复制才会发生。

如果在Blueprint中我们只是在正确的地方打勾,那么C ++并不会复杂得多。 最重要的是不要忘记包含#include“ UnrealNetwork.h”

首先,考虑对象复制。
在构造函数中,我们编写:


bReplicates = true; 

如果我们要复制运动:


 bReplicateMovement = true; 

如果需要复制连接的组件:


 Component->SetReplicates(true); 

完整的描述可以在这里找到。


使用变量复制,事情会更加有趣。
让我们从.h头文件开始。
您可以简单地复制变量:


 UPROPERTY(Replicated) bool bMyReplicatedVariable; 

或者,如果变量已复制,则可以在客户端运行某些功能。 变量取什么值都没有关系。 其变化的事实很重要。


 UPROPERTY(ReplicatedUsing = OnRep_MySomeFunction) TArray<float> MyReplicatedArray; UFUNCTION() void OnRep_MySomeFunction(); 

运行功能只是从服务器发送命令的方法之一。 重要的是要知道,阵列的复制不会完全发生,而只会发生更改的部分。 因此,只需一个变量,您就可以从服务器发送许多命令,将数组解析为元素,并将元素解析为位。


现在让我们继续.cpp
我们编写复制条件:


 void AMySuperActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(AMySuperActor, bMyReplicatedVariable); DOREPLIFETIME_CONDITION(AMySuperActor, MyReplicatedArray, COND_OwnerOnly); } 

第一个变量bMyReplicatedVariable无条件地立即复制到所有Client,而第二个变量MyReplicatedArray仅针对拥有AMySuperActor对象的Client更新,除非被声明为一个。


可能条件的完整列表可以在此处找到。




RPC( 远程过程调用


与复制不同, 这种数据传输方法可以双向运行,但价格昂贵。 要使用它,您只需连接#include“ UnrealNetwork.h”

一个重要的功能是可以使用RPC方法传输变量。
首先,必须说RPC附带了对Reliable的认可,并且没有Unreliable 。 如果在第一种情况下,发件人直到确信包裹已交付(如果没有互惠消息便会一次又一次地发送)后才冷静下来,则在第二种情况下,发件人不在乎有人是否收到包裹。 发送并忘记了。
尽可能使用“ 不可靠” 。 通常,此方法适用于不太重要的信息或频繁更新的数据。 如上所示,在不可能从服务器发送到客户端的情况下,我们尝试通过函数调用进行复制。

因此,要将我们的软件包从客户端发送到服务器,您需要注册三个功能:


 UFUNCTION(Reliable, Server, WithValidation) void ServerTestFunction(float MyVariable); void ServerTestFunction_Implementation(float MyVariable); bool ServerTestFunction_Validate(float MyVariable); 

可靠 -带有回执的包裹。
服务器 -从客户端发送到服务器。
WithValidation-仅当满足bool ServerTestFunction_Validate(float MyVariable)函数中描述的条件时,收件人才打开包。 也就是说,如果函数返回true 。 仅在服务器上执行的功能才需要此参数。
ServerTestFunction(float MyVariable) -如果要向服务器发送内容,则由客户端调用此函数。 通常,甚至不需要在.cpp中对其进行描述。
ServerTestFunction_Implementation(浮动MyVariable) -仅在以下情况下,将直接在服务器上调用此函数:
ServerTestFunction_Validate(float MyVariable) -在服务器上执行此函数,如果返回true ,则将调用ServerTestFunction_Implementation(float MyVariable)


要将包从服务器发送到客户端,如果我们对复制的使用感到绝对不满意,则实质上只有服务器更改为客户端


 UFUNCTION(Reliable, Client, WithValidation) 

这些函数的名称原则上可以是任意的,但通常它们应反映软件包的运行位置。 为了我们的方便。


 UFUNCTION(Reliable, Client, WithValidation) void ClientTestFunction(float MyVariable); void ClientTestFunction_Implementation(float MyVariable); bool ClientTestFunction_Validate(float MyVariable); 

否则,考虑到这次软件包从服务器到客户端的事实,它的工作方式与上一个示例完全相同。


当程序包一次发送到所有客户端时,还有一个从服务器发送的选项。


 UFUNCTION(Reliable, NetMulticast, WithValidation) void NetMulticastTestFunction(); void NetMulticastTestFunction_Implementation(); bool NetMulticastTestFunction_Validate(); 

不要滥用此选项。 考虑一下如何管理复制。

对于客户端NetMulticast,验证是可选的



服务器请求实现示例
 /*       ,     */ void ADreampaxActor::DoSomethingWithOtherActor(ADreampaxOtherActor * SomeOtherActor) { /*  ,      */ if (Role < ROLE_Authority) { /*    ,    ,      */ ServerDoSomethingWithOtherActor(SomeOtherActor); /*   ,        */ return; } /*         */ SomeOtherActor->Destroy(true); } /*      ,    ServerDoSomethingWithOtherActor(SomeOtherActor)     */ void ADreampaxCharacter::ServerDoSomethingWithOtherActor_Implementation(ADreampaxOtherActor * SomeOtherActor) { /*   ,       */ DoSomethingWithOtherActor(SomeOtherActor); } /*     ,    ServerDoSomethingWithOtherActor_Implementation(ADreampaxOtherActor * SomeOtherActor) */ bool ADreampaxCharacter::ServerDoSomethingWithOtherActor_Validate(ADreampaxOtherActor * SomeOtherActor) { /*      true,   ,   -    fasle.       */ return true; } 

最后,是手册的链接,必须阅读。
“虚幻引擎4”网络纲要


这是您需要了解的有关服务器与客户端之间的通信的所有信息,以便继续进行下一部分,在该部分中,我们将写下清单的复制并考虑如何正确对其进行更改。


PS:如果您发现任何不正确或错误,请在评论中写。

Source: https://habr.com/ru/post/zh-CN420233/


All Articles