311 lines
11 KiB
C#
311 lines
11 KiB
C#
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<ModifierDefinition> _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<ModifierInventoryDebugWindow>("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<ModifierInstance>(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("<missing definition>", 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)
|
|
? "<unnamed>"
|
|
: definition.DisplayName;
|
|
var id = string.IsNullOrWhiteSpace(definition.Id)
|
|
? "<no-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 = FindAnyObjectByType<InventoryController>();
|
|
}
|
|
|
|
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<ModifierDefinition>(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();
|
|
}
|
|
}
|
|
}
|