using System; using System.Collections.Generic; using UnityEngine; public class CommandHandler : MonoBehaviour { public static CommandHandler Instance; //maybe refactor into a history of gamestate (similar to a picture where where we return, A list of gameObject, //initialy to keep tracks of position rotation scale, and eventually to keeps tracks of texture changes) // Also will be easier to pool resources because it would only be one type of class to handle // Should notify the undo button when current index is 0 to make the button unclickable as you can't undo anymore public Action OnUndoUnavailable; public Action OnUndoAvailable; // Should notify the Redo button when current index is History.Size() - 1 to make the button unclickable as you can't Redo anymore public Action OnRedoUnavailable; public Action OnRedoAvailable; //need to introduce a pooling system to reused Command to prevent Garbage Collector // everytime we remove Command from the list but for later public Action DelayOver; // Keep tracks of the executed commands ICommand[] _commandHistory; // keep tracks what command to undo and redo [SerializeField] int _currentIndex = 0; [SerializeField] int _currentHistorySize = 0; // 5 because of webgl limited spaces [SerializeField] int _maxHistorySize = 5; [SerializeField] string _undoAction = null; [SerializeField] string _redoAction = null; [SerializeField] List _commandNameHistory; [Header("Before Data Temp")] [SerializeField] string[] _beforeDataTemp; public string[] BeforeDataTemp { get { return _beforeDataTemp; } set { _beforeDataTemp = value; } } private void Awake() { if(Instance == null) { Instance = this; } else { Destroy(this); } _commandHistory = new ICommand[_maxHistorySize]; _commandNameHistory = new (); } private void Start() { CheckBoundaryCondition(); DelayOver+=UpdateCommands; } // Need to be called everytime a command is executed in the code // to be able to undo and redo along the history of commands void UpdateCommandNameHistory() { _commandNameHistory = new(); for (int i = 0; i < _currentIndex; i++) { _commandNameHistory.Add( _commandHistory[i].GetAction()); } } public void AddToHistory(ICommand command) { // Need to check the current index to add, compare it with command history Size and remove all // command past that point // exemple : history size == 4 so the index in the history ranges between 0 and 3 // current index == 1 because you have undo 2 times // by adding a new command, you need to remove the object in index 2 and 3 because // you are rewriting the history past that point bool isValid = IsCommandValid(command); if (isValid) { if (_currentIndex >= _maxHistorySize) { for (int i = 1; i < _currentHistorySize; i++) { _commandHistory[i - 1] = _commandHistory[i]; } _currentIndex--; } _commandHistory[_currentIndex] = command; command.Execute(); _currentIndex++; _currentHistorySize = _currentIndex; CheckBoundaryCondition(); } } private bool IsCommandValid(ICommand command) { bool isValid = true; int currentObjectNumber = command.GetObjectNumber(); if(currentObjectNumber >= 0) { for (int i = 1; i < _currentHistorySize; i++) { int objectNumber = _commandHistory[i].GetObjectNumber(); if (currentObjectNumber == objectNumber) { isValid = false; } } } if (currentObjectNumber >= _G.OBJs.Length - 1) { isValid = false; } return isValid; } public void Redo() { // if last Redo was index _commandHistory.Length - 1 and the check boundary condition // reached the button correctly, Redo should not be available right now if (_currentIndex < _currentHistorySize) { _commandHistory[_currentIndex].Execute(); _currentIndex++; } CheckBoundaryCondition(); } public void Undo() { if (_currentIndex > 0) { _currentIndex--; _commandHistory[_currentIndex].Undo(); } CheckBoundaryCondition(); } // Check boundary Condition To notify what button can be clicked to Exectute the Undo and Redo Commands void CheckBoundaryCondition() { if (_currentIndex <= 0) { _undoAction = null; OnUndoUnavailable?.Invoke(); } else { _undoAction = _commandHistory[_currentIndex - 1].GetAction(); OnUndoAvailable?.Invoke(); } if (_currentIndex >= _currentHistorySize || _currentHistorySize == 0) { _redoAction = null; OnRedoUnavailable?.Invoke(); } else { _redoAction = _commandHistory[_currentIndex].GetAction(); OnRedoAvailable?.Invoke(); } UpdateCommandNameHistory(); } public void EraseHistory() { _currentIndex = 0; _currentHistorySize = 0; CheckBoundaryCondition(); } public void UpdateCommands() { for (int i = 0; i < _currentHistorySize; i++) { _commandHistory[i].UpdateCommand(); } } public static string[] CopyObjectData(string[] dataToCopy) { string[] data = new string[dataToCopy.Length]; for(int i = 0; i < dataToCopy.Length; i++) { data[i] = CopyString(dataToCopy[i]); } return data; } public static string CopyString(string dataToCopy) { return dataToCopy != null ? String.Copy(dataToCopy) : null; } }