mirror of
https://github.com/RHeavenStudio/HeavenStudio.git
synced 2025-06-12 22:07:37 +02:00
Command pattern (Undo/Redo) system began. (Read desc)
I spent about 6 hours trying to fix this one specific bug involving the move undo. Turns out all I had to do was calm down and think logically instead of typing random bullshit for a few hours until it worked. I'm tired and I thank this for ruining my sleep schedule.
This commit is contained in:
75
Assets/Scripts/LevelEditor/Commands/CommandManager.cs
Normal file
75
Assets/Scripts/LevelEditor/Commands/CommandManager.cs
Normal file
@ -0,0 +1,75 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using RhythmHeavenMania.Editor.Commands;
|
||||
|
||||
namespace RhythmHeavenMania.Editor
|
||||
{
|
||||
public class CommandManager : MonoBehaviour
|
||||
{
|
||||
private Stack<IAction> historyStack = new Stack<IAction>();
|
||||
private Stack<IAction> redoHistoryStack = new Stack<IAction>();
|
||||
|
||||
int maxItems = 128;
|
||||
|
||||
public bool canUndo()
|
||||
{
|
||||
return historyStack.Count > 0;
|
||||
}
|
||||
public bool canRedo()
|
||||
{
|
||||
return redoHistoryStack.Count > 0;
|
||||
}
|
||||
|
||||
public static CommandManager instance { get; private set; }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public void Execute(IAction action)
|
||||
{
|
||||
action.Execute();
|
||||
historyStack.Push(action);
|
||||
redoHistoryStack.Clear();
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
if (!canUndo()) return;
|
||||
|
||||
if (historyStack.Count > 0)
|
||||
{
|
||||
redoHistoryStack.Push(historyStack.Peek());
|
||||
historyStack.Pop().Undo();
|
||||
}
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
if (!canRedo()) return;
|
||||
|
||||
if (redoHistoryStack.Count > 0)
|
||||
{
|
||||
historyStack.Push(redoHistoryStack.Peek());
|
||||
redoHistoryStack.Pop().Redo();
|
||||
}
|
||||
}
|
||||
|
||||
// this is here as to not hog up memory, "max undos" basically
|
||||
private void EnsureCapacity()
|
||||
{
|
||||
if (maxItems > 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void Clear()
|
||||
{
|
||||
historyStack.Clear();
|
||||
redoHistoryStack.Clear();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/LevelEditor/Commands/CommandManager.cs.meta
Normal file
11
Assets/Scripts/LevelEditor/Commands/CommandManager.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6187911411a100640b5f4f3f2f84b912
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
13
Assets/Scripts/LevelEditor/Commands/IAction.cs
Normal file
13
Assets/Scripts/LevelEditor/Commands/IAction.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RhythmHeavenMania.Editor.Commands
|
||||
{
|
||||
public interface IAction
|
||||
{
|
||||
void Execute();
|
||||
void Undo();
|
||||
void Redo();
|
||||
}
|
||||
}
|
11
Assets/Scripts/LevelEditor/Commands/IAction.cs.meta
Normal file
11
Assets/Scripts/LevelEditor/Commands/IAction.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 64b35e3b4d623144a82ed956ee52a136
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
129
Assets/Scripts/LevelEditor/Commands/Selections.cs
Normal file
129
Assets/Scripts/LevelEditor/Commands/Selections.cs
Normal file
@ -0,0 +1,129 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RhythmHeavenMania.Editor.Commands
|
||||
{
|
||||
public class Selection : IAction
|
||||
{
|
||||
public void Execute()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
// I spent 7 hours trying to fix this instead of sleeping, which would've probably worked better.
|
||||
// I'll go fuck myself later I'm just glad it works
|
||||
// I give massive props to people who code undo/redo systems
|
||||
// -- Starpelly
|
||||
|
||||
public class Move : IAction
|
||||
{
|
||||
public List<Pos> pos = new List<Pos>();
|
||||
|
||||
public class Pos
|
||||
{
|
||||
public TimelineEventObj eventObj;
|
||||
|
||||
public Vector2 lastPos_;
|
||||
public Vector3 previousPos;
|
||||
}
|
||||
|
||||
public Move(List<TimelineEventObj> eventObjs)
|
||||
{
|
||||
pos.Clear();
|
||||
|
||||
for (int i = 0; i < eventObjs.Count; i++)
|
||||
{
|
||||
Pos p = new Pos();
|
||||
p.eventObj = eventObjs[i];
|
||||
p.lastPos_ = eventObjs[i].lastPos_;
|
||||
p.previousPos = eventObjs[i].transform.localPosition;
|
||||
this.pos.Add(p);
|
||||
}
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
for (int i = 0; i < pos.Count; i++)
|
||||
{
|
||||
EnsureEventObj(i);
|
||||
pos[i].eventObj.transform.localPosition = pos[i].previousPos;
|
||||
}
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
|
||||
for (int i = 0; i < pos.Count; i++)
|
||||
{
|
||||
EnsureEventObj(i);
|
||||
pos[i].eventObj.transform.localPosition = pos[i].lastPos_;
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureEventObj(int id)
|
||||
{
|
||||
if (pos[id].eventObj == null)
|
||||
{
|
||||
pos[id].eventObj = GameManager.instance.Beatmap.entities.Find(c => c.eventObj.eventObjID == pos[id].eventObj.eventObjID).eventObj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Deletion : IAction
|
||||
{
|
||||
List<TimelineEventObj> eventObjs;
|
||||
|
||||
List<TimelineEventObj> deletedObjs;
|
||||
|
||||
public Deletion(List<TimelineEventObj> eventObjs)
|
||||
{
|
||||
this.eventObjs = eventObjs;
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
deletedObjs = eventObjs;
|
||||
for (int i = 0; i < eventObjs.Count; i++)
|
||||
{
|
||||
Selections.instance.Deselect(eventObjs[i]);
|
||||
Timeline.instance.DestroyEventObject(eventObjs[i].entity);
|
||||
}
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
deletedObjs = eventObjs;
|
||||
for (int i = 0; i < eventObjs.Count; i++)
|
||||
{
|
||||
Selections.instance.Deselect(eventObjs[i]);
|
||||
Timeline.instance.DestroyEventObject(eventObjs[i].entity);
|
||||
}
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
for (int i = 0; i < deletedObjs.Count; i++)
|
||||
{
|
||||
Beatmap.Entity e = deletedObjs[i].entity;
|
||||
eventObjs[i] = Timeline.instance.AddEventObject(e.datamodel, false, new Vector3(e.beat, -e.track * Timeline.instance.LayerHeight()), e, true, e.eventObj.eventObjID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/LevelEditor/Commands/Selections.cs.meta
Normal file
11
Assets/Scripts/LevelEditor/Commands/Selections.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e13e41a59182b74ba7f0be1e3b58ff9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
34
Assets/Scripts/LevelEditor/Commands/TestCommand.cs
Normal file
34
Assets/Scripts/LevelEditor/Commands/TestCommand.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using RhythmHeavenMania.Editor.Commands;
|
||||
|
||||
public class TestCommand : IAction
|
||||
{
|
||||
private GameObject prefab;
|
||||
private Vector3 pos;
|
||||
|
||||
private GameObject spawnedgameObj;
|
||||
|
||||
public TestCommand(GameObject prefab, Vector3 pos)
|
||||
{
|
||||
this.prefab = prefab;
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
spawnedgameObj = GameObject.Instantiate(prefab, pos, Quaternion.identity);
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
GameObject.Destroy(spawnedgameObj);
|
||||
}
|
||||
}
|
11
Assets/Scripts/LevelEditor/Commands/TestCommand.cs.meta
Normal file
11
Assets/Scripts/LevelEditor/Commands/TestCommand.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1e32a4a20b85d944aa030268410b0101
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user