UE4 网络 Replicate,ActorRemote,OwnerShip,RPC

(一定得模拟测试,方才能get到!)

I. Replication

Replication指的是 ***从服务端向客户端*** 传递数据和信息的行为。注意是单向的,不会从客户端传递信息和数据到服务端。

假设一个Actor被设置为Replicates, ***当且仅当它被服务端生成*** ,那么它会被所有客户端生成,并被Replicated。言外之意,即使是Replicates的Actor,如果在某个客户端生成,它也只会在本客户端生成,是 不会在其他客户端或者服务端生成 的,自然也谈不上Replication。

还有一种情况容易让人糊涂:假设在Pawn类中的Authority端生成一个Actor,并且把它存为变量,那么这个变量的Replicates属性和这个Actor本身的Replicates属性是什么关系?实际上,这里变量只是指向这个Actor的一个引用/指针,掌握住这点就好理解了。如果这个Actor没有Replicates,而让这个指针Replicates,那么它在客户端上就会指向一个NULL,这个并不会让引擎崩溃,但是没有任何意义。如果Actor Replicates,但是指针不是Replicated,那么在客户端这个Actor是存在的,但是指针没办法指向正确的对象。所以这种情况下需要Actor和变量都是Replicates(ed)才能达到正确的效果

另外,GameMode是不会Replicates的,它只存在于服务端,所以对它存储的变量设置Replicated没有任何意义。

那么再考虑一下,如果这个Actor在编辑阶段就被置于场景中呢,它在多人联网的情形下是什么状况?

我做了以下几个实验来逐步分析:

(以下实验如无特殊说明,均采用默认的第三人称场景,Play选项Number of Players选择2,New Editor Window(PIE))

实验1:Actor不勾选Replicates,直接放置于场景中,初始一个随机速度运动

结果:客户端和服务端都各自以各自的速度运动,证明这两个物体在不同的instance上是独立的,互无关联的。

实验2:Actor勾选Replicates,但不勾选Replicate Movement,直接放置于场景中,初始一个随机速度运动

结果:和实验1一样。那么大家可能就会怀疑,这种情况下是不是和实验1是完全一样的?实际上和实验1有很大的区别,这个Actor有了Replication,也就可以进行属性的Replicates和RPC调用,而实验1里的Actor就不可能进行这些操作。

实验3:Actor勾选Replicates,勾选Replicate Movement,直接放置于场景中,初始一个随机速度运动

结果:虽然初始化了不同的速度(print出来了),但是服务端和客户端运动基本上是同步的,只是客户端的运动会有些许“抖动”。出现这种情况的原因是客户端“想”以自己的速度去运动,但是由于更新了Replicate Movement,服务端会以固定的频率去把自身的位置同步给客户端,因此客户端会在更新的瞬间跳跃到服务器指定的位置,从而产生了抖动。

放置于场景中的Actor的情况我们搞清楚了,再来考虑一下更麻烦的——动态生成:

实验4:我们先在LevelBlueprint的BeginPlay中直接生成Actor,这个Actor是实验2的,也就是Actor勾选了Replicate,但并不同步移动。

结果:服务端有一个Actor,客户端有2个Actor,并且3个Actor均以不同的速度在运动。不难理解,因为在LevelBP中生成,所以服务端生成了一个,但是这个Actor是Replicates的,所以被复制到客户端,同时客户端本身的LevelBP中也生成了一个,所以客户端有两个。

所以如果要在LevelBlueprint中生成Replicates的Actor,一定要在前面加上Switch has authority,并在Authority后面生成。

上述几个实验的工程源码存放在这里

II. Ownership

所谓“Own”(拥有)的主语其实是一个“连接”的实例或者PlayerController。

每个“连接”的实例肯定会Own(拥有)一个PlayerController

那么决定一个Actor是否被拥有,就是向上查找他的Ownership结构树,找到最上层的拥有者,如果是个PlayerController,它就被这个PlayerController以及它的“连接”所拥有。

最典型的的例子,一个Pawn被PlayerController Possess的时候它就被Owned。如果它被Unposses了,Ownership也就丢失了。

那么一个普通的Actor能不能被“拥有”呢?答案是可以的,使用Set Owner方法就可以让他被某个PlayerController拥有。

为什么要强调Ownership呢?

  • 后面我们将描述这个问题:RPC需要决定在哪个客户端执行 Run on Client的 RPC
  • Actor网络复制和连接的Rlevancy(相关性)
  • 牵扯到Owner时候的property Replication条件

