com.unity.netcode.gameobjects icon indicating copy to clipboard operation
com.unity.netcode.gameobjects copied to clipboard

When Overloading FastBuffer methods, The wrong reflection is called for List<T>

Open WeLikeIke opened this issue 4 years ago • 3 comments

Describe the bug While trying to implement custom serialization of data to be given to Rpcs, I found myself implementing methods:

public static void ReadValueSafe(this FastBufferReader reader, out List<int> value);
public static void WriteValueSafe(this FastBufferWriter writer, in List<int> value);

public static void ReadValueSafe(this FastBufferReader reader, out List<string> value);
public static void WriteValueSafe(this FastBufferWriter writer, in List<string> value);

However when invoked by Rpcs that use List<int> and List<string>, only one at the time works.

Specifically,

  • if both implementations are present, the List<int> overload will be called for both, leading to an error when using List<string>.
  • if only the List implementation is present, then you cannot call Rpcs that use List<string>, but List<int> ones are fine.
  • if only the List implementation is present, then you cannot call Rpcs that use List<int>, but List<string> ones are fine.

I have attached a test scene that has a 100% reproducibility rate.

BadReflectionIssue.zip

To Reproduce Steps to reproduce the behavior:

  1. Open UnityEditor with the latest Netcode Package.
  2. Drag and Drop the Scene provided in the attachment.
  3. Build and Run.
  4. In the Editor, Start the runtime and click on the "Start Server" button.
  5. In the Build, click on the "Start Client" button.
  6. In the Build, click on the "Send Int List" button and then on the "Send String List" button.
  7. Observe the Console.

Actual outcome

[Netcode-Server Sender=0] The ReadValueSafe overload for List<int> has just been called
[ServerRpc]: Received int list containing: |313|339|335|
[Netcode-Server Sender=0] The ReadValueSafe overload for List<int> has just been called
Unhandled RPC Exception: System.NullReferenceException: Object reference not set to an instance of an object

Expected outcome

[Netcode-Server Sender=0] The ReadValueSafe overload for List<int> has just been called
[ServerRpc]: Received int list containing: |313|339|335|
[Netcode-Server Sender=0] The ReadValueSafe overload for List<string> has just been called
[ServerRpc]: Received int list containing: |uqb|lzy|dwa|

Environment:

  • OS: Windows 10
  • Unity Version: 2020.3.15f2
  • Netcode Version: 1.0.0-pre.4

Additional context Note that my serialization methods work when used exclusively. It looks like a Unity reflection problem and I encourage you to comment out the overload for List<int> to see that, in the next build, the "Send String List" button would fill the console correctly.

Also, the numbers and letters in the output are irrelevant, they are randomly generated

WeLikeIke avatar Jan 13 '22 16:01 WeLikeIke

Run into same issue.. I have

public static void WriteValueSafe(this FastBufferWriter writer, in List<EquipmentSlot> value)

and

public static void WriteValueSafe(this FastBufferWriter writer, in List<Guid> value)

When sending Guid List as Rpc param WriteValueSafe for EquipmentSlot List is called.

MrCool92 avatar Feb 01 '22 16:02 MrCool92

Adding this to GetWriteMethodForParameter and GetReadMethodForParameter of NetworkBehaviourILPP fixes the issue.

if (parameters[1].ParameterType.FullName != paramType.MakeByReferenceType().FullName)
    continue;

.Resolve() reduces generic type like List<int> and List<string> to List'1. That's why same read/write methods are used for both types.

This is just a quick and dirty fix. I have no idea how to use Mono.Cecil lib.

MrCool92 avatar Feb 02 '22 08:02 MrCool92

Added to our backlog MTT-3063

ashwinimurt avatar Mar 30 '22 15:03 ashwinimurt