• Ue4 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,
      };
    };
    
  • 相关阅读:
    网络攻防第十一周作业
    网络攻防第十周作业
    网络攻防第九周作业
    网络攻防第八周作业
    网络攻防第七周作业
    网络攻防第六周作业
    网络攻防第五周作业
    网络攻防第四周作业
    网络攻防第三周作业
    20189207《网络攻防实践》第十一周作业
  • 原文地址:https://www.cnblogs.com/whitelily/p/16158793.html
Copyright © 2020-2023  润新知