#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; } int errorCount = 0; int warnCount = 0; var usedIds = new Dictionary(); // id -> asset path for (int i = 0; i < guids.Length; i++) { string path = AssetDatabase.GUIDToAssetPath(guids[i]); 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