1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-05 10:33:22 +08:00

fix mix changehandler and command handler

This commit is contained in:
OliBomby 2024-10-12 22:31:35 +02:00
parent 8cbd40f0e8
commit 75eefcfc9b
2 changed files with 57 additions and 21 deletions

View File

@ -27,7 +27,7 @@ namespace osu.Game.Screens.Edit
private readonly List<byte[]> savedStates = new List<byte[]>();
private int currentState = -1;
public int CurrentState { get; set; } = -1;
/// <summary>
/// A SHA-2 hash representing the current visible editor state.
@ -38,7 +38,7 @@ namespace osu.Game.Screens.Edit
{
ensureStateSaved();
using (var stream = new MemoryStream(savedStates[currentState]))
using (var stream = new MemoryStream(savedStates[CurrentState]))
return stream.ComputeSHA2Hash();
}
}
@ -71,17 +71,17 @@ namespace osu.Game.Screens.Edit
byte[] newState = stream.ToArray();
// if the previous state is binary equal we don't need to push a new one, unless this is the initial state.
if (savedStates.Count > 0 && newState.SequenceEqual(savedStates[currentState])) return;
if (savedStates.Count > 0 && newState.SequenceEqual(savedStates[CurrentState])) return;
if (currentState < savedStates.Count - 1)
savedStates.RemoveRange(currentState + 1, savedStates.Count - currentState - 1);
if (CurrentState < savedStates.Count - 1)
savedStates.RemoveRange(CurrentState + 1, savedStates.Count - CurrentState - 1);
if (savedStates.Count > MAX_SAVED_STATES)
savedStates.RemoveAt(0);
savedStates.Add(newState);
currentState = savedStates.Count - 1;
CurrentState = savedStates.Count - 1;
OnStateChange?.Invoke();
updateBindables();
@ -96,15 +96,15 @@ namespace osu.Game.Screens.Edit
if (savedStates.Count == 0)
return;
int newState = Math.Clamp(currentState + direction, 0, savedStates.Count - 1);
if (currentState == newState)
int newState = Math.Clamp(CurrentState + direction, 0, savedStates.Count - 1);
if (CurrentState == newState)
return;
isRestoring = true;
ApplyStateChange(savedStates[currentState], savedStates[newState]);
ApplyStateChange(savedStates[CurrentState], savedStates[newState]);
currentState = newState;
CurrentState = newState;
isRestoring = false;
@ -128,8 +128,8 @@ namespace osu.Game.Screens.Edit
private void updateBindables()
{
CanUndo.Value = savedStates.Count > 0 && currentState > 0;
CanRedo.Value = currentState < savedStates.Count - 1;
CanUndo.Value = savedStates.Count > 0 && CurrentState > 0;
CanRedo.Value = CurrentState < savedStates.Count - 1;
}
}
}

View File

@ -28,7 +28,8 @@ namespace osu.Game.Screens.Edit
public bool HasUncommittedChanges => currentTransaction.UndoCommands.Count != 0;
private bool suppressStateChange;
private bool ignoreCommandStateChange;
private bool ignoreChangeHandlerStateChange;
private Transaction currentTransaction;
@ -44,12 +45,21 @@ namespace osu.Game.Screens.Edit
if (this.changeHandler != null)
{
// Ensure mutually exclusive state changes.
TransactionBegan += () => this.changeHandler.SuppressStateChange = true;
TransactionEnded += () => this.changeHandler.SuppressStateChange = false;
this.changeHandler.TransactionBegan += () => suppressStateChange = true;
this.changeHandler.TransactionEnded += () => suppressStateChange = false;
this.changeHandler.SaveStateTriggered += commitChangeHandlerTransaction;
TransactionBegan += () =>
{
ignoreChangeHandlerStateChange = !ignoreCommandStateChange;
// The change handler should save states even when a change is recorded as commands,
// because it needs to know the state after the commands in order to restore it.
this.changeHandler.BeginChange();
};
TransactionEnded += () =>
{
this.changeHandler.EndChange();
ignoreChangeHandlerStateChange = false;
};
this.changeHandler.TransactionBegan += () => ignoreCommandStateChange = !ignoreChangeHandlerStateChange;
this.changeHandler.TransactionEnded += () => ignoreCommandStateChange = false;
this.changeHandler.OnStateChange += commitChangeHandlerStateChange;
}
}
@ -92,7 +102,7 @@ namespace osu.Game.Screens.Edit
return;
}
if (!suppressStateChange)
if (!ignoreCommandStateChange)
{
undoStack.Push(currentTransaction);
redoStack.Clear();
@ -105,8 +115,11 @@ namespace osu.Game.Screens.Edit
historyChanged();
}
private void commitChangeHandlerTransaction()
private void commitChangeHandlerStateChange()
{
if (ignoreChangeHandlerStateChange || changeHandler!.CurrentState <= 0)
return;
undoStack.Push(new Transaction(isChangeHandlerTransaction: true));
redoStack.Clear();
@ -128,10 +141,21 @@ namespace osu.Game.Screens.Edit
var redoTransaction = transaction.Reverse();
if (transaction.IsChangeHandlerTransaction)
{
ignoreChangeHandlerStateChange = true;
changeHandler!.RestoreState(-1);
ignoreChangeHandlerStateChange = false;
Logger.Log("Undo handled by change handler");
}
else
{
revertTransaction(transaction);
if (changeHandler != null)
changeHandler.CurrentState--;
Logger.Log("Undo handled by command handler");
}
redoStack.Push(redoTransaction);
historyChanged();
@ -152,10 +176,21 @@ namespace osu.Game.Screens.Edit
var undoTransaction = transaction.Reverse();
if (transaction.IsChangeHandlerTransaction)
{
ignoreChangeHandlerStateChange = true;
changeHandler!.RestoreState(1);
ignoreChangeHandlerStateChange = false;
Logger.Log("Redo handled by change handler");
}
else
{
revertTransaction(transaction);
if (changeHandler != null)
changeHandler.CurrentState++;
Logger.Log("Redo handled by command handler");
}
undoStack.Push(undoTransaction);
historyChanged();
@ -181,6 +216,7 @@ namespace osu.Game.Screens.Edit
private void revertTransaction(Transaction transaction)
{
// We are navigating history so we don't want to write a new state.
if (changeHandler != null)
changeHandler.SuppressStateChange = true;