1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 02:42:54 +08:00

Improved logic

This commit is contained in:
Terochi 2023-04-30 12:05:55 +02:00
parent 585318400c
commit 949dc1c0f9
2 changed files with 46 additions and 36 deletions

View File

@ -172,7 +172,7 @@ namespace osu.Game.Tests.Visual.Gameplay
}
[Test]
public void TestUndo()
public void TestUndoEditHistory()
{
SkinComponentsContainer firstTarget = null!;
TestSkinEditorChangeHandler changeHandler = null!;
@ -205,18 +205,29 @@ namespace osu.Game.Tests.Visual.Gameplay
InputManager.Click(MouseButton.Left);
InputManager.Click(MouseButton.Left);
});
AddStep("Revert changes", () => changeHandler.RestoreState(int.MinValue));
AddAssert("Nothing changed", () => defaultState.SequenceEqual(changeHandler.GetCurrentState()));
revertAndCheckUnchanged();
AddStep("Move components", () =>
{
changeHandler.BeginChange();
testComponents.ForEach(c => ((Drawable)c).Position += Vector2.One);
changeHandler.EndChange();
});
revertAndCheckUnchanged();
AddStep("Select components", () => skinEditor.SelectedComponents.AddRange(testComponents));
AddStep("Bring to front", () => skinEditor.BringSelectionToFront());
AddStep("Revert changes", () => changeHandler.RestoreState(int.MinValue));
AddAssert("Nothing changed", () => defaultState.SequenceEqual(changeHandler.GetCurrentState()));
revertAndCheckUnchanged();
AddStep("Remove components", () => testComponents.ForEach(c => firstTarget.Remove(c, false)));
revertAndCheckUnchanged();
void revertAndCheckUnchanged()
{
AddStep("Revert changes", () => changeHandler.RestoreState(int.MinValue));
AddAssert("Nothing changed", () => defaultState.SequenceEqual(changeHandler.GetCurrentState()));
}
}
[TestCase(false)]
[TestCase(true)]

View File

@ -60,49 +60,48 @@ namespace osu.Game.Overlays.SkinEditor
SerialisedDrawableInfo[] skinnableInfos = deserializedContent.ToArray();
ISerialisableDrawable[] targetComponents = firstTarget.Components.ToArray();
// Store indexes based on type for later lookup
// Store components based on type for later lookup
var typedComponents = new Dictionary<Type, List<ISerialisableDrawable>>();
var targetComponentsIndexes = new Dictionary<Type, List<int>>();
for (int i = 0; i < targetComponents.Length; i++)
foreach (var component in targetComponents)
{
Type lookup = targetComponents[i].GetType();
Type lookup = component.GetType();
if (!targetComponentsIndexes.TryGetValue(lookup, out List<int>? componentIndexes))
targetComponentsIndexes.Add(lookup, componentIndexes = new List<int>());
if (!typedComponents.TryGetValue(lookup, out List<ISerialisableDrawable>? typeComponents))
typedComponents.Add(lookup, typeComponents = new List<ISerialisableDrawable>());
componentIndexes.Add(i);
typeComponents.Add(component);
}
var indexCounting = new Dictionary<Type, int>();
// Remove all components
for (int i = targetComponents.Length - 1; i >= 0; i--)
firstTarget.Remove(targetComponents[i], false);
var empty = new List<int>(0);
// Keeps count of how many components for each type were already revived
Dictionary<Type, int> typedComponentCounter = typedComponents.Keys.ToDictionary(t => t, _ => 0);
for (int i = 0; i < skinnableInfos.Length; i++)
foreach (var skinnableInfo in skinnableInfos)
{
Type lookup = skinnableInfos[i].Type;
Type lookup = skinnableInfo.Type;
if (!targetComponentsIndexes.TryGetValue(lookup, out List<int>? componentIndexes))
componentIndexes = empty;
if (!typedComponents.TryGetValue(lookup, out List<ISerialisableDrawable>? typeComponents))
{
firstTarget.Add((ISerialisableDrawable)skinnableInfo.CreateInstance());
continue;
}
if (!indexCounting.ContainsKey(lookup))
indexCounting.Add(lookup, 0);
int typeComponentsUsed = typedComponentCounter[lookup]++;
if (i >= componentIndexes.Count)
// Add new component
firstTarget.Add((ISerialisableDrawable)skinnableInfos[i].CreateInstance());
ISerialisableDrawable component;
if (typeComponentsUsed < typeComponents.Count)
// Re-use unused component
((Drawable)(component = typeComponents[typeComponentsUsed])).ApplySerialisedInfo(skinnableInfo);
else
// Modify existing component
((Drawable)targetComponents[componentIndexes[indexCounting[lookup]++]]).ApplySerialisedInfo(skinnableInfos[i]);
}
// Create new one
component = (ISerialisableDrawable)skinnableInfo.CreateInstance();
foreach ((Type lookup, List<int> componentIndexes) in targetComponentsIndexes)
{
indexCounting.TryGetValue(lookup, out int i);
// Remove extra components that weren't removed above
for (; i < componentIndexes.Count; i++)
firstTarget.Remove(targetComponents[componentIndexes[i]], false);
firstTarget.Add(component);
}
}
}