Skip to content

Commit

Permalink
Merge pull request #153 from brunomikoski/feature/fix-item-picker-edi…
Browse files Browse the repository at this point in the history
…tor-usage

Feature/fix item picker editor usage
  • Loading branch information
brunomikoski authored Aug 27, 2024
2 parents 75087cc + 7295c20 commit 9eca097
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 27 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [2.3.4]
## Changed
- Update PickerPropertyDrawer to use PopupList from property path cache to avoid issue when rendered inside a List/Array
- Update CollectionRegistry to search for the ScriptableObjectCollection using the `AssetDatabase.FindAssets` instead of the `TypeCache` first
- Added confirmation popup for deleting items from the Collection
- Fixed issue while renaming one asset could be canceled on arrow keys press
- Fix removing wrong usages of ApplyModifiedProperties
- Fixed issue with the CollectionItemPicker not updating the collection properly on editor mode

## [2.3.3]
## Added
Expand Down Expand Up @@ -577,6 +580,7 @@ public bool IsValidConsumable(Consumable consumable)
### Added
- First initial working version

[2.3.4]: https://github.com/badawe/ScriptableObjectCollection/releases/tag/v2.3.4
[2.3.3]: https://github.com/badawe/ScriptableObjectCollection/releases/tag/v2.3.3
[2.3.2]: https://github.com/badawe/ScriptableObjectCollection/releases/tag/v2.3.2
[2.3.1]: https://github.com/badawe/ScriptableObjectCollection/releases/tag/v2.3.1
Expand Down
144 changes: 143 additions & 1 deletion Scripts/Editor/Extensions/SerializedPropertyExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;

namespace BrunoMikoski.ScriptableObjectCollections
{
Expand Down Expand Up @@ -108,5 +112,143 @@ public static void SetValue(this SerializedProperty serializedProperty, object v
break;
}
}

public static T GetActualObject<T>(this SerializedProperty property, FieldInfo fieldInfo)
where T : class
{
string label = string.Empty;
return property.GetActualObjectForSerializedProperty<T>(fieldInfo, ref label);
}

/// <summary>
/// Used to extract the target object from a serialized property.
/// NOTE: This implementation comes from Unity's own Addressables package.
/// </summary>
/// <typeparam name="T">The type of the object to extract.</typeparam>
/// <param name="property">The property containing the object.</param>
/// <param name="field">The field data.</param>
/// <param name="label">The label name.</param>
/// <returns>Returns the target object type.</returns>
public static T GetActualObjectForSerializedProperty<T>(
this SerializedProperty property, FieldInfo field, ref string label)
{
try
{
if (property == null || field == null)
return default;

SerializedObject serializedObject = property.serializedObject;
if (serializedObject == null)
return default;

Object targetObject = serializedObject.targetObject;

if (property.depth > 0)
{
List<string> slicedName = property.propertyPath.Split('.').ToList();
List<int> arrayCounts = new List<int>();
for (int index = 0; index < slicedName.Count; index++)
{
arrayCounts.Add(-1);
string currName = slicedName[index];
if (currName.EndsWith("]"))
{
string[] arraySlice = currName.Split('[', ']');
if (arraySlice.Length >= 2)
{
arrayCounts[index - 2] = Convert.ToInt32(arraySlice[1]);
slicedName[index] = string.Empty;
slicedName[index - 1] = string.Empty;
}
}
}

while (string.IsNullOrEmpty(slicedName.Last()))
{
int i = slicedName.Count - 1;
slicedName.RemoveAt(i);
arrayCounts.RemoveAt(i);
}

if (property.propertyPath.EndsWith("]"))
{
string[] slice = property.propertyPath.Split('[', ']');
if (slice.Length >= 2)
label = "Element " + slice[slice.Length - 2];
}

return DescendHierarchy<T>(targetObject, slicedName, arrayCounts, 0);
}

object obj = field.GetValue(targetObject);
return (T)obj;
}
catch
{
return default;
}
}

