Adding Null To HashSet Crashes Odin

Issue #761 new
Nicholas Aitken created an issue

Odin Version: Actually 3.0.4 (but it wasn’t an option on the drop-down list, so I picked 3.0.3)

What Happens?

When you have a GameObject with a [Serialized] HashSet<T>, where T is an Interface, you cannot just drag several assets (e.g. SerializedScriptableObject assets from the Hierarchy) into the HashSet in the inspector. The assets with that interface also do not populate with the HashSet’s (+) button. So, instead, you use the (+) button to add a null item, then drag the asset onto that null item in the hashset to replace it. This works fine for the first item in the HashSet. When you try to add a second null item (so that you can replace it with an asset), Odin throws a ton of errors, and the HashSet is no longer drawn in the inspector. In fact, you cannot rectify the situation by removing the added null item - because the HashSet is not being drawn anymore. So you have to use Undo.

Video gif, and code to reproduce the error very easily is attached.

This is the error:

ArgumentNullException: Value cannot be null.
Parameter name: key
Sirenix.Serialization.DictionaryKeyUtility.GetDictionaryKeyString (System.Object key) (at Y:/Repositories/sirenix-development-framework/OdinSerializer/OdinSerializer/Unity Integration/DictionaryKeySupport/DictionaryKeyUtility.cs:298)
Sirenix.Serialization.DictionaryKeyUtility+FallbackKeyComparer`1[T].Compare (T x, T y) (at Y:/Repositories/sirenix-development-framework/OdinSerializer/OdinSerializer/Unity Integration/DictionaryKeySupport/DictionaryKeyUtility.cs:87)
Sirenix.Serialization.DictionaryKeyUtility+KeyComparer`1[T].Compare (T x, T y) (at Y:/Repositories/sirenix-development-framework/OdinSerializer/OdinSerializer/Unity Integration/DictionaryKeySupport/DictionaryKeyUtility.cs:130)
System.Collections.Generic.ArraySortHelper`1[T].SwapIfGreater (T[] keys, System.Comparison`1[T] comparer, System.Int32 a, System.Int32 b) (at <eae584ce26bc40229c1b1aa476bfa589>:0)
System.Collections.Generic.ArraySortHelper`1[T].IntroSort (T[] keys, System.Int32 lo, System.Int32 hi, System.Int32 depthLimit, System.Comparison`1[T] comparer) (at <eae584ce26bc40229c1b1aa476bfa589>:0)
System.Collections.Generic.ArraySortHelper`1[T].IntrospectiveSort (T[] keys, System.Int32 left, System.Int32 length, System.Comparison`1[T] comparer) (at <eae584ce26bc40229c1b1aa476bfa589>:0)
System.Collections.Generic.ArraySortHelper`1[T].Sort (T[] keys, System.Int32 index, System.Int32 length, System.Collections.Generic.IComparer`1[T] comparer) (at <eae584ce26bc40229c1b1aa476bfa589>:0)
Rethrow as InvalidOperationException: Failed to compare two elements in the array.
System.Collections.Generic.ArraySortHelper`1[T].Sort (T[] keys, System.Int32 index, System.Int32 length, System.Collections.Generic.IComparer`1[T] comparer) (at <eae584ce26bc40229c1b1aa476bfa589>:0)
System.Array.Sort[T] (T[] array, System.Int32 index, System.Int32 length, System.Collections.Generic.IComparer`1[T] comparer) (at <eae584ce26bc40229c1b1aa476bfa589>:0)
System.Collections.Generic.List`1[T].Sort (System.Int32 index, System.Int32 count, System.Collections.Generic.IComparer`1[T] comparer) (at <eae584ce26bc40229c1b1aa476bfa589>:0)
System.Collections.Generic.List`1[T].Sort (System.Collections.Generic.IComparer`1[T] comparer) (at <eae584ce26bc40229c1b1aa476bfa589>:0)
Sirenix.OdinInspector.Editor.HashSetResolver`2[TCollection,TElement].EnsureUpdated (System.Boolean force) (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Resolvers/Property Resolvers/HashSetResolver.cs:138)
Sirenix.OdinInspector.Editor.HashSetResolver`2[TCollection,TElement].GetElement (TCollection collection, System.Int32 index) (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Resolvers/Property Resolvers/HashSetResolver.cs:71)
Sirenix.OdinInspector.Editor.HashSetResolver`2+<>c__DisplayClass9_0[TCollection,TElement].<GetChildInfo>b__0 (TCollection& collection) (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Resolvers/Property Resolvers/HashSetResolver.cs:54)
Sirenix.OdinInspector.Editor.GetterSetter`2[TOwner,TValue].GetValue (TOwner& owner) (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/GetterSetter.cs:270)
Sirenix.OdinInspector.Editor.PropertyValueEntry`2[TParent,TValue].UpdateValues () (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Value Entries/PropertyValueEntry.cs:1049)
Sirenix.OdinInspector.Editor.PropertyValueEntry.Update () (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Value Entries/PropertyValueEntry.cs:226)
Sirenix.OdinInspector.Editor.InspectorProperty.UpdateValueEntry () (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/InspectorProperty.cs:1454)
Sirenix.OdinInspector.Editor.InspectorProperty.Update (System.Boolean forceUpdate) (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/InspectorProperty.cs:1108)
Sirenix.OdinInspector.Editor.InspectorProperty.OnStateUpdate (System.Int32 treeID) (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/InspectorProperty.cs:681)
Sirenix.OdinInspector.Editor.InspectorProperty.OnStateUpdate (System.Int32 treeID) (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/InspectorProperty.cs:686)
Sirenix.OdinInspector.Editor.InspectorProperty.OnStateUpdate (System.Int32 treeID) (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/InspectorProperty.cs:686)
Sirenix.OdinInspector.Editor.PropertyTree.BeginDraw (System.Boolean withUndo) (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/PropertyTree.cs:450)
Sirenix.OdinInspector.Editor.PropertyTree.Draw (System.Boolean applyUndo) (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/PropertyTree.cs:388)
Sirenix.OdinInspector.Editor.OdinEditor.DrawTree () (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/OdinEditor.cs:93)
Sirenix.OdinInspector.Editor.OdinEditor.DrawOdinInspector () (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/OdinEditor.cs:216)
Sirenix.OdinInspector.Editor.OdinEditor.OnInspectorGUI () (at Y:/Repositories/sirenix-development-framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/OdinEditor.cs:85)
UnityEditor.UIElements.InspectorElement+<>c__DisplayClass59_0.<CreateIMGUIInspectorFromEditor>b__0 () (at <420b942f64794d4da66420603f126f7b>:0)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)

How to Reproduce It

(1) Add GameObject to empty scene

(2) Add component with this script to the GameObject:

using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;

public class Test : SerializedMonoBehaviour
{
    [SerializeField] public HashSet<MyInterface> myHashSet;
}

(3) Make a few scriptable object assets with this script:

using Sirenix.OdinInspector;
public class MyScriptableObject : SerializedScriptableObject, MyInterface
{

}

public interface MyInterface
{

}

(3) In the inspector, initialize the GameObject’s hashset

(4) In the inspector, use the (+) button to add a “Null (MyInterface)” to the hashSet

(5) In the inspector, drag one of the scriptableObjects (from step 3) to replace the null entry in the hashSet

(6) In the inspector, use the (+) button to add another “Null (MyInterface)” to the hashSet.

Observe the error and that the hashset is no longer being drawn. Also, the only way to remove the problem null entry is to use an Undo since the hashset cannot be manipulated now in the inspector (because it isn’t being drawn).

Video Screen Recording:

Version of Unity: 2020.2.5f1

Editor Only Mode: Not enabled

Operating System: Windows 10 with latest system updates

Comments (1)

  1. Log in to comment