From dc901b98950b58ffacf9d5d63df1dad99c0d691e Mon Sep 17 00:00:00 2001 From: Konstantin Dyachenko Date: Thu, 5 Mar 2026 09:03:19 +0700 Subject: [PATCH] [Add] Debugger Inventory & small ui fixes --- .../Prefab/UI/Game Info/Game Info View.prefab | 10 +- .../Prefab/UI/Inventory/Inventory Slot.prefab | 12 +- .../Prefab/UI/Inventory/Inventory View.prefab | 2 +- Assets/Prefab/UI/Shop/Shop Item View.prefab | 4 +- Assets/Prefab/UI/Shop/ShopTooltipView.prefab | 13 +- Assets/Scenes/Scene.unity | 4 - .../Editor/ModifierDefinitionValidator.cs | 224 ------------- .../ModifierDefinitionValidator.cs.meta | 2 - .../Editor/ModifierInventoryDebugWindow.cs | 310 ++++++++++++++++++ .../ModifierInventoryDebugWindow.cs.meta | 2 + 10 files changed, 334 insertions(+), 249 deletions(-) delete mode 100644 Assets/Scripts/Modifiers/Editor/ModifierDefinitionValidator.cs delete mode 100644 Assets/Scripts/Modifiers/Editor/ModifierDefinitionValidator.cs.meta create mode 100644 Assets/Scripts/Modifiers/Editor/ModifierInventoryDebugWindow.cs create mode 100644 Assets/Scripts/Modifiers/Editor/ModifierInventoryDebugWindow.cs.meta diff --git a/Assets/Prefab/UI/Game Info/Game Info View.prefab b/Assets/Prefab/UI/Game Info/Game Info View.prefab index 1633753..05d8db5 100644 --- a/Assets/Prefab/UI/Game Info/Game Info View.prefab +++ b/Assets/Prefab/UI/Game Info/Game Info View.prefab @@ -516,7 +516,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!224 &2533462241018374848 RectTransform: m_ObjectHideFlags: 0 @@ -740,7 +740,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 703621256034232799, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_SizeDelta.x - value: 122.6 + value: 75 objectReference: {fileID: 0} - target: {fileID: 703621256034232799, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_SizeDelta.y @@ -776,7 +776,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 703621256034232799, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_AnchoredPosition.x - value: 61.302 + value: 37.158817 objectReference: {fileID: 0} - target: {fileID: 703621256034232799, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_AnchoredPosition.y @@ -1019,7 +1019,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 703621256034232799, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_SizeDelta.x - value: 77.396 + value: 125 objectReference: {fileID: 0} - target: {fileID: 703621256034232799, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_SizeDelta.y @@ -1055,7 +1055,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 703621256034232799, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_AnchoredPosition.x - value: -38.698 + value: -62.671 objectReference: {fileID: 0} - target: {fileID: 703621256034232799, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_AnchoredPosition.y diff --git a/Assets/Prefab/UI/Inventory/Inventory Slot.prefab b/Assets/Prefab/UI/Inventory/Inventory Slot.prefab index 5f45c00..8328fea 100644 --- a/Assets/Prefab/UI/Inventory/Inventory Slot.prefab +++ b/Assets/Prefab/UI/Inventory/Inventory Slot.prefab @@ -465,7 +465,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Color: {r: 0.5188679, g: 0.5188679, b: 0.5188679, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 @@ -655,7 +655,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Color: {r: 0.2830189, g: 0.2830189, b: 0.2830189, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 @@ -1450,15 +1450,15 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 3472307258458128773, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_fontColor.b - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 3472307258458128773, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_fontColor.g - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 3472307258458128773, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_fontColor.r - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 3472307258458128773, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_fontSizeBase @@ -1466,7 +1466,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 3472307258458128773, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_fontColor32.rgba - value: 4278190080 + value: 4294967295 objectReference: {fileID: 0} - target: {fileID: 3472307258458128773, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_VerticalAlignment diff --git a/Assets/Prefab/UI/Inventory/Inventory View.prefab b/Assets/Prefab/UI/Inventory/Inventory View.prefab index d69ea3e..3a1ab35 100644 --- a/Assets/Prefab/UI/Inventory/Inventory View.prefab +++ b/Assets/Prefab/UI/Inventory/Inventory View.prefab @@ -243,7 +243,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Color: {r: 0.7924528, g: 0.7924528, b: 0.7924528, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 diff --git a/Assets/Prefab/UI/Shop/Shop Item View.prefab b/Assets/Prefab/UI/Shop/Shop Item View.prefab index 6fff2e8..8f2a6cc 100644 --- a/Assets/Prefab/UI/Shop/Shop Item View.prefab +++ b/Assets/Prefab/UI/Shop/Shop Item View.prefab @@ -65,7 +65,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Color: {r: 0.4433962, g: 0.4433962, b: 0.4433962, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 @@ -323,7 +323,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Color: {r: 0.2924528, g: 0.2924528, b: 0.2924528, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 diff --git a/Assets/Prefab/UI/Shop/ShopTooltipView.prefab b/Assets/Prefab/UI/Shop/ShopTooltipView.prefab index 45c4d6f..00caba6 100644 --- a/Assets/Prefab/UI/Shop/ShopTooltipView.prefab +++ b/Assets/Prefab/UI/Shop/ShopTooltipView.prefab @@ -18,7 +18,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!224 &133637959725470091 RectTransform: m_ObjectHideFlags: 0 @@ -38,7 +38,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 39.7049, y: -46.6634} + m_AnchoredPosition: {x: 512.5834, y: 300.2} m_SizeDelta: {x: 150, y: 150} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &7291137291065553443 @@ -186,7 +186,8 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 3472307258458128773, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_text - value: Name + value: "\u0427\u0438\u0441\u0442\u044B\u0439 \u043C\u043D\u043E\u0436\u0438\u0442\u0435\u043B\u044C + x1.5" objectReference: {fileID: 0} - target: {fileID: 3472307258458128773, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_fontSize @@ -327,7 +328,9 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 3472307258458128773, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_text - value: Description Text + value: "\u0423\u043C\u043D\u043E\u0436\u0430\u0435\u0442 \u0438\u0442\u043E\u0433\u043E\u0432\u044B\u0439 + \u0441\u0447\u0435\u0442 \u043A\u0430\u0442\u0435\u0433\u043E\u0440\u0438\u0438 + \u043D\u0430 1.5." objectReference: {fileID: 0} - target: {fileID: 3472307258458128773, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_fontSize @@ -476,7 +479,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 3472307258458128773, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_text - value: 123 + value: 'Price: 260' objectReference: {fileID: 0} - target: {fileID: 3472307258458128773, guid: 0829148555ff32841afde9f6193a0b72, type: 3} propertyPath: m_fontSize diff --git a/Assets/Scenes/Scene.unity b/Assets/Scenes/Scene.unity index e029bec..16918f5 100644 --- a/Assets/Scenes/Scene.unity +++ b/Assets/Scenes/Scene.unity @@ -2041,10 +2041,6 @@ PrefabInstance: propertyPath: m_Name value: Game Info View objectReference: {fileID: 0} - - target: {fileID: 5167299410648281090, guid: 010ebb8b9becf6b45930c5fb7a5c95e0, type: 3} - propertyPath: m_IsActive - value: 0 - objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] diff --git a/Assets/Scripts/Modifiers/Editor/ModifierDefinitionValidator.cs b/Assets/Scripts/Modifiers/Editor/ModifierDefinitionValidator.cs deleted file mode 100644 index c25df6e..0000000 --- a/Assets/Scripts/Modifiers/Editor/ModifierDefinitionValidator.cs +++ /dev/null @@ -1,224 +0,0 @@ -#if UNITY_EDITOR -using System.Collections.Generic; -using UnityEditor; -using UnityEngine; -using YachtDice.Modifiers.Definition; - -namespace YachtDice.Modifiers.Editor -{ - public static class ModifierDefinitionValidator - { - [MenuItem("YachtDice/Validate All Modifier Definitions")] - public static void ValidateAll() - { - string[] guids = AssetDatabase.FindAssets("t:ModifierDefinitionSO"); - - if (guids.Length == 0) - { - Debug.Log("[ModifierValidator] No ModifierDefinitionSO assets found."); - return; - } - - var errorCount = 0; - var warnCount = 0; - var usedIds = new Dictionary(); // id -> asset path - - foreach (var t in guids) - { - var path = AssetDatabase.GUIDToAssetPath(t); - var def = AssetDatabase.LoadAssetAtPath(path); - - if (def == null) - { - Debug.LogError($"[ModifierValidator] Failed to load asset at {path}"); - errorCount++; - continue; - } - - // ── Id checks ──────────────────────────────────────── - - if (string.IsNullOrWhiteSpace(def.Id)) - { - Debug.LogError($"[ModifierValidator] {path}: Id is empty.", def); - errorCount++; - } - else if (usedIds.TryGetValue(def.Id, out string existingPath)) - { - Debug.LogError($"[ModifierValidator] {path}: Duplicate Id '{def.Id}' (also used by {existingPath}).", def); - errorCount++; - } - else - { - usedIds[def.Id] = path; - } - - // ── Economy checks ─────────────────────────────────── - - if (def.ShopPrice < 0) - { - Debug.LogError($"[ModifierValidator] {path}: ShopPrice is negative ({def.ShopPrice}).", def); - errorCount++; - } - - if (def.SellPrice < 0) - { - Debug.LogError($"[ModifierValidator] {path}: SellPrice is negative ({def.SellPrice}).", def); - errorCount++; - } - - if (def.SellPrice > def.ShopPrice && def.ShopPrice > 0) - { - Debug.LogWarning($"[ModifierValidator] {path}: SellPrice ({def.SellPrice}) > ShopPrice ({def.ShopPrice}). Infinite money exploit?", def); - warnCount++; - } - - // ── Durability checks ──────────────────────────────── - - if (def.HasLimitedUses && def.MaxUses <= 0) - { - Debug.LogError($"[ModifierValidator] {path}: HasLimitedUses is true but MaxUses is {def.MaxUses}.", def); - errorCount++; - } - - if (!def.HasLimitedUses && def.MaxUses > 0) - { - Debug.LogWarning($"[ModifierValidator] {path}: HasLimitedUses is false but MaxUses is {def.MaxUses}. Ignored at runtime.", def); - warnCount++; - } - - if (def.MaxStacks < 1) - { - Debug.LogError($"[ModifierValidator] {path}: MaxStacks must be >= 1 (is {def.MaxStacks}).", def); - errorCount++; - } - - // ── Behavior checks ────────────────────────────────── - - if (def.Behaviors == null || def.Behaviors.Count == 0) - { - Debug.LogWarning($"[ModifierValidator] {path}: No behaviors assigned. Modifier will do nothing.", def); - warnCount++; - continue; - } - - for (int b = 0; b < def.Behaviors.Count; b++) - { - var behavior = def.Behaviors[b]; - - if (behavior == null) - { - Debug.LogError($"[ModifierValidator] {path}: Behavior slot [{b}] is null.", def); - errorCount++; - continue; - } - - // Check for null conditions - if (behavior.Conditions != null) - { - for (int c = 0; c < behavior.Conditions.Count; c++) - { - if (behavior.Conditions[c] == null) - { - Debug.LogWarning($"[ModifierValidator] {path}: Behavior '{behavior.name}' has null condition at slot [{c}].", behavior); - warnCount++; - } - } - } - - // Check for null or empty effects - if (behavior.Effects == null || behavior.Effects.Count == 0) - { - Debug.LogWarning($"[ModifierValidator] {path}: Behavior '{behavior.name}' has no effects.", behavior); - warnCount++; - } - else - { - for (int e = 0; e < behavior.Effects.Count; e++) - { - if (behavior.Effects[e] == null) - { - Debug.LogError($"[ModifierValidator] {path}: Behavior '{behavior.name}' has null effect at slot [{e}].", behavior); - errorCount++; - } - } - } - } - - // ── Display checks ─────────────────────────────────── - - if (string.IsNullOrWhiteSpace(def.DisplayName)) - { - Debug.LogWarning($"[ModifierValidator] {path}: DisplayName is empty.", def); - warnCount++; - } - - if (string.IsNullOrWhiteSpace(def.Description)) - { - Debug.LogWarning($"[ModifierValidator] {path}: Description is empty.", def); - warnCount++; - } - } - - string summary = $"[ModifierValidator] Validated {guids.Length} modifier(s): {errorCount} error(s), {warnCount} warning(s)."; - - if (errorCount > 0) - Debug.LogError(summary); - else if (warnCount > 0) - Debug.LogWarning(summary); - else - Debug.Log(summary); - } - - [MenuItem("YachtDice/Validate Modifier Catalog")] - public static void ValidateCatalog() - { - string[] guids = AssetDatabase.FindAssets("t:ModifierCatalogSO"); - - if (guids.Length == 0) - { - Debug.LogWarning("[ModifierValidator] No ModifierCatalogSO asset found. Create one via Create > YachtDice/Modifiers/Catalog."); - return; - } - - for (int i = 0; i < guids.Length; i++) - { - string path = AssetDatabase.GUIDToAssetPath(guids[i]); - var catalog = AssetDatabase.LoadAssetAtPath(path); - - if (catalog == null) - { - Debug.LogError($"[ModifierValidator] Failed to load catalog at {path}"); - continue; - } - - if (catalog.All == null || catalog.All.Count == 0) - { - Debug.LogWarning($"[ModifierValidator] Catalog at {path} is empty."); - continue; - } - - int nullCount = 0; - var catalogIds = new HashSet(); - - for (int j = 0; j < catalog.All.Count; j++) - { - if (catalog.All[j] == null) - { - nullCount++; - Debug.LogError($"[ModifierValidator] Catalog {path}: Null entry at index [{j}].", catalog); - continue; - } - - string id = catalog.All[j].Id; - if (!catalogIds.Add(id)) - { - Debug.LogError($"[ModifierValidator] Catalog {path}: Duplicate modifier Id '{id}' in catalog.", catalog); - } - } - - Debug.Log($"[ModifierValidator] Catalog {path}: {catalog.All.Count} entries, {nullCount} null."); - } - } - } -} -#endif diff --git a/Assets/Scripts/Modifiers/Editor/ModifierDefinitionValidator.cs.meta b/Assets/Scripts/Modifiers/Editor/ModifierDefinitionValidator.cs.meta deleted file mode 100644 index 3d2e420..0000000 --- a/Assets/Scripts/Modifiers/Editor/ModifierDefinitionValidator.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 2f07f633fcb085e49890cec1280b4129 \ No newline at end of file diff --git a/Assets/Scripts/Modifiers/Editor/ModifierInventoryDebugWindow.cs b/Assets/Scripts/Modifiers/Editor/ModifierInventoryDebugWindow.cs new file mode 100644 index 0000000..816063e --- /dev/null +++ b/Assets/Scripts/Modifiers/Editor/ModifierInventoryDebugWindow.cs @@ -0,0 +1,310 @@ +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using YachtDice.Inventory; +using YachtDice.Modifiers.Definition; +using YachtDice.Modifiers.Runtime; + +namespace YachtDice.Modifiers.Editor +{ + public class ModifierInventoryDebugWindow : EditorWindow + { + private const double RepaintIntervalSeconds = 0.5d; + + private readonly List _allDefinitions = new(); + + private Vector2 _catalogScroll; + private Vector2 _inventoryScroll; + private string _search = string.Empty; + private InventoryController _inventoryController; + private double _nextRepaintTime; + + [MenuItem("YachtDice/Debug/Modifier Inventory")] + public static void Open() + { + var window = GetWindow("Modifier Debug"); + window.minSize = new Vector2(700f, 400f); + window.RefreshDefinitions(); + window.ResolveInventoryController(); + } + + private void OnEnable() + { + RefreshDefinitions(); + ResolveInventoryController(); + EditorApplication.playModeStateChanged += HandlePlayModeStateChanged; + } + + private void OnDisable() + { + EditorApplication.playModeStateChanged -= HandlePlayModeStateChanged; + } + + private void OnFocus() + { + RefreshDefinitions(); + ResolveInventoryController(); + } + + private void OnHierarchyChange() + { + if (!Application.isPlaying) + return; + + ResolveInventoryController(); + Repaint(); + } + + private void Update() + { + if (EditorApplication.timeSinceStartup < _nextRepaintTime) + return; + + _nextRepaintTime = EditorApplication.timeSinceStartup + RepaintIntervalSeconds; + + if (Application.isPlaying && (_inventoryController == null || _inventoryController.Model == null)) + ResolveInventoryController(); + + Repaint(); + } + + private void OnGUI() + { + DrawToolbar(); + + if (!Application.isPlaying) + { + EditorGUILayout.HelpBox("Enter Play Mode to edit runtime inventory state.", MessageType.Info); + } + + var model = GetInventoryModel(); + if (Application.isPlaying && model == null) + { + EditorGUILayout.HelpBox("InventoryController was not found in the scene.", MessageType.Warning); + } + + DrawOwnedModifiers(model); + EditorGUILayout.Space(8f); + DrawDefinitionCatalog(model); + } + + private void DrawToolbar() + { + using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar)) + { + if (GUILayout.Button("Refresh Catalog", EditorStyles.toolbarButton)) + RefreshDefinitions(); + + if (GUILayout.Button("Find Inventory", EditorStyles.toolbarButton)) + ResolveInventoryController(); + + GUILayout.FlexibleSpace(); + EditorGUILayout.LabelField("Search", GUILayout.Width(45f)); + _search = EditorGUILayout.TextField(_search, GUILayout.Width(220f)); + } + } + + private void DrawOwnedModifiers(InventoryModel model) + { + EditorGUILayout.LabelField("Owned Modifiers", EditorStyles.boldLabel); + + if (model == null) + { + EditorGUILayout.HelpBox("Inventory is unavailable.", MessageType.None); + return; + } + + EditorGUILayout.LabelField($"Active slots: {model.ActiveCount}/{model.MaxActiveSlots}"); + + var snapshot = new List(model.OwnedModifiers); + if (snapshot.Count == 0) + { + EditorGUILayout.HelpBox("Inventory is empty.", MessageType.None); + return; + } + + _inventoryScroll = EditorGUILayout.BeginScrollView(_inventoryScroll, GUILayout.MinHeight(140f)); + + foreach (var instance in snapshot) + { + DrawOwnedModifierRow(model, instance); + } + + EditorGUILayout.EndScrollView(); + } + + private void DrawOwnedModifierRow(InventoryModel model, ModifierInstance instance) + { + var definition = instance.Definition; + if (definition == null) + { + using (new EditorGUILayout.VerticalScope("box")) + { + EditorGUILayout.LabelField("", EditorStyles.boldLabel); + if (GUILayout.Button("Remove", GUILayout.Width(90f))) + model.RemoveModifier(instance); + } + + return; + } + + var state = instance.IsActive ? "Active" : "Inactive"; + var uses = definition.HasLimitedUses + ? $"Uses: {instance.RemainingUses}/{definition.MaxUses}" + : "Uses: infinite"; + + using (new EditorGUILayout.VerticalScope("box")) + { + EditorGUILayout.LabelField(BuildDefinitionLabel(definition), EditorStyles.boldLabel); + EditorGUILayout.LabelField($"State: {state} | {uses}"); + + using (new EditorGUILayout.HorizontalScope()) + { + using (new EditorGUI.DisabledScope(instance.IsActive)) + { + if (GUILayout.Button("Activate", GUILayout.Width(90f))) + { + if (!model.TryActivate(instance)) + Debug.LogWarning($"[ModifierDebug] Failed to activate '{definition.Id}'. Check slot limits."); + } + } + + using (new EditorGUI.DisabledScope(!instance.IsActive)) + { + if (GUILayout.Button("Deactivate", GUILayout.Width(90f))) + model.Deactivate(instance); + } + + if (GUILayout.Button("Remove", GUILayout.Width(90f))) + model.RemoveModifier(instance); + } + } + } + + private void DrawDefinitionCatalog(InventoryModel model) + { + EditorGUILayout.LabelField("All Modifier Definitions", EditorStyles.boldLabel); + EditorGUILayout.LabelField($"Loaded assets: {_allDefinitions.Count}"); + + if (_allDefinitions.Count == 0) + { + EditorGUILayout.HelpBox("No ModifierDefinition assets found.", MessageType.Warning); + return; + } + + _catalogScroll = EditorGUILayout.BeginScrollView(_catalogScroll); + + var loweredSearch = string.IsNullOrWhiteSpace(_search) + ? string.Empty + : _search.Trim().ToLowerInvariant(); + + for (var i = 0; i < _allDefinitions.Count; i++) + { + var definition = _allDefinitions[i]; + if (definition == null) + continue; + + if (!MatchesSearch(definition, loweredSearch)) + continue; + + DrawDefinitionRow(model, definition); + } + + EditorGUILayout.EndScrollView(); + } + + private void DrawDefinitionRow(InventoryModel model, ModifierDefinition definition) + { + var uses = definition.HasLimitedUses ? $"limited ({definition.MaxUses})" : "permanent"; + + using (new EditorGUILayout.HorizontalScope("box")) + { + EditorGUILayout.LabelField($"{BuildDefinitionLabel(definition)} | {uses}"); + + using (new EditorGUI.DisabledScope(model == null)) + { + if (GUILayout.Button("Add", GUILayout.Width(90f))) + model.AddModifier(definition); + } + } + } + + private static bool MatchesSearch(ModifierDefinition definition, string loweredSearch) + { + if (string.IsNullOrEmpty(loweredSearch)) + return true; + + var id = definition.Id ?? string.Empty; + var displayName = definition.DisplayName ?? string.Empty; + return id.IndexOf(loweredSearch, StringComparison.OrdinalIgnoreCase) >= 0 + || displayName.IndexOf(loweredSearch, StringComparison.OrdinalIgnoreCase) >= 0; + } + + private static string BuildDefinitionLabel(ModifierDefinition definition) + { + var displayName = string.IsNullOrWhiteSpace(definition.DisplayName) + ? "" + : definition.DisplayName; + var id = string.IsNullOrWhiteSpace(definition.Id) + ? "" + : definition.Id; + return $"{displayName} [{id}]"; + } + + private InventoryModel GetInventoryModel() + { + if (!Application.isPlaying) + return null; + + if (_inventoryController == null) + ResolveInventoryController(); + + return _inventoryController != null ? _inventoryController.Model : null; + } + + private void ResolveInventoryController() + { + if (!Application.isPlaying) + { + _inventoryController = null; + return; + } + + _inventoryController = FindObjectOfType(); + } + + private void RefreshDefinitions() + { + _allDefinitions.Clear(); + + var guids = AssetDatabase.FindAssets("t:ModifierDefinition"); + for (var i = 0; i < guids.Length; i++) + { + var path = AssetDatabase.GUIDToAssetPath(guids[i]); + var definition = AssetDatabase.LoadAssetAtPath(path); + if (definition != null) + _allDefinitions.Add(definition); + } + + _allDefinitions.Sort((a, b) => + { + var nameComparison = string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase); + if (nameComparison != 0) + return nameComparison; + return string.Compare(a.Id, b.Id, StringComparison.OrdinalIgnoreCase); + }); + } + + private void HandlePlayModeStateChanged(PlayModeStateChange change) + { + if (change == PlayModeStateChange.EnteredPlayMode) + ResolveInventoryController(); + + if (change == PlayModeStateChange.ExitingPlayMode || change == PlayModeStateChange.EnteredEditMode) + _inventoryController = null; + + Repaint(); + } + } +} diff --git a/Assets/Scripts/Modifiers/Editor/ModifierInventoryDebugWindow.cs.meta b/Assets/Scripts/Modifiers/Editor/ModifierInventoryDebugWindow.cs.meta new file mode 100644 index 0000000..cd4175d --- /dev/null +++ b/Assets/Scripts/Modifiers/Editor/ModifierInventoryDebugWindow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4a8b096304878c94e83fb2a8c711a969 \ No newline at end of file