UE代碼-TArray的屬性同步


1. 相關技術文檔

2. 屬性同步相關源碼位置

  • NetDiver.h/cpp: 服務器在NetDiver的TickFlush里面,每一幀都會去執行ServerReplicateActors來同步Actor的相關內容。
  • UActorChannel.h/cpp: UActorChannel::ReplicateActor執行真正的Actor同步以及內部數據的同步。

3. TArray如何同步

對於一個數組的同步,會先對其進行一個判斷,在初始化RepLayOut的Cmds數組的時候,就會判斷當前的屬性類型是否是動態數組(UArrayProperty),並會給其cmd.type做上標記REPCMD_DynamicArray。

  • 對於靜態數組,是將每個元素都作為一個單獨的屬性,進行同步。
  • 對與動態數組,則是先進行一個長度的判斷,比如服務器上數組長度發生變化,客戶端在接收同步過來的數組時,會執行FRepLayout::ReceiveProperties_DynamicArray_r來處理動態數組,這個函數里面會矯正當前對象同步數組的大小。而若進行刪除或插入操作時,由於TArray是一個連續的數組,所以可能導致后綴一長串的元素往后移或往前移動,而UE4的屬性同步機制會認為,一連串的元素都發生改變,從而同步一長串的數據。

在這個影響下,使用插入刪除TArray的元素時可能會導致一個效率的下降。

解決方法:

  1. 官方給的方案就是用FastTArray來替代TArray的屬性同步了。FastTArray的使用方法見UE4引擎頭文件源碼:NetSerialization.h。
  2. 貪心策略:
    1. 可以減少使用插入刪除操作,用其他方式代替;
    2. 還可以犧牲少部分時間對TArray進行一個優先級的排序,經常插入刪除的元素盡量放在數組后面,這樣受到其影響的后綴長度會盡可能少。

4. FastTArray相關

4.1 原理:

對TArray這種動態屬性實現一個增量序列化,增量序列化是通過比較初始狀態和當前狀態並生成的,並生成一個差異狀態與完全狀態,並更新其為新的初始狀態。

4.2 優缺點:

  • 優點:沒有通過常規的TArray方式同步,避免了從中間刪除元素,會使得后面所有元素都需要重新同步的情況,減少大量開銷。
  • 缺點:當數據發生改變后,不能保證服務端與客戶端中TArray元素順序一致。

4.3 如何使用FastTArray:

/** Step 1: Make your struct inherit from FFastArraySerializerItem */
USTRUCT()
struct FExampleItemEntry : public FFastArraySerializerItem
{
  GENERATED_USTRUCT_BODY()
  // Your data:
  UPROPERTY()
  int32 ExampleIntProperty;
  UPROPERTY()
  float ExampleFloatProperty;
  /** Optional functions you can implement for client side notification of changes to items */
  void PreReplicatedRemove();
  void PostReplicatedAdd();
  void PostReplicatedChange();
};

/** Step 2: You MUST wrap your TArray in another struct that inherits from FFastArraySerializer */
USTRUCT()
struct FExampleArray: public FFastArraySerializer
{
  GENERATED_USTRUCT_BODY()
  UPROPERTY()
  TArray<FExampleItemEntry> Items; /** Step 3: You MUST have a TArray named Items of the struct you made in step 1. */
  /** Step 4: Copy this, replace example with your names */
  bool NetDeltaSerialize(FNetDeltaSerializeInfo & DeltaParms)
  {
  return FastArrayDeltaSerialize<FExampleItemEntry>( Items, DeltaParms );
  }
};

/** Step 5: Copy and paste this struct trait, replacing FExampleArray with your Step 2 struct. */
template<>
struct TStructOpsTypeTraits< FExampleArray > : public TStructOpsTypeTraitsBase
{
  enum
  {
  WithNetDeltaSerializer = true,
  };
};


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM