Skip to content

Instantly share code, notes, and snippets.

@SolarianZ
Last active July 24, 2024 10:03
Show Gist options
  • Select an option

  • Save SolarianZ/deb6f95d59cbcd9ccb0858eed65c9af6 to your computer and use it in GitHub Desktop.

Select an option

Save SolarianZ/deb6f95d59cbcd9ccb0858eed65c9af6 to your computer and use it in GitHub Desktop.
{"category": "Unity Engine/Editor/Extensions", "keywords": "Unity, Editor, UI, Odin, Primary, Key, List, Element"} Odin extension to verify the primary key of the list element.
using System;
using System.Collections;
using System.Diagnostics;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities.Editor;
using UnityEngine;
// Put the following class to the Runtime folder
// Used on primary key field
[Conditional("UNITY_EDITOR")]
public class PrimaryKeyAttribute : Attribute { }
// Put the following class to the Editor folder
public class PrimaryKeyListElementDrawer : OdinAttributeDrawer<PrimaryKeyAttribute>
{
/// <inheritdoc />
protected override void DrawPropertyLayout(GUIContent label)
{
if (IsParentObjectInList())
{
if (Property.ValueEntry.WeakSmartValue == null
|| (Property.ValueEntry.WeakSmartValue is string str && string.IsNullOrEmpty(str)))
{
SirenixEditorGUI.ErrorMessageBox("Primary key cannot be null or empty.");
}
else if (HasDuplicateKeys())
{
SirenixEditorGUI.ErrorMessageBox("Duplicate primary keys are not allowed.");
}
}
CallNextDrawer(label);
}
private bool IsParentObjectInList()
{
return Property.Parent.Parent?.ValueEntry?.WeakSmartValue is IList;
}
private bool HasDuplicateKeys()
{
InspectorProperty listProperty = Property.Parent.Parent;
foreach (InspectorProperty listElementProperty in listProperty.Children)
{
if (listElementProperty == Property.Parent)
{
continue;
}
foreach (InspectorProperty siblingProperty in listElementProperty.Children)
{
if (!Property.Name.Equals(siblingProperty.Name))
{
continue;
}
// Do not use == operator here, because it does not support polymorphic comparison
if (Property.ValueEntry.WeakSmartValue.Equals(siblingProperty.ValueEntry.WeakSmartValue))
{
return true;
}
}
}
return false;
}
}
// If you can add the PrimaryKeyAttribute to the field of the list element type,
// you can use the following code to validate the primary key:
//
// // Usage: [ListDrawerSettings(OnBeginListElementGUI = nameof(OdinValidatePrimaryKey))]
// // Replace "LIST" and "PRIMARY_KEY" with your list name and primary key name.
// private void OdinValidatePrimaryKey(int index)
// {
// var value = LIST[index].PRIMARY_KEY;
// if (value == null || (value is string str && string.IsNullOrEmpty(str))) // Not suitable for all types
// {
// SirenixEditorGUI.ErrorMessageBox("Primary key cannot be null or empty.");
// return;
// }
//
// for (int i = 0; i < LIST.Length; i++)
// {
// if (i == index)
// {
// continue;
// }
//
// var otherValue = LIST[i].PRIMARY_KEY;
// if (value.Equals(otherValue))
// {
// SirenixEditorGUI.ErrorMessageBox("Duplicate primary keys are not allowed.");
// return;
// }
// }
// }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment