Unity-Technologies / com.unity.netcode.gameobjects

Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.
MIT License
2.15k stars 435 forks source link

[Distributed Authority] Custom Struct in NetworkList Causes Connection Failure #3061

Open william-bratches opened 2 months ago

william-bratches commented 2 months ago

Hey all,

I found what I believe to be a bug in the new 2.0.0-preview-4 edition of NGO. If a networkobject present in your scene contains a NetworkList with a custom struct, additional clients will fail to connect after the first. This took me awhile to debug, I was trying to figure out why none of my clients could connect after the scene was instantiated 😅

Here's example code I put together to demonstrate the solution, using the "WeaponBooster" struct from the current documentation:

using UnityEngine;
using Unity.Netcode;

public class NetworkListTest : NetworkBehaviour
{
        public NetworkList<WeaponBooster> netList;

    public void Awake()
    {
        netList = new NetworkList<WeaponBooster>();
    }

}

/// <summary>
/// Example: Complex Type
/// This is an example of how one might handle tracking any weapon booster currently applied
/// to a player.
/// </summary>
public struct WeaponBooster : INetworkSerializable, System.IEquatable<WeaponBooster>
{
    public float PowerAmplifier;
    public float Duration;

    public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    {
        if (serializer.IsReader)
        {
            var reader = serializer.GetFastBufferReader();
            reader.ReadValueSafe(out PowerAmplifier);
            reader.ReadValueSafe(out Duration);
        }
        else
        {
            var writer = serializer.GetFastBufferWriter();
            writer.WriteValueSafe(PowerAmplifier);
            writer.WriteValueSafe(Duration);
        }
    }

    public bool Equals(WeaponBooster other)
    {
        return PowerAmplifier == other.PowerAmplifier && Duration == other.Duration;
    }
}

If this code is present on any NetworkObject, additional clients will fail to connect.

If you change the NetworkList<WeaponBooster> to a NetworkList<int>, everything works fine!

I suspect something is wrong with serialization, or there is some change I need to make I'm not aware of. This code previously worked 100% fine in the client/host model.

NoelStephensUnity commented 2 months ago

@william-bratches This is actually a known issue with the live service. You can use collections with NetworkVariable in place of NetworkList. The fix should not require an update to the NGO package, and it should (hopefully) be resolved soon.