static T DescendHierarchy<T>(object targetObject, List<string> splitName, List<int> splitCounts, int depth)
{
if (depth >= splitName.Count)
return default;

string currName = splitName[depth];

if (string.IsNullOrEmpty(currName))
return DescendHierarchy<T>(targetObject, splitName, splitCounts, depth + 1);

int arrayIndex = splitCounts[depth];

FieldInfo newField = targetObject.GetType().GetField(
currName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

if (newField == null)
{
Type baseType = targetObject.GetType().BaseType;
while (baseType != null && newField == null)
{
newField = baseType.GetField(
currName,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
baseType = baseType.BaseType;
}
}

object newObj = newField.GetValue(targetObject);
if (depth == splitName.Count - 1)
{
T actualObject = default(T);
if (arrayIndex >= 0)
{
if (newObj.GetType().IsArray && ((Array)newObj).Length > arrayIndex)
actualObject = (T)((Array)newObj).GetValue(arrayIndex);

if (newObj is IList newObjList && newObjList.Count > arrayIndex)
{
actualObject = (T)newObjList[arrayIndex];

//if (actualObject == null)
// actualObject = new T();
}
}
else
{
actualObject = (T)newObj;
}

return actualObject;
}
else if (arrayIndex >= 0)
{
if (newObj is IList list)
newObj = list[arrayIndex];
else if (newObj is Array a)
newObj = a.GetValue(arrayIndex);
}

return DescendHierarchy<T>(newObj, splitName, splitCounts, depth + 1);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,7 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten

private void DrawItemDrawer(Rect position, SerializedProperty property, GUIContent label, ScriptableObject collectionItem)
{
collectionItemPropertyDrawer.DrawCollectionItemDrawer(ref position, property, collectionItem, label, item =>
{
SetSerializedPropertyGUIDs(item);
drawingProperty.serializedObject.ApplyModifiedProperties();
});
collectionItemPropertyDrawer.DrawCollectionItemDrawer(ref position, property, collectionItem, label, SetSerializedPropertyGUIDs);
}

private void SetSerializedPropertyGUIDs(ScriptableObject item)
Expand Down Expand Up @@ -156,4 +152,4 @@ private SOCItemEditorOptionsAttribute GetOptionsAttribute()
return null;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class CollectionItemPickerPropertyDrawer : PropertyDrawer
private const string COLLECTION_GUID_VALUE_A = "collectionGUIDValueA";
private const string COLLECTION_GUID_VALUE_B = "collectionGUIDValueB";

private const string ITEMS_PROPERTY_NAME = "cachedIndirectReferences";
private const string ITEMS_PROPERTY_NAME = "indirectReferences";

private static GUIStyle labelStyle;
private static GUIStyle buttonStyle;
Expand Down Expand Up @@ -158,7 +158,6 @@ private void CreatAndAddNewItems(SerializedProperty property)
itemsProperty.arraySize++;

AssignItemGUIDToProperty(newItem, itemsProperty.GetArrayElementAtIndex(itemsProperty.arraySize - 1));
itemsProperty.serializedObject.ApplyModifiedProperties();
}

private void GetValuesFromPopup(PopupList<PopupItem> popupList, SerializedProperty property)
Expand Down Expand Up @@ -188,23 +187,21 @@ private void GetValuesFromPopup(PopupList<PopupItem> popupList, SerializedProper
propertyArrayIndex++;
}
}

itemsProperty.serializedObject.ApplyModifiedProperties();
}

private void AssignItemGUIDToProperty(ScriptableObject scriptableObject, SerializedProperty newProperty)
{
if (scriptableObject is ISOCItem item)
{
(long, long) itemValues = item.GUID.GetRawValues();
(long, long) collectionValues = item.Collection.GUID.GetRawValues();
if (scriptableObject is not ISOCItem item)
return;

newProperty.FindPropertyRelative(COLLECTION_ITEM_GUID_VALUE_A).longValue = itemValues.Item1;
newProperty.FindPropertyRelative(COLLECTION_ITEM_GUID_VALUE_B).longValue = itemValues.Item2;
(long, long) itemValues = item.GUID.GetRawValues();
(long, long) collectionValues = item.Collection.GUID.GetRawValues();

newProperty.FindPropertyRelative(COLLECTION_GUID_VALUE_A).longValue = collectionValues.Item1;
newProperty.FindPropertyRelative(COLLECTION_GUID_VALUE_B).longValue = collectionValues.Item2;
}
newProperty.FindPropertyRelative(COLLECTION_ITEM_GUID_VALUE_A).longValue = itemValues.Item1;
newProperty.FindPropertyRelative(COLLECTION_ITEM_GUID_VALUE_B).longValue = itemValues.Item2;

newProperty.FindPropertyRelative(COLLECTION_GUID_VALUE_A).longValue = collectionValues.Item1;
newProperty.FindPropertyRelative(COLLECTION_GUID_VALUE_B).longValue = collectionValues.Item2;
}

private void SetSelectedValuesOnPopup(PopupList<PopupItem> popupList, SerializedProperty property)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten
newItem =>
{
property.objectReferenceValue = newItem;
property.serializedObject.ApplyModifiedProperties();
});
}
EditorGUI.EndProperty();
Expand Down
16 changes: 10 additions & 6 deletions Scripts/Runtime/Core/CollectionItemPicker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;

namespace BrunoMikoski.ScriptableObjectCollections.Picker
{
Expand All @@ -13,10 +14,8 @@ namespace BrunoMikoski.ScriptableObjectCollections.Picker
public class CollectionItemPicker<TItemType> : IList<TItemType>, IEquatable<IList<TItemType>>, IEquatable<CollectionItemPicker<TItemType>>
where TItemType : ScriptableObject, ISOCItem
{
[SerializeField]
private List<CollectionItemIndirectReference<TItemType>> cachedIndirectReferences = new();

private List<CollectionItemIndirectReference<TItemType>> indirectReferences => cachedIndirectReferences;
[SerializeField, FormerlySerializedAs("cachedIndirectReferences")]
private List<CollectionItemIndirectReference<TItemType>> indirectReferences = new();

public event Action<TItemType> OnItemTypeAddedEvent;
public event Action<TItemType> OnItemTypeRemovedEvent;
Expand All @@ -28,7 +27,7 @@ public List<TItemType> Items
{
get
{
if (isDirty)
if (!Application.isPlaying || isDirty)
{
cachedItems.Clear();

Expand Down Expand Up @@ -104,6 +103,11 @@ public bool HasNone(params TItemType[] itemTypes)
//Implement mathematical operators
#region Operators

public static implicit operator List<TItemType>(CollectionItemPicker<TItemType> targetPicker)
{
return targetPicker.Items;
}

public static CollectionItemPicker<TItemType> operator +(CollectionItemPicker<TItemType> picker1,
CollectionItemPicker<TItemType> picker2)
{
Expand Down Expand Up @@ -261,7 +265,7 @@ public bool Remove(TItemType item)

public int IndexOf(TItemType item)
{
return indirectReferences.FindIndex(reference => reference.Ref.GUID== item.GUID);
return indirectReferences.FindIndex(reference => reference.Ref.GUID == item.GUID);
}

public void Insert(int index, TItemType item)
Expand Down

0 comments on commit 9eca097

Please sign in to comment.