III. Actor Role 和 Remote Role

Actor Role在我的 这篇文章 里已经很详细的描述过了,这里做一下补充:

Actor Role 和 Remote Role是一组相对的概念,Actor Role指的是在本地的角色,Remote Role指的是远程端的角色。这里的“远程端”有点tricky,容易误解,我也是糊涂了很久才明白。

设想有一个服务端加两个或两个以上的客户端,那么所谓的“远程端”到底指的是在哪个“端”?实际上我们只需要分两个“端”,一个服务端,一个客户端,把所有的客户端都看成一端,这个问题的答案就很显而易见了。

另外 官方文档专门说明了, “目前,仅服务端可以负责同步信息到客户端,因此仅服务端可以看到Role=Authority,并且RemoteRole=Simulated_Proxy或者Autonomous_Proxy”,这个“目前”说的是目前的网络构架。

总之,只有服务端才可能有Authority,所有Replicates的Actor在服务端的Role都是Authority,要牢记这点。(非Replciates的有没有Authority?有待验证)

实际上,Simulated_Proxy和Autonomous_Proxy讲的是两种同步模式(Mode of Replication),因为服务器不可能每一帧都去把信息同步给所有客户端,而是以一定的频率去下发信息,那么两次下发之间的空白怎么填补呢?虚幻设计了两种同步的模式:

Simulated_Proxy是标准模式,用最后的速度和位置去移动物体.(使用最后的速度只是一种算法,你也可以实施自己的算法)

Autonomous_Proxy基本上只会用于被PlayerController 所Possess的对象(那就是被Possess的Pawn啦),那么在空白期间就直接用用户的操作来填补。

看到这里,我们需要明确两点:

1、Autonomous_Proxy就是Pawn(当然说的是被Possess的)在本客户端的Role——目前我能想到仅有这一种情况。它的RemoteRole——也就是在服务端的Role是Authority,它在其他客户端的Role是Simulated_Proxy。

2、而任何非Pawn的Actor,在服务端的Role都是Authority,他们的RemoteRole都是SimulatedProxy。

在C++中可以使用Role==XXX来判断一个Pawn的Role,但是在蓝图中我们可能需要分两步来进行:首先判断是否has authority,如果是,则是服务端,如果否,还要继续判断pawn是否isLocallyControlled,如果是,则是Autonomous_Proxy,如果否则是Simulated_Proxy。

IV. Actor Role和Ownership的关系

很重要的一点, Actor Role 和 Ownership没有任何关系 ,是不同的概念。

只是很巧合,Autonomous_Proxy肯定会被Own,但不能说被Own了就一定是Autonomous_Proxy,例如我们可以对一个非Pawn的Actor 设置所有者(Set Owner),但是它的Actor Role没有改变。

V. RPC

    RPC本质是用来调用在 另外一个游戏实例上的函数的 。
    RPC无法获取返回值 ,这就是为为什么没办法把蓝图中的Function设置为RPC的原因,因为Function是可以带返回值的。而CustomEvent是没法设置返回值的,所以RPC只能标记在CustomEvent上。
    RPC分三种,Run on Server,Run on owning Client,NetMulticast
    RPC必须在Actor或者其子类上调用
    Actor必须是Replicated的(否则不存在RPC一说)
  1. Run on Server

    表示在Actor的服务端实例上执行。
    如果RPC是从客户端调用,让其在服务端执行,客户端必须 Own(拥有) 这个Actor。
    
  2. Run on owning Client

    表示在Actor的Owner上执行。
    
    如果RPC是从服务端调用,让其在客户端执行,只有 Own(拥有) 这个Actor的客户端才会执行。
    
    注意Run on Server和 Run on owning Client的条件:客户端必须Own这个Actor,也就是 这个Actor必须有Ownership 。
    
  3. NetMulticast

    表示在Actor的所有实例上执行。
    
    如前所述,前两种RPC模式都要求Actor必须有Ownership。 Multicast是个例外,它不需要OwnerShip 。
    
    如果从服务端调用,服务端会本地执行,所有目前连接的客户端也都会执行。
    
    如果从客户端端执行,则只会本地执行,服务端不会执行,其他客户端也不会执行。
    

    这里写图片描述

    转载于:http://www.cnblogs.com/AnKen/p/8602233.html

猜你喜欢

转载自blog.csdn.net/u012801153/article/details/79638409
今日推荐