using UnityEditor; using UnityEngine; using System.Collections.Generic; public class PuzzleChainEditorWindow : EditorWindow { private List puzzleSteps = new List(); private Dictionary> dependencyGraph; private Vector2 scrollPos; private const int INDENT_SIZE = 24; [MenuItem("AppleHills/Puzzle Chain Editor")] public static void ShowWindow() { var window = GetWindow("Puzzle Chain Editor"); window.minSize = new Vector2(600, 400); window.maxSize = new Vector2(1200, 800); window.position = new Rect(100, 100, 700, 500); // Reasonable default size and position } private void OnEnable() { LoadPuzzleSteps(); ProcessPuzzleChains(); } private void LoadPuzzleSteps() { puzzleSteps.Clear(); // Find all PuzzleStepSO assets in the project string[] guids = AssetDatabase.FindAssets("t:PuzzleStepSO"); foreach (var guid in guids) { var path = AssetDatabase.GUIDToAssetPath(guid); // Only include those under Assets/Data/Puzzles (case-insensitive) if (path.Replace('\\', '/').StartsWith("Assets/Data/Puzzles", System.StringComparison.OrdinalIgnoreCase)) { var step = AssetDatabase.LoadAssetAtPath(path); if (step != null) puzzleSteps.Add(step); } } // Remove any nulls just in case puzzleSteps.RemoveAll(s => s == null); // Remove nulls from unlocks lists foreach (var step in puzzleSteps) { if (step.unlocks != null) step.unlocks.RemoveAll(u => u == null); } } private void ProcessPuzzleChains() { // Defensive: ensure no nulls in puzzleSteps or unlocks puzzleSteps.RemoveAll(s => s == null); foreach (var step in puzzleSteps) { if (step.unlocks != null) step.unlocks.RemoveAll(u => u == null); } dependencyGraph = PuzzleGraphUtility.BuildDependencyGraph(puzzleSteps); } private void OnGUI() { EditorGUILayout.LabelField("Puzzle Chain Visualization", EditorStyles.boldLabel); if (puzzleSteps.Count == 0) { EditorGUILayout.HelpBox("No PuzzleStepSO assets found in Assets/Data/Puzzles.", MessageType.Warning); return; } scrollPos = EditorGUILayout.BeginScrollView(scrollPos); var initialSteps = dependencyGraph != null ? PuzzleGraphUtility.FindInitialSteps(dependencyGraph) : new List(); foreach (var step in initialSteps) { if (step == null) continue; // Defensive EditorGUILayout.BeginVertical("box"); EditorGUILayout.LabelField($"Step Path: {step.displayName} ({step.stepId})", EditorStyles.largeLabel); GUILayout.Space(6); DrawStepTree(step, 0); EditorGUILayout.EndVertical(); GUILayout.Space(12); // Space between step paths } EditorGUILayout.EndScrollView(); } private void DrawStepTree(PuzzleStepSO step, int indent) { if (step == null) { EditorGUILayout.LabelField("[Missing Step]", EditorStyles.boldLabel); return; } EditorGUILayout.BeginHorizontal(); GUILayout.Space(indent * INDENT_SIZE); EditorGUILayout.BeginVertical("box"); EditorGUILayout.LabelField($"{step.displayName} ({step.stepId})", EditorStyles.boldLabel); EditorGUILayout.LabelField(step.description ?? "", EditorStyles.wordWrappedLabel); GUILayout.Space(4); if (GUILayout.Button("Open in Inspector", GUILayout.Width(150))) { Selection.activeObject = step; EditorGUIUtility.PingObject(step); } EditorGUILayout.EndVertical(); EditorGUILayout.EndHorizontal(); GUILayout.Space(6); if (step.unlocks != null) { foreach (var unlock in step.unlocks) { DrawStepTree(unlock, indent + 1); } } } }