Files
AppleHillsProduction/Assets/Editor/PuzzleSystem/PuzzleEditorWindow.cs

876 lines
32 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
using PuzzleS;
namespace AppleHills.Editor.PuzzleSystem
{
/// <summary>
/// Editor utility for managing puzzle steps and debugging puzzle state at runtime.
/// Provides tabs for both editing puzzle data and runtime debugging.
/// </summary>
public class PuzzleEditorWindow : EditorWindow
{
// Paths
private const string PuzzleDataBasePath = "Assets/Data";
private const string MenuPath = "AppleHills/Puzzle Editor";
// Editor state
private List<PuzzleStepSO> _allPuzzleSteps = new List<PuzzleStepSO>();
private Dictionary<string, List<PuzzleStepSO>> _puzzleStepsByFolder = new Dictionary<string, List<PuzzleStepSO>>();
private PuzzleStepSO _selectedStep;
private Dictionary<string, bool> _folderExpanded = new Dictionary<string, bool>();
private Vector2 _puzzleListScrollPosition;
private Vector2 _puzzleEditScrollPosition;
private string _searchQuery = "";
private bool _isDirty = false;
// Tab management
private int _selectedTab = 0;
private readonly string[] _tabNames = { "Edit", "Debug" };
// Runtime debug state
private Dictionary<string, bool> _stepUnlockState = new Dictionary<string, bool>();
private Dictionary<string, bool> _stepCompletedState = new Dictionary<string, bool>();
private Vector2 _debugScrollPosition;
private bool _isPlaying = false;
private bool _hasRuntimeData = false;
private PuzzleLevelDataSO _runtimeLevelData;
// New step creation
private string _newStepName = "New Step";
private string _selectedFolder = "";
private bool _showCreateNewStepDialog = false;
[MenuItem(MenuPath)]
public static void ShowWindow()
{
var window = GetWindow<PuzzleEditorWindow>("Puzzle Editor");
window.minSize = new Vector2(800, 600);
window.Show();
}
private void OnEnable()
{
// Load all puzzle steps
LoadAllPuzzleSteps();
// Register for undo/redo
Undo.undoRedoPerformed += OnUndoRedo;
// Set up update callbacks
EditorApplication.update += OnEditorUpdate;
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
}
private void OnDisable()
{
// Unregister from undo/redo
Undo.undoRedoPerformed -= OnUndoRedo;
// Unregister from update
EditorApplication.update -= OnEditorUpdate;
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
}
private void OnEditorUpdate()
{
// Check if we're in play mode
bool currentlyPlaying = EditorApplication.isPlaying && !EditorApplication.isPaused;
if (_isPlaying != currentlyPlaying)
{
_isPlaying = currentlyPlaying;
Repaint();
}
// In play mode, update runtime data periodically
if (_isPlaying)
{
UpdateRuntimeData();
Repaint();
}
}
private void OnUndoRedo()
{
_isDirty = true;
Repaint();
}
private void OnPlayModeStateChanged(PlayModeStateChange state)
{
if (state == PlayModeStateChange.EnteredPlayMode)
{
_isPlaying = true;
_hasRuntimeData = false;
_stepUnlockState.Clear();
_stepCompletedState.Clear();
}
else if (state == PlayModeStateChange.ExitingPlayMode)
{
_isPlaying = false;
_hasRuntimeData = false;
_runtimeLevelData = null;
}
Repaint();
}
private void OnGUI()
{
DrawHeader();
_selectedTab = GUILayout.Toolbar(_selectedTab, _tabNames);
EditorGUILayout.Space();
switch (_selectedTab)
{
case 0: // Edit tab
DrawEditTab();
break;
case 1: // Debug tab
DrawDebugTab();
break;
}
// Apply any pending changes
if (_isDirty)
{
SaveChanges();
_isDirty = false;
}
}
#region Header UI
private void DrawHeader()
{
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
if (GUILayout.Button("Refresh", EditorStyles.toolbarButton, GUILayout.Width(60)))
{
LoadAllPuzzleSteps();
}
GUILayout.FlexibleSpace();
// Tab-specific toolbar options
if (_selectedTab == 0) // Edit tab
{
if (GUILayout.Button("Create New", EditorStyles.toolbarButton, GUILayout.Width(80)))
{
_showCreateNewStepDialog = true;
}
}
else if (_selectedTab == 1) // Debug tab
{
EditorGUILayout.LabelField(_isPlaying ? "Runtime Active" : "Editor Mode", EditorStyles.toolbarButton, GUILayout.Width(100));
}
EditorGUILayout.EndHorizontal();
}
#endregion
#region Edit Tab
private void DrawEditTab()
{
EditorGUILayout.BeginHorizontal();
// Left panel - puzzle step list
EditorGUILayout.BeginVertical(GUILayout.Width(250));
DrawStepListPanel();
EditorGUILayout.EndVertical();
// Separator
EditorGUILayout.Space();
// Right panel - puzzle step editor
EditorGUILayout.BeginVertical();
DrawStepEditorPanel();
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
// Draw create new step dialog if needed
if (_showCreateNewStepDialog)
{
DrawCreateNewStepDialog();
}
}
private void DrawStepListPanel()
{
// Search field
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
_searchQuery = EditorGUILayout.TextField(_searchQuery, EditorStyles.toolbarSearchField);
if (GUILayout.Button("×", EditorStyles.toolbarButton, GUILayout.Width(20)) && !string.IsNullOrEmpty(_searchQuery))
{
_searchQuery = "";
GUI.FocusControl(null);
}
EditorGUILayout.EndHorizontal();
_puzzleListScrollPosition = EditorGUILayout.BeginScrollView(_puzzleListScrollPosition);
// If search query exists, show filtered results across all folders
if (!string.IsNullOrEmpty(_searchQuery))
{
var filteredSteps = _allPuzzleSteps.Where(step =>
step.displayName.ToLower().Contains(_searchQuery.ToLower()) ||
step.stepId.ToLower().Contains(_searchQuery.ToLower())).ToList();
if (filteredSteps.Any())
{
EditorGUILayout.LabelField($"Search Results ({filteredSteps.Count}):", EditorStyles.boldLabel);
foreach (var step in filteredSteps)
{
if (DrawStepListItem(step))
{
_selectedStep = step;
GUI.FocusControl(null);
}
}
}
else
{
EditorGUILayout.LabelField("No matching steps found");
}
}
// Otherwise show organized by folder
else
{
foreach (var folderEntry in _puzzleStepsByFolder)
{
string folderName = folderEntry.Key;
List<PuzzleStepSO> steps = folderEntry.Value;
if (!_folderExpanded.ContainsKey(folderName))
{
_folderExpanded[folderName] = true; // Default to expanded
}
// Folder header with toggle
EditorGUILayout.BeginHorizontal();
_folderExpanded[folderName] = EditorGUILayout.Foldout(_folderExpanded[folderName], folderName, true);
// Show step count
EditorGUILayout.LabelField($"({steps.Count})", GUILayout.Width(40));
EditorGUILayout.EndHorizontal();
// Draw steps in folder if expanded
if (_folderExpanded[folderName])
{
EditorGUI.indentLevel++;
foreach (var step in steps)
{
if (DrawStepListItem(step))
{
_selectedStep = step;
GUI.FocusControl(null);
}
}
EditorGUI.indentLevel--;
}
}
}
EditorGUILayout.EndScrollView();
}
private bool DrawStepListItem(PuzzleStepSO step)
{
if (step == null) return false;
bool isSelected = step == _selectedStep;
EditorGUILayout.BeginHorizontal(isSelected ? EditorStyles.selectionRect : EditorStyles.helpBox);
// Icon if available
if (step.icon != null)
{
GUILayout.Label(new GUIContent(step.icon.texture), GUILayout.Width(20), GUILayout.Height(20));
}
else
{
GUILayout.Space(24);
}
// Name and ID
EditorGUILayout.BeginVertical();
EditorGUILayout.LabelField(step.displayName, EditorStyles.boldLabel);
EditorGUILayout.LabelField(step.stepId, EditorStyles.miniLabel);
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
// Check if this item was clicked
Rect itemRect = GUILayoutUtility.GetLastRect();
bool wasClicked = Event.current.type == EventType.MouseDown && Event.current.button == 0
&& itemRect.Contains(Event.current.mousePosition);
if (wasClicked)
{
Event.current.Use();
}
return wasClicked;
}
private void DrawStepEditorPanel()
{
if (_selectedStep == null)
{
EditorGUILayout.HelpBox("Select a puzzle step to edit", MessageType.Info);
return;
}
_puzzleEditScrollPosition = EditorGUILayout.BeginScrollView(_puzzleEditScrollPosition);
EditorGUI.BeginChangeCheck();
// Header with name and ID
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Editing:", EditorStyles.boldLabel, GUILayout.Width(60));
EditorGUILayout.LabelField(_selectedStep.displayName, EditorStyles.boldLabel);
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
// Basic properties
EditorGUILayout.LabelField("Basic Properties", EditorStyles.boldLabel);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
// Step ID
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Step ID:", GUILayout.Width(100));
string newStepId = EditorGUILayout.TextField(_selectedStep.stepId);
if (newStepId != _selectedStep.stepId)
{
Undo.RecordObject(_selectedStep, "Change Step ID");
_selectedStep.stepId = newStepId;
_isDirty = true;
}
EditorGUILayout.EndHorizontal();
// Display Name
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Display Name:", GUILayout.Width(100));
string newDisplayName = EditorGUILayout.TextField(_selectedStep.displayName);
if (newDisplayName != _selectedStep.displayName)
{
Undo.RecordObject(_selectedStep, "Change Display Name");
_selectedStep.displayName = newDisplayName;
_isDirty = true;
}
EditorGUILayout.EndHorizontal();
// Description
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Description:", GUILayout.Width(100));
string newDescription = EditorGUILayout.TextArea(_selectedStep.description, GUILayout.Height(60));
if (newDescription != _selectedStep.description)
{
Undo.RecordObject(_selectedStep, "Change Description");
_selectedStep.description = newDescription;
_isDirty = true;
}
EditorGUILayout.EndHorizontal();
// Icon
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Icon:", GUILayout.Width(100));
Sprite newIcon = (Sprite)EditorGUILayout.ObjectField(_selectedStep.icon, typeof(Sprite), false);
if (newIcon != _selectedStep.icon)
{
Undo.RecordObject(_selectedStep, "Change Icon");
_selectedStep.icon = newIcon;
_isDirty = true;
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
// Unlocks (dependencies)
EditorGUILayout.LabelField("Unlocks", EditorStyles.boldLabel);
EditorGUILayout.HelpBox("Steps that will be unlocked when this step is completed", MessageType.Info);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
// Show unlocked steps list
if (_selectedStep.unlocks.Count > 0)
{
for (int i = 0; i < _selectedStep.unlocks.Count; i++)
{
EditorGUILayout.BeginHorizontal();
// Draw step selector
PuzzleStepSO newUnlockedStep = (PuzzleStepSO)EditorGUILayout.ObjectField(
_selectedStep.unlocks[i], typeof(PuzzleStepSO), false);
if (newUnlockedStep != _selectedStep.unlocks[i])
{
Undo.RecordObject(_selectedStep, "Change Unlocked Step");
_selectedStep.unlocks[i] = newUnlockedStep;
_isDirty = true;
}
// Remove button
if (GUILayout.Button("-", GUILayout.Width(20)))
{
Undo.RecordObject(_selectedStep, "Remove Unlocked Step");
_selectedStep.unlocks.RemoveAt(i);
_isDirty = true;
i--;
}
EditorGUILayout.EndHorizontal();
}
}
else
{
EditorGUILayout.LabelField("No steps will be unlocked");
}
// Add new dependency
if (GUILayout.Button("Add Unlocked Step"))
{
Undo.RecordObject(_selectedStep, "Add Unlocked Step");
_selectedStep.unlocks.Add(null);
_isDirty = true;
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
// Asset path info
string assetPath = AssetDatabase.GetAssetPath(_selectedStep);
EditorGUILayout.LabelField("Asset Path:", EditorStyles.miniLabel);
EditorGUILayout.LabelField(assetPath, EditorStyles.miniLabel);
// Delete button
EditorGUILayout.Space();
if (GUILayout.Button("Delete Step", GUILayout.Width(100)))
{
if (EditorUtility.DisplayDialog("Delete Puzzle Step",
$"Are you sure you want to delete '{_selectedStep.displayName}'? This action cannot be undone.",
"Delete", "Cancel"))
{
DeletePuzzleStep(_selectedStep);
_selectedStep = null;
}
}
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(_selectedStep);
}
EditorGUILayout.EndScrollView();
}
private void DrawCreateNewStepDialog()
{
// Create a centered window
Rect windowRect = new Rect(
(position.width - 400) / 2,
(position.height - 200) / 2,
400, 200);
GUI.Box(windowRect, "Create New Puzzle Step", EditorStyles.helpBox);
GUILayout.BeginArea(new Rect(windowRect.x + 10, windowRect.y + 30, windowRect.width - 20, windowRect.height - 40));
// Name field
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Name:", GUILayout.Width(80));
_newStepName = EditorGUILayout.TextField(_newStepName);
EditorGUILayout.EndHorizontal();
// Folder selection
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Folder:", GUILayout.Width(80));
// Create folder dropdown
List<string> folderNames = _puzzleStepsByFolder.Keys.ToList();
int selectedFolderIndex = folderNames.IndexOf(_selectedFolder);
int newSelectedFolderIndex = EditorGUILayout.Popup(selectedFolderIndex >= 0 ? selectedFolderIndex : 0, folderNames.ToArray());
if (newSelectedFolderIndex >= 0 && newSelectedFolderIndex < folderNames.Count)
{
_selectedFolder = folderNames[newSelectedFolderIndex];
}
else if (folderNames.Count > 0)
{
_selectedFolder = folderNames[0];
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
// Buttons
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Cancel", GUILayout.Width(100)))
{
_showCreateNewStepDialog = false;
}
if (GUILayout.Button("Create", GUILayout.Width(100)))
{
if (!string.IsNullOrEmpty(_newStepName) && !string.IsNullOrEmpty(_selectedFolder))
{
CreateNewPuzzleStep(_newStepName, _selectedFolder);
_showCreateNewStepDialog = false;
_newStepName = "New Step";
}
}
EditorGUILayout.EndHorizontal();
GUILayout.EndArea();
}
#endregion
#region Debug Tab
private void DrawDebugTab()
{
if (!_isPlaying)
{
EditorGUILayout.HelpBox("Enter Play Mode to debug puzzles at runtime", MessageType.Info);
return;
}
if (!_hasRuntimeData || _runtimeLevelData == null)
{
EditorGUILayout.HelpBox("Waiting for puzzle data to be loaded...", MessageType.Info);
return;
}
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
EditorGUILayout.LabelField($"Current Level: {_runtimeLevelData.levelId}", EditorStyles.boldLabel);
EditorGUILayout.EndHorizontal();
_debugScrollPosition = EditorGUILayout.BeginScrollView(_debugScrollPosition);
// List all steps with their current state
EditorGUILayout.LabelField("Puzzle Steps", EditorStyles.boldLabel);
// Show steps directly from the level data in a flat list
foreach (var step in _runtimeLevelData.allSteps)
{
if (step == null) continue;
DrawRuntimeStepItem(step);
}
EditorGUILayout.EndScrollView();
}
private void DrawRuntimeStepItem(PuzzleStepSO step)
{
bool isUnlocked = _stepUnlockState.ContainsKey(step.stepId) && _stepUnlockState[step.stepId];
bool isCompleted = _stepCompletedState.ContainsKey(step.stepId) && _stepCompletedState[step.stepId];
// Set background color based on state
Color originalColor = GUI.backgroundColor;
if (isCompleted)
GUI.backgroundColor = new Color(0.5f, 1f, 0.5f); // Green for completed
else if (isUnlocked)
GUI.backgroundColor = new Color(1f, 1f, 0.5f); // Yellow for unlocked but not completed
else
GUI.backgroundColor = new Color(1f, 0.5f, 0.5f); // Red for locked
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
// Reset color
GUI.backgroundColor = originalColor;
EditorGUILayout.BeginHorizontal();
// Step info
EditorGUILayout.BeginVertical(GUILayout.ExpandWidth(true));
EditorGUILayout.LabelField(step.displayName, EditorStyles.boldLabel);
EditorGUILayout.LabelField(step.stepId, EditorStyles.miniLabel);
// Status text
string statusText = isCompleted ? "Completed" : (isUnlocked ? "Unlocked" : "Locked");
EditorGUILayout.LabelField($"Status: {statusText}", EditorStyles.miniLabel);
EditorGUILayout.EndVertical();
// Action buttons
EditorGUILayout.BeginVertical(GUILayout.Width(100));
EditorGUI.BeginDisabledGroup(isCompleted);
if (GUILayout.Button(isUnlocked ? "Lock" : "Unlock"))
{
ToggleStepUnlocked(step);
}
EditorGUI.EndDisabledGroup();
EditorGUI.BeginDisabledGroup(!isUnlocked || isCompleted);
if (GUILayout.Button("Complete"))
{
CompleteStep(step);
}
EditorGUI.EndDisabledGroup();
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
}
#endregion
#region Data Management
private void LoadAllPuzzleSteps()
{
_allPuzzleSteps.Clear();
_puzzleStepsByFolder.Clear();
// Find all PuzzleStepSO assets in the project
string[] guids = AssetDatabase.FindAssets("t:PuzzleStepSO");
foreach (string guid in guids)
{
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
// Only include assets from the Data folder
if (assetPath.StartsWith(PuzzleDataBasePath))
{
PuzzleStepSO step = AssetDatabase.LoadAssetAtPath<PuzzleStepSO>(assetPath);
if (step != null)
{
_allPuzzleSteps.Add(step);
// Add to folder dictionary for organization
string folder = Path.GetDirectoryName(assetPath)?.Replace("\\", "/");
if (folder != null)
{
if (!_puzzleStepsByFolder.ContainsKey(folder))
{
_puzzleStepsByFolder[folder] = new List<PuzzleStepSO>();
}
_puzzleStepsByFolder[folder].Add(step);
}
}
}
}
// Make sure each folder is sorted by name
foreach (var key in _puzzleStepsByFolder.Keys.ToList())
{
_puzzleStepsByFolder[key] = _puzzleStepsByFolder[key]
.OrderBy(step => step.displayName)
.ToList();
}
_isDirty = false;
}
private void SaveChanges()
{
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
private void CreateNewPuzzleStep(string stepName, string folderPath)
{
// Create a new PuzzleStepSO
PuzzleStepSO newStep = CreateInstance<PuzzleStepSO>();
newStep.stepId = GenerateUniqueStepId(stepName);
newStep.displayName = stepName;
// Create the path
string assetPath = Path.Combine(folderPath, $"{stepName}.asset").Replace("\\", "/");
// Make sure the directory exists
string directory = Path.GetDirectoryName(assetPath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// Create the asset
AssetDatabase.CreateAsset(newStep, assetPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
// Reload all steps and select the new one
LoadAllPuzzleSteps();
_selectedStep = newStep;
}
private void DeletePuzzleStep(PuzzleStepSO step)
{
if (step == null) return;
string assetPath = AssetDatabase.GetAssetPath(step);
if (!string.IsNullOrEmpty(assetPath))
{
// Also need to remove all references to this step from other steps' unlocks lists
foreach (var otherStep in _allPuzzleSteps)
{
if (otherStep != null && otherStep != step)
{
if (otherStep.unlocks.Contains(step))
{
Undo.RecordObject(otherStep, "Remove Deleted Step Reference");
otherStep.unlocks.Remove(step);
EditorUtility.SetDirty(otherStep);
}
}
}
AssetDatabase.DeleteAsset(assetPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
// Reload all steps
LoadAllPuzzleSteps();
}
}
private string GenerateUniqueStepId(string baseName)
{
// Convert to lowercase and replace spaces with underscores
string baseId = baseName.ToLower().Replace(" ", "_");
// Check if this ID already exists
bool idExists = _allPuzzleSteps.Any(step => step.stepId == baseId);
if (!idExists)
{
return baseId;
}
// Add a number suffix if ID already exists
int counter = 1;
while (_allPuzzleSteps.Any(step => step.stepId == $"{baseId}_{counter}"))
{
counter++;
}
return $"{baseId}_{counter}";
}
#endregion
#region Runtime Debug Helpers
private void UpdateRuntimeData()
{
if (!_isPlaying) return;
// Find PuzzleManager instance
PuzzleManager puzzleManager = Object.FindObjectOfType<PuzzleManager>();
if (puzzleManager == null)
{
_hasRuntimeData = false;
return;
}
// Get current level data
var levelData = puzzleManager.GetCurrentLevelData();
if (levelData == null)
{
_hasRuntimeData = false;
return;
}
_hasRuntimeData = true;
_runtimeLevelData = levelData;
// Update step states
foreach (var step in _runtimeLevelData.allSteps)
{
if (step != null)
{
_stepUnlockState[step.stepId] = puzzleManager.IsStepUnlocked(step);
_stepCompletedState[step.stepId] = puzzleManager.IsPuzzleStepCompleted(step.stepId);
}
}
}
private void ToggleStepUnlocked(PuzzleStepSO step)
{
if (!_isPlaying || step == null) return;
PuzzleManager puzzleManager = Object.FindObjectOfType<PuzzleManager>();
if (puzzleManager == null) return;
// Get current unlock state
bool isCurrentlyUnlocked = _stepUnlockState.ContainsKey(step.stepId) && _stepUnlockState[step.stepId];
// Call appropriate method using reflection since these might be private methods
System.Type managerType = puzzleManager.GetType();
if (isCurrentlyUnlocked)
{
// Find the LockStep method that takes a PuzzleStepSO parameter
System.Reflection.MethodInfo lockMethod = managerType.GetMethod("LockStep",
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic);
if (lockMethod != null)
{
lockMethod.Invoke(puzzleManager, new object[] { step });
}
}
else
{
// Find the UnlockStep method that takes a PuzzleStepSO parameter
System.Reflection.MethodInfo unlockMethod = managerType.GetMethod("UnlockStep",
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic);
if (unlockMethod != null)
{
unlockMethod.Invoke(puzzleManager, new object[] { step });
}
}
// Update state
UpdateRuntimeData();
}
private void CompleteStep(PuzzleStepSO step)
{
if (!_isPlaying || step == null) return;
PuzzleManager puzzleManager = Object.FindObjectOfType<PuzzleManager>();
if (puzzleManager == null) return;
// Complete the step
puzzleManager.MarkPuzzleStepCompleted(step);
// Update state
UpdateRuntimeData();
}
#endregion
}
}