FirstGearGames / FishNet

FishNet: Unity Networking Evolved.
Other
1.39k stars 149 forks source link

Sirenix Odin serialization breaks SyncDictionaries, causes them to be null on Spawn #693

Closed yrokhlin closed 4 months ago

yrokhlin commented 5 months ago

General Unity version: 2021.3.5f1 Fish-Networking version: 4.3.4R PRO Discord link: https://discord.com/channels/424284635074134018/1247017550609518602

I have posted about this on the discord priority help and was encouraged to write this ticket.

Replicating this issue is quite easy, simply spawn a GameObject that has a script attached with a class that uses the Odin serializer and a SyncDictionary as well. This is the method used to achieve Odin serialization : Mentioned here in the Sirenix Docs

This causes the SyncDictionary to become null, and will throw exception on Spawn() every time.

[ShowOdinSerializedPropertiesInInspector]
public class TEST : NetworkBehaviour, ISerializationCallbackReceiver, ISupportsPrefabSerialization
{
    [SerializeField, HideInInspector]
    private SerializationData serializationData;

    SerializationData ISupportsPrefabSerialization.SerializationData { get { return this.serializationData; } set { this.serializationData = value; } }

    void ISerializationCallbackReceiver.OnAfterDeserialize()
    {
        UnitySerializationUtility.DeserializeUnityObject(this, ref this.serializationData);
    }

    void ISerializationCallbackReceiver.OnBeforeSerialize()
    {
        UnitySerializationUtility.SerializeUnityObject(this, ref this.serializationData);
    }

    public readonly SyncDictionary<int, string> test = new ();
    void Awake()
    {
        for (int i = 0; i < 10; i++)
        {
            test.Add(i, "test" + i); // Exception will happen right here, because the SyncDictionary will be null.
        }
    }
    // Rest of the code
}

An example of the exception:

image

SyncDictionary initialization values become null:


Jetbrains: Rider throws a warning about the initialization of those fields: Fields initializer value is ignored on initialization image

I have debugged with Jetbrains: Rider, so I can confirm the values are null on start: image image

I have temporarily hacked my way around the issue by adding the following lines to SyncDictionary.cs. I now initialize those values in the Initialized functions, seems to work, but not 100% sure this is the right solution here.

protected override void Initialized()
        {
            base.Initialized();

            _initialValues ??= new Dictionary<TKey, TValue>();
            _changed ??= new List<ChangeData>();
            _serverOnChanges ??= new List<CachedOnChange>();
            _clientOnChanges ??= new List<CachedOnChange>();

            foreach (KeyValuePair<TKey, TValue> item in Collection)
                _initialValues[item.Key] = item.Value;
        }

Additional Consideration

I also suspect that this might have something to do with issue #9 -- the [SyncObject] no longer exists, so maybe it has something to do with that? Not sure.

FirstGearGames commented 5 months ago

Yeah this does seem 100% to be an Odin issue. I see no reason your patch cannot be marked as a solution though. If you want to make a PR I can merge it so you can get credit, no worries otherwise.

FirstGearGames commented 4 months ago

Resolved in 4.3.6