Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice

Bug Contents of FixedList is not properly serialized/deserialized

Discussion in 'NetCode for ECS' started by ts_headfirst, Oct 27, 2023.

  1. ts_headfirst

    ts_headfirst

    Joined:
    Aug 1, 2023
    Posts:
    87
    Given the following structure, the contents of LeafsByPlayer will not be properly serialized or deserialized.
    On the client, it will have the correct number of items, however these items will all be initialized to defaults.

    In the example case, the PlayerId will be 0 and the Leafs list will be empty.

    Code (CSharp):
    1.     [GhostComponent(PrefabType = GhostPrefabType.All)]
    2.     public struct OuterList : IComponentData
    3.     {
    4.         [GhostField]
    5.         public FixedList512Bytes<InnerList> LeafsByPlayer;
    6.     }
    7.     public struct InnerList
    8.     {
    9.         public ulong PlayerId;
    10.         public FixedList32Bytes<Leaf> Leafs;
    11.     }
    12.     public struct Leaf
    13.     {
    14.         ...
    15.     }
    16.  
    17.     var outer = SystemAPI.GetSingletonRW<OuterList>();
    18.     outer.ValueRW.LeafsByPlayer = new InnerList
    19.     {
    20.         PlayerId = 42,
    21.         Leafs = new FixedList32Bytes<Leaf>
    22.         {
    23.             new Leaf()
    24.         }
    25.     }
     
  2. CMarastoni

    CMarastoni

    Unity Technologies

    Joined:
    Mar 18, 2020
    Posts:
    891
    FixedList are not supported yet and does not serialise correctly. It is known issue.
     
  3. ts_headfirst

    ts_headfirst

    Joined:
    Aug 1, 2023
    Posts:
    87
    That is unfortunate. I also found it missing from this list in the mean time. Any plans to support this and if so, any ETA?
    As an alternative I suppose an RPC with a custom serializer could be the answer.
     
  4. NikiWalker

    NikiWalker

    Unity Technologies

    Joined:
    May 18, 2021
    Posts:
    313
  5. ts_headfirst

    ts_headfirst

    Joined:
    Aug 1, 2023
    Posts:
    87
    Using an RPC with a custom serializer worked for our use case, and even though the documentation is actually quite good for this, I'll add our example for reference:

    Code (CSharp):
    1.  
    2. [BurstCompile]
    3. public struct LevelUpRewardOfferRequest : IComponentData, IRpcCommandSerializer<LevelUpRewardOfferRequest>
    4. {
    5.     public FixedList32Bytes<LevelUpReward> RewardsOnOffer;
    6.     private static readonly PortableFunctionPointer<RpcExecutor.ExecuteDelegate> Executor = new(InvokeExecute);
    7.     public static readonly ComponentTypeSet SendRequestComponentSet = new(typeof(LevelUpRewardOfferRequest), typeof(SendRpcCommandRequest));
    8.     public void Serialize(ref DataStreamWriter writer, in RpcSerializerState state, in LevelUpRewardOfferRequest data)
    9.     {
    10.         // length|[Type|Id]*
    11.         var offer = data.RewardsOnOffer;
    12.         writer.WriteByte((byte)offer.Length);
    13.         foreach (var reward in offer)
    14.         {
    15.             writer.WriteByte(reward.Id.Value);
    16.             writer.WriteByte((byte)reward.Type);
    17.         }
    18.     }
    19.     public void Deserialize(ref DataStreamReader reader, in RpcDeserializerState state, ref LevelUpRewardOfferRequest data)
    20.     {
    21.         var rewardCount = reader.ReadByte();
    22.         for (var i = 0; i < rewardCount; i++)
    23.         {
    24.             var reward = new LevelUpReward
    25.             {
    26.                 Id = ByteId.From(reader.ReadByte()),
    27.                 Type = (LevelUpRewardType)reader.ReadByte()
    28.             };
    29.             data.RewardsOnOffer.Add(reward);
    30.         }
    31.     }
    32.     public PortableFunctionPointer<RpcExecutor.ExecuteDelegate> CompileExecute() => Executor;
    33.     [BurstCompile(DisableDirectCall = true)]
    34.     private static void InvokeExecute(ref RpcExecutor.Parameters parameters)
    35.     {
    36.         RpcExecutor.ExecuteCreateRequestComponent<LevelUpRewardOfferRequest, LevelUpRewardOfferRequest>(ref parameters);
    37.     }
    38. }
    39.  
     
    CMarastoni likes this.