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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章