diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 10964e5..17311f2 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -5,6 +5,19 @@ 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.9] - 19/02/2025 +## Changed + - Added some general fixes to validate Collection and Items have unique `LongGuid` + - Fixed issues when after some operation with the context menu on the CollectionEditor items would not refresh properly + - Fixed issue when moving items between collection would not generate unique names + - Removed the post processing of assets that tried to assign items to collections automatically, since this was causing issue when duplicating collections, everyting now is done on the collection + - Overall code improvement and organization + +## Added + - Added new Context Menu for moving items between collections + - Added the new PropertyDrawer that shows what Collection every item belongs to + - Added a few more Confirmation dialog when detecting items that looks wrong + ## [2.3.8] - 30/01/2025 ## Changed @@ -612,6 +625,7 @@ public bool IsValidConsumable(Consumable consumable) ### Added - First initial working version +[2.3.9]: https://github.com/badawe/ScriptableObjectCollection/releases/tag/v2.3.9 [2.3.8]: https://github.com/badawe/ScriptableObjectCollection/releases/tag/v2.3.8 [2.3.7]: https://github.com/badawe/ScriptableObjectCollection/releases/tag/v2.3.7 [2.3.6]: https://github.com/badawe/ScriptableObjectCollection/releases/tag/v2.3.6 diff --git a/Scripts/Editor/CustomEditors/CollectionCustomEditor.cs b/Scripts/Editor/CustomEditors/CollectionCustomEditor.cs index 3225e4e..5a3d46c 100644 --- a/Scripts/Editor/CustomEditors/CollectionCustomEditor.cs +++ b/Scripts/Editor/CustomEditors/CollectionCustomEditor.cs @@ -19,7 +19,6 @@ namespace BrunoMikoski.ScriptableObjectCollections { - [CustomEditor(typeof(ScriptableObjectCollection), true)] public class CollectionCustomEditor : Editor { @@ -394,6 +393,12 @@ protected virtual void OnEnable() { collection = (ScriptableObjectCollection)target; + if (!CollectionsRegistry.Instance.HasUniqueGUID(collection)) + { + collection.GenerateNewGUID(); + collection.Clear(); + } + if (!CollectionsRegistry.Instance.IsKnowCollection(collection)) CollectionsRegistry.Instance.ReloadCollections(); @@ -626,10 +631,10 @@ private bool IsAddressableAsset(ScriptableObject target) #endif } - private ScriptableObject AddNewItemOfType(Type targetType, bool autoFocusForRename = true) + private ScriptableObject AddNewItemOfType(Type targetType,string assetName = "", bool autoFocusForRename = true) { Undo.IncrementCurrentGroup(); - ScriptableObject newItem = collection.AddNew(targetType); + ScriptableObject newItem = collection.AddNew(targetType, assetName); Undo.RegisterCreatedObjectUndo(newItem, "Create New Item"); Undo.RecordObject(collection, "Add New Item"); Undo.SetCurrentGroupName($"Created new item {newItem.name}"); @@ -792,10 +797,12 @@ private void ShowOptionsForIndex(MouseUpEvent evt, int targetIndex) { DuplicateItem(item, false); } + ReloadFilteredItems(); } else { DuplicateItem(targetIndex); + ReloadFilteredItems(); } } ); @@ -825,6 +832,7 @@ private void ShowOptionsForIndex(MouseUpEvent evt, int targetIndex) { RemoveItemAtIndex(collection.IndexOf(item), result == 2); } + ReloadFilteredItems(); } else { @@ -837,6 +845,7 @@ private void ShowOptionsForIndex(MouseUpEvent evt, int targetIndex) } RemoveItemAtIndex(filteredItems.Count - 1, result == 2); + ReloadFilteredItems(); } } ); @@ -872,19 +881,20 @@ private void ShowOptionsForIndex(MouseUpEvent evt, int targetIndex) foreach (ScriptableObject item in moveItems) { - MoveItem(item, scriptableObjectCollection); + SOCItemUtility.MoveItem(item as ISOCItem, scriptableObjectCollection); } + ReloadFilteredItems(); } else { - if (!EditorUtility.DisplayDialog($"Move Item", + if (!EditorUtility.DisplayDialog("Move Item", $"Are you sure you want to move {filteredItems[^1].name}, from {AssetDatabase.GetAssetPath(collection)} to {AssetDatabase.GetAssetPath(scriptableObject)}", "Yes", "No")) { return; } - - MoveItem(filteredItems[targetIndex], scriptableObjectCollection); + SOCItemUtility.MoveItem(filteredItems[targetIndex], scriptableObjectCollection); + ReloadFilteredItems(); } } ); @@ -923,38 +933,6 @@ private void ShowOptionsForIndex(MouseUpEvent evt, int targetIndex) menu.ShowAsContext(); } - private void MoveItem(ScriptableObject item, ScriptableObjectCollection targetCollection) - { - Undo.RecordObject(collection, "Move Item"); - Undo.RecordObject(targetCollection, "Move Item"); - - collection.Remove(item); - targetCollection.Add(item); - - string itemPath = AssetDatabase.GetAssetPath(item); - string targetCollectionPath = AssetDatabase.GetAssetPath(targetCollection); - - if (!string.IsNullOrEmpty(itemPath) && !string.IsNullOrEmpty(targetCollectionPath)) - { - string directory = Path.GetDirectoryName(targetCollectionPath); - - string itemsFolderPath = Path.Combine(directory, "Items"); - bool hasItemsFolder = AssetDatabase.IsValidFolder(itemsFolderPath); - - string finalDirectory = hasItemsFolder ? itemsFolderPath : directory; - string fileName = Path.GetFileName(itemPath); - - string newPath = AssetDatabase.GenerateUniqueAssetPath(Path.Combine(finalDirectory, fileName)); - - AssetDatabase.MoveAsset(itemPath, newPath); - } - - AssetDatabase.SaveAssets(); - AssetDatabase.Refresh(); - - ReloadFilteredItems(); - } - private List GetPossibleAnotherCollections() { CollectionsRegistry.Instance.TryGetCollectionsOfItemType(collection.GetItemType(), out List collections); @@ -980,7 +958,14 @@ private void DuplicateItem(int index, bool showRenameAfter = true) private void DuplicateItem(ScriptableObject source, bool showRenameAfter) { CopyCollectionItemUtility.SetSource(source); - ScriptableObject newItem = AddNewItemOfType(source.GetType(), false); + + string path = AssetDatabase.GetAssetPath(source); + string directory = Path.GetDirectoryName(path); + string fileName = $"{source.name} (Clone)"; + + fileName = AssetDatabase.GenerateUniqueAssetPath(Path.Combine(directory, $"{fileName}.asset")); + + ScriptableObject newItem = AddNewItemOfType(source.GetType(), Path.GetFileNameWithoutExtension(fileName), false); CopyCollectionItemUtility.ApplySourceToTarget(newItem); if (showRenameAfter) @@ -990,7 +975,6 @@ private void DuplicateItem(ScriptableObject source, bool showRenameAfter) } else { - AssetDatabaseUtils.RenameAsset(newItem, $"{source.name} (Copy)"); AssetDatabase.SaveAssetIfDirty(newItem); ReloadFilteredItems(); } diff --git a/Scripts/Editor/CustomEditors/MoveToCollectionWindow.cs b/Scripts/Editor/CustomEditors/MoveToCollectionWindow.cs new file mode 100644 index 0000000..93d294a --- /dev/null +++ b/Scripts/Editor/CustomEditors/MoveToCollectionWindow.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace BrunoMikoski.ScriptableObjectCollections +{ + public class MoveToCollectionWindow : EditorWindow + { + private List itemsToMove; + private List availableCollections; + + public static void ShowWindow(List items, List collections) + { + MoveToCollectionWindow window = GetWindow("Move to Collection"); + window.itemsToMove = items; + window.availableCollections = collections; + window.ShowPopup(); + } + + private void OnGUI() + { + EditorGUILayout.LabelField("Select a Collection to Move Items", EditorStyles.boldLabel); + + if (availableCollections == null || availableCollections.Count == 0) + { + EditorGUILayout.LabelField("No available collections."); + return; + } + + foreach (ScriptableObjectCollection collection in availableCollections) + { + if (GUILayout.Button(collection.name)) + { + foreach (ISOCItem item in itemsToMove) + { + SOCItemUtility.MoveItem(item, collection); + EditorUtility.SetDirty(collection); + } + + Close(); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Editor/CustomEditors/MoveToCollectionWindow.cs.meta b/Scripts/Editor/CustomEditors/MoveToCollectionWindow.cs.meta new file mode 100644 index 0000000..1c64435 --- /dev/null +++ b/Scripts/Editor/CustomEditors/MoveToCollectionWindow.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 517dfb63fdfc446eb055a5e2859396b1 +timeCreated: 1739956461 \ No newline at end of file diff --git a/Scripts/Editor/Processors/CollectionAssetsModificationProcessor.cs b/Scripts/Editor/Processors/CollectionAssetsModificationProcessor.cs index 1ff9d5b..6fd6f1c 100644 --- a/Scripts/Editor/Processors/CollectionAssetsModificationProcessor.cs +++ b/Scripts/Editor/Processors/CollectionAssetsModificationProcessor.cs @@ -24,6 +24,9 @@ public static AssetDeleteResult OnWillDeleteAsset(string targetAssetPath, Remove if (socItem == null) return AssetDeleteResult.DidNotDelete; + if (socItem.Collection == null) + return AssetDeleteResult.DidNotDelete; + socItem.Collection.Remove(collectionItem); return AssetDeleteResult.DidNotDelete; } @@ -42,4 +45,4 @@ public static AssetDeleteResult OnWillDeleteAsset(string targetAssetPath, Remove } } -} +} \ No newline at end of file diff --git a/Scripts/Editor/Processors/CollectionsAssetsPostProcessor.cs b/Scripts/Editor/Processors/CollectionsAssetsPostProcessor.cs index 78c9f2e..6d61465 100644 --- a/Scripts/Editor/Processors/CollectionsAssetsPostProcessor.cs +++ b/Scripts/Editor/Processors/CollectionsAssetsPostProcessor.cs @@ -29,30 +29,21 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse ScriptableObject collectionItem = AssetDatabase.LoadAssetAtPath(importedAssetPath); - if (collectionItem != null) + if (collectionItem == null) { - if (collectionItem is ISOCItem socItem) - { - if (socItem.Collection == null) - { - continue; - } + continue; + } + + if (collectionItem is not ISOCItem socItem) + { + continue; + } - if (!socItem.Collection.Contains(collectionItem)) - { - if (socItem.Collection.TryGetItemByGUID(socItem.GUID, out _)) - { - Debug.LogWarning( - $"Collection already contains one item with the same GUID" + - $" ({socItem.GUID}) but different name ({socItem.name}), generating new GUID"); - socItem.GenerateNewGUID(); - } - - socItem.Collection.Add(collectionItem); - Debug.Log($"{collectionItem.name} has collection assigned " - + $"{socItem.Collection} but its missing from collection list, adding it"); - } - } + if (!CollectionsRegistry.Instance.HasUniqueGUID(socItem)) + { + socItem.GenerateNewGUID(); + socItem.ClearCollection(); + Debug.LogWarning($"Item {socItem} GUID was not unique, generating a new one and clearing the collection"); } } @@ -64,6 +55,13 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse if (collection == null) continue; + if (!CollectionsRegistry.Instance.HasUniqueGUID(collection)) + { + collection.GenerateNewGUID(); + collection.Clear(); + Debug.LogWarning($"Collection {collection} GUID was not unique, generating a new one, and clearing the items"); + } + if (!CollectionsRegistry.Instance.IsKnowCollection(collection)) { RefreshRegistry(); @@ -95,4 +93,4 @@ static void OnAfterScriptsReloading() RefreshRegistryAfterRecompilation = false; } } -} +} \ No newline at end of file diff --git a/Scripts/Editor/PropertyDrawers/CollectionReferenceLongGuidDrawer.cs b/Scripts/Editor/PropertyDrawers/CollectionReferenceLongGuidDrawer.cs new file mode 100644 index 0000000..4d3d85a --- /dev/null +++ b/Scripts/Editor/PropertyDrawers/CollectionReferenceLongGuidDrawer.cs @@ -0,0 +1,29 @@ +using UnityEditor; +using UnityEngine; + +namespace BrunoMikoski.ScriptableObjectCollections.Picker +{ + [CustomPropertyDrawer(typeof(CollectionReferenceLongGuidAttribute))] + public class CollectionReferenceLongGuidDrawer : PropertyDrawer + { + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUIUtility.singleLineHeight; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + LongGuid collectionGUID = (LongGuid)property.boxedValue; + + ScriptableObjectCollection collection = null; + if (collectionGUID.IsValid()) + { + collection = CollectionsRegistry.Instance.GetCollectionByGUID(collectionGUID); + } + + EditorGUI.BeginDisabledGroup(true); + EditorGUI.ObjectField(position, "Collection", collection, typeof(ScriptableObjectCollection), false); + EditorGUI.EndDisabledGroup(); + } + } +} \ No newline at end of file diff --git a/Scripts/Editor/PropertyDrawers/CollectionReferenceLongGuidDrawer.cs.meta b/Scripts/Editor/PropertyDrawers/CollectionReferenceLongGuidDrawer.cs.meta new file mode 100644 index 0000000..4bb0103 --- /dev/null +++ b/Scripts/Editor/PropertyDrawers/CollectionReferenceLongGuidDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ba509ba6e52c4bb3ba782d70edda061b +timeCreated: 1739954642 \ No newline at end of file diff --git a/Scripts/Editor/Utils/SOCollectionsContextMenuItems.cs b/Scripts/Editor/Utils/SOCollectionsContextMenuItems.cs new file mode 100644 index 0000000..fd347c9 --- /dev/null +++ b/Scripts/Editor/Utils/SOCollectionsContextMenuItems.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace BrunoMikoski.ScriptableObjectCollections +{ + public static class SOCollectionsProjectContextMenus + { + [MenuItem("Assets/Move to Different Collection", true, priority = 10000)] + private static bool ValidateMoveToDifferentCollection() + { + Object[] selectedObjects = Selection.objects; + if (selectedObjects == null || selectedObjects.Length == 0) + return false; + + foreach (Object obj in selectedObjects) + { + ISOCItem socItem = obj as ISOCItem; + if (socItem == null) + return false; + } + + List possibleCollections = + CollectionsRegistry.Instance.GetCollectionsByItemType(selectedObjects[0].GetType()); + + if (possibleCollections == null || possibleCollections.Count <= 1) + { + return false; + } + + return true; + } + + [MenuItem("Assets/Move to Different Collection", priority = 10000)] + private static void MoveToDifferentCollection() + { + Object[] selectedObjects = Selection.objects; + List items = new List(); + + foreach (Object obj in selectedObjects) + { + if (obj is ISOCItem item) + items.Add(item); + } + + if (items.Count == 0) + return; + + List possibleCollections = + CollectionsRegistry.Instance.GetCollectionsByItemType(items[0].GetType()); + + if (possibleCollections == null || possibleCollections.Count == 0) + { + EditorUtility.DisplayDialog("Move to Different Collection", "No collections available.", "OK"); + return; + } + + ScriptableObjectCollection currentCollection = items[0].Collection; + + List filteredCollections = new List(); + foreach (ScriptableObjectCollection collection in possibleCollections) + { + if (collection != currentCollection) + filteredCollections.Add(collection); + } + + if (filteredCollections.Count == 0) + { + EditorUtility.DisplayDialog("Move to Different Collection", "No other collections available.", "OK"); + return; + } + + MoveToCollectionWindow.ShowWindow(items, filteredCollections); + } + + + [MenuItem("Assets/Select Collection", true, priority = 10000)] + private static bool ValidateSelectCollection() + { + Object[] selectedObjects = Selection.objects; + if (selectedObjects == null || selectedObjects.Length != 1) + return false; + ISOCItem socItem = selectedObjects[0] as ISOCItem; + return socItem != null && socItem.Collection != null; + } + + [MenuItem("Assets/Select Collection", priority = 10000)] + private static void SelectCollection() + { + Object[] selectedObjects = Selection.objects; + if (selectedObjects == null || selectedObjects.Length != 1) + return; + ISOCItem socItem = selectedObjects[0] as ISOCItem; + if (socItem != null && socItem.Collection != null) + Selection.activeObject = socItem.Collection; + } + } +} \ No newline at end of file diff --git a/Scripts/Editor/Utils/SOCollectionsContextMenuItems.cs.meta b/Scripts/Editor/Utils/SOCollectionsContextMenuItems.cs.meta new file mode 100644 index 0000000..03701b9 --- /dev/null +++ b/Scripts/Editor/Utils/SOCollectionsContextMenuItems.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6dd5680979ff4ebb958e1e776affe066 +timeCreated: 1739180519 \ No newline at end of file diff --git a/Scripts/Runtime/Attributes/CollectionReferenceLongGuidAttribute.cs b/Scripts/Runtime/Attributes/CollectionReferenceLongGuidAttribute.cs new file mode 100644 index 0000000..a459f39 --- /dev/null +++ b/Scripts/Runtime/Attributes/CollectionReferenceLongGuidAttribute.cs @@ -0,0 +1,11 @@ +using System; +using UnityEngine; + +namespace BrunoMikoski.ScriptableObjectCollections +{ + [AttributeUsage(AttributeTargets.Field)] + public class CollectionReferenceLongGuidAttribute : PropertyAttribute + { + + } +} \ No newline at end of file diff --git a/Scripts/Runtime/Attributes/CollectionReferenceLongGuidAttribute.cs.meta b/Scripts/Runtime/Attributes/CollectionReferenceLongGuidAttribute.cs.meta new file mode 100644 index 0000000..f2a9c98 --- /dev/null +++ b/Scripts/Runtime/Attributes/CollectionReferenceLongGuidAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 60387b23f75f40a4b2b5e46fdee24397 +timeCreated: 1739954588 \ No newline at end of file diff --git a/Scripts/Runtime/Attributes/SOCItemEditorOptionsAttribute.cs b/Scripts/Runtime/Attributes/SOCItemEditorOptionsAttribute.cs index e52cbac..b58ae7e 100644 --- a/Scripts/Runtime/Attributes/SOCItemEditorOptionsAttribute.cs +++ b/Scripts/Runtime/Attributes/SOCItemEditorOptionsAttribute.cs @@ -47,4 +47,4 @@ public class SOCItemEditorOptionsAttribute : Attribute public class CollectionItemEditorOptions : SOCItemEditorOptionsAttribute { } -} +} \ No newline at end of file diff --git a/Scripts/Runtime/Core/CollectionsRegistry.cs b/Scripts/Runtime/Core/CollectionsRegistry.cs index d4492ea..feefe36 100644 --- a/Scripts/Runtime/Core/CollectionsRegistry.cs +++ b/Scripts/Runtime/Core/CollectionsRegistry.cs @@ -522,5 +522,35 @@ public void UpdateAutoSearchForCollections() SetAutoSearchForCollections(false); } + + public bool HasUniqueGUID(ISOCItem targetItem) + { + for (int i = 0; i < collections.Count; i++) + { + ScriptableObjectCollection collection = collections[i]; + foreach (ScriptableObject scriptableObject in collection) + { + if (scriptableObject is ISOCItem socItem) + { + if(!Equals(socItem, targetItem) && socItem.GUID == targetItem.GUID) + return false; + } + } + } + + return true; + } + + public bool HasUniqueGUID(ScriptableObjectCollection targetCollection) + { + for (int i = 0; i < collections.Count; i++) + { + ScriptableObjectCollection collection = collections[i]; + if (collection != targetCollection && collection.GUID == targetCollection.GUID) + return false; + } + + return true; + } } } \ No newline at end of file diff --git a/Scripts/Runtime/Core/ISOCItem.cs b/Scripts/Runtime/Core/ISOCItem.cs index a499c66..1a4c50b 100644 --- a/Scripts/Runtime/Core/ISOCItem.cs +++ b/Scripts/Runtime/Core/ISOCItem.cs @@ -9,10 +9,11 @@ public interface ISOCItem string name { get; set; } void SetCollection(ScriptableObjectCollection collection); void GenerateNewGUID(); + void ClearCollection(); } public interface ISOCColorizedItem { Color LabelColor { get;} } -} +} \ No newline at end of file diff --git a/Scripts/Runtime/Core/ScriptableObjectCollection.cs b/Scripts/Runtime/Core/ScriptableObjectCollection.cs index 6e0efcc..519cf4c 100644 --- a/Scripts/Runtime/Core/ScriptableObjectCollection.cs +++ b/Scripts/Runtime/Core/ScriptableObjectCollection.cs @@ -111,7 +111,7 @@ public bool Add(ScriptableObject item) return true; } - internal void GenerateNewGUID() + public void GenerateNewGUID() { guid = LongGuid.NewGuid(); ObjectUtility.SetDirty(this); @@ -135,20 +135,10 @@ public ScriptableObject AddNew(Type itemType, string assetName = "") if (string.IsNullOrEmpty(itemName)) { - int count = Count; - while (true) - { - itemName = $"New{itemType.Name}{count}"; - string testPath = Path.Combine(parentFolderPath, itemName); - - if (!File.Exists(Path.GetFullPath($"{testPath}.asset"))) - break; - - count++; - } + itemName = $"{itemType.Name}"; } - newItem.name = itemName; + newItem.name = AssetDatabase.GenerateUniqueAssetPath(itemName); if(itemName.IsReservedKeyword()) Debug.LogError($"{itemName} is a reserved keyword name, will cause issues with code generation, please rename it"); @@ -282,6 +272,9 @@ public void Insert(int index, object value) public bool Remove(ScriptableObject item) { bool result = items.Remove(item); + if (item is ISOCItem socItem) + socItem.ClearCollection(); + ObjectUtility.SetDirty(this); return result; } @@ -321,8 +314,7 @@ public void Swap(int targetIndex, int newIndex) (items[targetIndex], items[newIndex]) = (items[newIndex], items[targetIndex]); ObjectUtility.SetDirty(this); } - - [ContextMenu("Refresh Collection")] + public void RefreshCollection() { #if UNITY_EDITOR @@ -334,15 +326,16 @@ public void RefreshCollection() string assetPath = AssetDatabase.GetAssetPath(this); if (string.IsNullOrEmpty(assetPath)) return; - + string folder = Path.GetDirectoryName(assetPath); string[] guids = AssetDatabase.FindAssets($"t:{collectionItemType.Name}", new []{folder}); + List itemsFromOtherCollections = new List(); for (int i = 0; i < guids.Length; i++) { ScriptableObject item = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guids[i])); - + if (item == null) continue; @@ -352,7 +345,10 @@ public void RefreshCollection() if (socItem.Collection != null) { if (socItem.Collection != this) + { + itemsFromOtherCollections.Add(socItem); continue; + } if (socItem.Collection.Contains(item)) continue; @@ -362,23 +358,77 @@ public void RefreshCollection() changed = true; } - for (int i = items.Count - 1; i >= 0; i--) + int itemsCount = items.Count; + for (int i = itemsCount - 1; i >= 0; i--) { if (items[i] == null) { RemoveAt(i); Debug.Log($"Removing item at index {i} as it is null"); changed = true; + continue; } - + ScriptableObject scriptableObject = items[i]; + + + if (scriptableObject is ISOCItem socItem) + { + if (socItem.Collection != this) + { + RemoveAt(i); + Debug.Log($"Removing item at index {i} since it belongs to another collection {socItem.Collection}"); + changed = true; + } + } + if (scriptableObject.GetType() == GetItemType() || scriptableObject.GetType().IsSubclassOf(GetItemType())) continue; - + RemoveAt(i); Debug.Log($"Removing item at index {i} {scriptableObject} since it is not of type {GetItemType()}"); } + if (itemsFromOtherCollections.Any()) + { + int result = EditorUtility.DisplayDialogComplex("Items from another collections", + $"The following items {string.Join(",", itemsFromOtherCollections.Select(o => o.name).ToArray())} belong to other collections, should I move to the appropriated folder?", + "Move to the assigned collection", $"Assign it to this collection ", "Do nothing"); + + if (result == 0) + { + foreach (ISOCItem itemsFromOtherCollection in itemsFromOtherCollections) + { + SOCItemUtility.MoveItem(itemsFromOtherCollection, itemsFromOtherCollection.Collection); + changed = true; + ObjectUtility.SetDirty(itemsFromOtherCollection.Collection); + } + + } + else if (result == 1) + { + if (!CollectionsRegistry.Instance.HasUniqueGUID(this)) + { + GenerateNewGUID(); + Clear(); + } + + if (!CollectionsRegistry.Instance.IsKnowCollection(this)) + { + CollectionsRegistry.Instance.RegisterCollection(this); + } + + foreach (ISOCItem itemsFromOtherCollection in itemsFromOtherCollections) + { + itemsFromOtherCollection.ClearCollection(); + Add(itemsFromOtherCollection as ScriptableObject); + ObjectUtility.SetDirty(itemsFromOtherCollection as ScriptableObject); + changed = true; + + } + } + } + if (changed) ObjectUtility.SetDirty(this); #endif @@ -607,4 +657,4 @@ protected override void ClearCachedValues() cachedValues = null; } } -} +} \ No newline at end of file diff --git a/Scripts/Runtime/Core/ScriptableObjectCollectionItem.cs b/Scripts/Runtime/Core/ScriptableObjectCollectionItem.cs index ed75e14..5950dae 100644 --- a/Scripts/Runtime/Core/ScriptableObjectCollectionItem.cs +++ b/Scripts/Runtime/Core/ScriptableObjectCollectionItem.cs @@ -19,7 +19,7 @@ public LongGuid GUID } } - [SerializeField, HideInInspector] + [SerializeField, CollectionReferenceLongGuid] private LongGuid collectionGUID; @@ -79,6 +79,7 @@ public void SetCollection(ScriptableObjectCollection collection) public void ClearCollection() { cachedCollection = null; + hasCachedCollection = false; collectionGUID = default; ObjectUtility.SetDirty(this); } diff --git a/Scripts/Runtime/Utils/SOCItemUtility.cs b/Scripts/Runtime/Utils/SOCItemUtility.cs new file mode 100644 index 0000000..91bfbb0 --- /dev/null +++ b/Scripts/Runtime/Utils/SOCItemUtility.cs @@ -0,0 +1,56 @@ +using System; +using System.IO; +#if UNITY_EDITOR +using UnityEditor; +#endif +using UnityEngine; + +namespace BrunoMikoski.ScriptableObjectCollections +{ + public static class SOCItemUtility + { + public static void MoveItem(ScriptableObject item, ScriptableObjectCollection targetCollection, + Action onCompleteCallback = null) + { + if (item is ISOCItem) + { + MoveItem(item, targetCollection, onCompleteCallback); + } + } + + public static void MoveItem(ISOCItem item, ScriptableObjectCollection targetCollection, Action onCompleteCallback = null) + { +#if UNITY_EDITOR + Undo.RecordObject(item.Collection, "Move Item"); + Undo.RecordObject(targetCollection, "Move Item"); + + item.Collection.Remove(item); + targetCollection.Add(item); + item.SetCollection(targetCollection); + + string itemPath = AssetDatabase.GetAssetPath(item as ScriptableObject); + string targetCollectionPath = AssetDatabase.GetAssetPath(targetCollection); + + if (!string.IsNullOrEmpty(itemPath) && !string.IsNullOrEmpty(targetCollectionPath)) + { + string directory = Path.GetDirectoryName(targetCollectionPath); + + string itemsFolderPath = Path.Combine(directory, "Items"); + bool hasItemsFolder = AssetDatabase.IsValidFolder(itemsFolderPath); + + string finalDirectory = hasItemsFolder ? itemsFolderPath : directory; + string fileName = Path.GetFileName(itemPath); + + string newPath = AssetDatabase.GenerateUniqueAssetPath(Path.Combine(finalDirectory, fileName)); + + AssetDatabase.MoveAsset(itemPath, newPath); + } + + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + onCompleteCallback?.Invoke(); +#endif + } + } +} \ No newline at end of file diff --git a/Scripts/Runtime/Utils/SOCItemUtility.cs.meta b/Scripts/Runtime/Utils/SOCItemUtility.cs.meta new file mode 100644 index 0000000..569f104 --- /dev/null +++ b/Scripts/Runtime/Utils/SOCItemUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f5f5245140e749748251516813de5ebe +timeCreated: 1739121561 \ No newline at end of file diff --git a/package.json b/package.json index f385dc2..425ebb7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "com.brunomikoski.scriptableobjectcollection", "displayName": "Scriptable Object Collection", - "version": "2.3.8", + "version": "2.3.9", "unity": "2022.2", "description": "A library to help improve the usability of Unity3D Scriptable Objects by grouping them into a collection and exposing them by code or nice inspectors!", "keywords": [