Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only.

    Please, do not make any changes to your username or email addresses at id.unity.com during this transition time.

    It's still possible to reply to existing private message conversations during the migration, but any new replies you post will be missing after the main migration is complete. We'll do our best to migrate these messages in a follow-up step.

    On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live.


    Read our full announcement for more information and let us know if you have any questions.

Bug NetworkVariable fails to update when size greater 256 Bytes

Discussion in 'Netcode for GameObjects' started by ThendonExe, Sep 20, 2023.

  1. ThendonExe

    ThendonExe

    Joined:
    Feb 27, 2019
    Posts:
    6
    Heyhey,

    Today I tried to update the Unity NGO package to version 1.6.0 but I encountered this error:
    OverflowException: Writing past the end of the buffer
    Unity.Netcode.FastBufferWriter.WriteBytesSafe (System.Byte* value, System.Int32 size, System.Int32 offset) (at ./Library/PackageCache/com.unity.netcode.gameobjects@1.6.0/Runtime/Serialization/FastBufferWriter.cs:732)
    Unity.Netcode.FastBufferWriter.WriteUnmanagedSafe[T] (Unity.Collections.NativeList`1[T] value) (at ./Library/PackageCache/com.unity.netcode.gameobjects@1.6.0/Runtime/Serialization/FastBufferWriter.cs:1001)
    Unity.Netcode.FastBufferWriter.WriteValueSafe[T] (Unity.Collections.NativeList`1[T] value, Unity.Netcode.FastBufferWriter+ForGeneric unused) (at ./Library/PackageCache/com.unity.netcode.gameobjects@1.6.0/Runtime/Serialization/FastBufferWriter.cs:1263)
    Unity.Netcode.BufferSerializerWriter.SerializeValue[T] (Unity.Collections.NativeList`1[T]& value, Unity.Netcode.FastBufferWriter+ForGeneric unused) (at ./Library/PackageCache/com.unity.netcode.gameobjects@1.6.0/Runtime/Serialization/BufferSerializerWriter.cs:41)
    Unity.Netcode.BufferSerializer`1[TReaderWriter].SerializeValue[T] (Unity.Collections.NativeList`1[T]& value, Unity.Netcode.FastBufferWriter+ForGeneric unused) (at ./Library/PackageCache/com.unity.netcode.gameobjects@1.6.0/Runtime/Serialization/BufferSerializer.cs:143)
    LargeByteList.NetworkSerialize[T] (Unity.Netcode.BufferSerializer`1[TReaderWriter] serializer) (at Assets/Core/RTVR/Scripts/Netcode/DuplicateBugTester.cs:13)

    This is only happening for NetworkVariable<LargeCustomClass>() but not for RPC calls.

    After some investigation I think the problem lays with the Duplicate function in the ngopackage\Runtime\NetworkVariable\NetworkVariableSerialization.cs file. It does not allow the FastBufferWritter to scale beyond 256Bytes

    Code (CSharp):
    1.      
    2.         public void Duplicate(in T value, ref T duplicatedValue)
    3.         {
    4.             using var writer = new FastBufferWriter(256, Allocator.Temp);
    5.             var refValue = value;
    6.             Write(writer, ref refValue);
    7.  
    8.             using var reader = new FastBufferReader(writer, Allocator.None);
    9.             Read(reader, ref duplicatedValue);
    10.         }
    11.  
    Adding something like
    using var writer = new FastBufferWriter(256, Allocator.Temp, 65536);
    seems to fix the issue, but those files are immutable of course.

    This is the code to reproduce the error:
    Code (CSharp):
    1.  
    2. using System;
    3. using Unity.Collections;
    4. using Unity.Netcode;
    5. using UnityEngine;
    6. [Serializable]
    7. public class LargeByteList : INetworkSerializable
    8. {
    9.     //being filled with 1024 bytes
    10.     const int targetByteCount = 1024;
    11.     public NativeList<byte> bytes = new NativeList<byte>(Allocator.Persistent);
    12.     public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    13.     {
    14.         serializer.SerializeValue(ref bytes);
    15.     }
    16.     public void Fill()
    17.     {
    18.         for (int i = 0; i < targetByteCount; i++)
    19.             bytes.Add(1);
    20.     }
    21. }
    22. [Serializable]
    23. public class LargeDecimalContainer : INetworkSerializable
    24. {
    25.     //sizeof(decimal) = 24 Bytes
    26.     //18 * decimal => 288 Bytes
    27.     public decimal x1, x2, x3, x4, x5, x6;
    28.     public decimal y1, y2, y3, y4, y5, y6;
    29.     public decimal z1, z2, z3, z4, z5, z6;
    30.     public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    31.     {
    32.         serializer.SerializeValue(ref x1);
    33.         serializer.SerializeValue(ref x2);
    34.         serializer.SerializeValue(ref x3);
    35.         serializer.SerializeValue(ref x4);
    36.         serializer.SerializeValue(ref x5);
    37.         serializer.SerializeValue(ref x6);
    38.         serializer.SerializeValue(ref y1);
    39.         serializer.SerializeValue(ref y2);
    40.         serializer.SerializeValue(ref y3);
    41.         serializer.SerializeValue(ref y4);
    42.         serializer.SerializeValue(ref y5);
    43.         serializer.SerializeValue(ref y6);
    44.         serializer.SerializeValue(ref z1);
    45.         serializer.SerializeValue(ref z2);
    46.         serializer.SerializeValue(ref z3);
    47.         serializer.SerializeValue(ref z4);
    48.         serializer.SerializeValue(ref z5);
    49.         serializer.SerializeValue(ref z6);
    50.     }
    51.     public void Fill()
    52.     {
    53.         const decimal value = decimal.MaxValue;
    54.         x1 = x2 = x3 = x4 = x5 = x6 = value;
    55.         y1 = y2 = y3 = y4 = y5 = y6 = value;
    56.         z1 = z2 = z3 = z4 = z5 = z6 = value;
    57.     }
    58. }
    59. class DuplicateBugTester : NetworkBehaviour
    60. {
    61.     public NetworkVariable<LargeByteList> largeByteList = new NetworkVariable<LargeByteList>(new LargeByteList());
    62.     public NetworkVariable<LargeDecimalContainer> largeDecimalContainer = new NetworkVariable<LargeDecimalContainer>(new LargeDecimalContainer());
    63.     public override void OnNetworkSpawn()
    64.     {
    65.         largeByteList.Value.Fill();
    66.         largeDecimalContainer.Value.Fill();
    67.     }
    68. }
    69.  

    Have a nice day :)
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    7,263
    I suspect NetworkVariable isn't designed for "large" amounts of data.
    Specifically considering that it would likely send out the entire 256 bytes on every change. Is that really what you need and want to do? Because that can quickly amount to significant bandwidth if you're not careful.

    The right way to go about this is to implement the INetworkSerializable (recalled from memory) interface and use that to serialize your custom class.

    But pretty sure you do NOT want to send the whole thing(-ies?) around on every change. ;)
    And if this is a one-time (or rare) thing, it shouldn't be a NetworkVariable to begin with.
     
  3. ThendonExe

    ThendonExe

    Joined:
    Feb 27, 2019
    Posts:
    6
    I agree to some extend. Since it was working before and I could not find any limitation information within the documentation I thought this might not be intended. The use case I got are relatively large level informations which only get changed when switching the level. Having this within a NetworkVariable was a pretty easy way to do it. But yea I ll just change to some RPC back and forth for now i guess :)