1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 01:27:29 +08:00

invoking hitobject updated before invoking removed

This commit is contained in:
OliBomby 2022-09-12 17:50:11 +02:00
parent f48a743890
commit 8400de4b2e
2 changed files with 63 additions and 17 deletions

View File

@ -1,10 +1,12 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Tests.Beatmaps; using osu.Game.Tests.Beatmaps;
using osuTK.Input;
namespace osu.Game.Rulesets.Osu.Tests.Editor namespace osu.Game.Rulesets.Osu.Tests.Editor
{ {
@ -16,13 +18,12 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
public void TestSingleDeleteAtSameTime() public void TestSingleDeleteAtSameTime()
{ {
HitCircle? circle1 = null; HitCircle? circle1 = null;
HitCircle? circle2 = null;
AddStep("add two circles at the same time", () => AddStep("add two circles at the same time", () =>
{ {
circle1 = new HitCircle();
circle2 = new HitCircle();
EditorClock.Seek(0); EditorClock.Seek(0);
circle1 = new HitCircle();
var circle2 = new HitCircle();
EditorBeatmap.Add(circle1); EditorBeatmap.Add(circle1);
EditorBeatmap.Add(circle2); EditorBeatmap.Add(circle2);
EditorBeatmap.SelectedHitObjects.Add(circle1); EditorBeatmap.SelectedHitObjects.Add(circle1);
@ -31,5 +32,33 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
AddStep("delete the first circle", () => EditorBeatmap.Remove(circle1)); AddStep("delete the first circle", () => EditorBeatmap.Remove(circle1));
} }
[Test]
public void TestBigStackDeleteAtSameTime()
{
AddStep("add 20 circles at the same time", () =>
{
EditorClock.Seek(0);
for (int i = 0; i < 20; i++)
{
EditorBeatmap.Add(new HitCircle());
}
});
AddStep("select half of the circles", () =>
{
foreach (var hitObject in EditorBeatmap.HitObjects.SkipLast(10).Reverse())
{
EditorBeatmap.SelectedHitObjects.Add(hitObject);
}
});
AddStep("delete all selected circles", () =>
{
InputManager.PressKey(Key.Delete);
InputManager.ReleaseKey(Key.Delete);
});
}
} }
} }

View File

@ -16,6 +16,7 @@ using osu.Game.Beatmaps.Legacy;
using osu.Game.Beatmaps.Timing; using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Screens.Edit namespace osu.Game.Screens.Edit
@ -79,7 +80,7 @@ namespace osu.Game.Screens.Edit
private readonly IBeatmapProcessor beatmapProcessor; private readonly IBeatmapProcessor beatmapProcessor;
private readonly Dictionary<HitObject, Bindable<double>> startTimeBindables = new Dictionary<HitObject, Bindable<double>>(); private readonly Dictionary<HitObject, List<IUnbindable>> hitObjectBindables = new Dictionary<HitObject, List<IUnbindable>>();
public EditorBeatmap(IBeatmap playableBeatmap, ISkin beatmapSkin = null, BeatmapInfo beatmapInfo = null) public EditorBeatmap(IBeatmap playableBeatmap, ISkin beatmapSkin = null, BeatmapInfo beatmapInfo = null)
{ {
@ -97,7 +98,7 @@ namespace osu.Game.Screens.Edit
beatmapProcessor = playableBeatmap.BeatmapInfo.Ruleset.CreateInstance().CreateBeatmapProcessor(PlayableBeatmap); beatmapProcessor = playableBeatmap.BeatmapInfo.Ruleset.CreateInstance().CreateBeatmapProcessor(PlayableBeatmap);
foreach (var obj in HitObjects) foreach (var obj in HitObjects)
trackStartTime(obj); trackBindables(obj);
} }
/// <summary> /// <summary>
@ -222,7 +223,7 @@ namespace osu.Game.Screens.Edit
/// <param name="hitObject">The <see cref="HitObject"/> to insert.</param> /// <param name="hitObject">The <see cref="HitObject"/> to insert.</param>
public void Insert(int index, HitObject hitObject) public void Insert(int index, HitObject hitObject)
{ {
trackStartTime(hitObject); trackBindables(hitObject);
mutableHitObjects.Insert(index, hitObject); mutableHitObjects.Insert(index, hitObject);
@ -299,9 +300,9 @@ namespace osu.Game.Screens.Edit
mutableHitObjects.RemoveAt(index); mutableHitObjects.RemoveAt(index);
var bindable = startTimeBindables[hitObject]; var bindables = hitObjectBindables[hitObject];
bindable.UnbindAll(); bindables.ForEach(b => b.UnbindAll());
startTimeBindables.Remove(hitObject); hitObjectBindables.Remove(hitObject);
BeginChange(); BeginChange();
batchPendingDeletes.Add(hitObject); batchPendingDeletes.Add(hitObject);
@ -325,25 +326,25 @@ namespace osu.Game.Screens.Edit
beatmapProcessor?.PreProcess(); beatmapProcessor?.PreProcess();
foreach (var h in batchPendingUpdates) processHitObject(h);
foreach (var h in batchPendingDeletes) processHitObject(h); foreach (var h in batchPendingDeletes) processHitObject(h);
foreach (var h in batchPendingInserts) processHitObject(h); foreach (var h in batchPendingInserts) processHitObject(h);
foreach (var h in batchPendingUpdates) processHitObject(h);
beatmapProcessor?.PostProcess(); beatmapProcessor?.PostProcess();
// callbacks may modify the lists so let's be safe about it // callbacks may modify the lists so let's be safe about it
var updates = batchPendingUpdates.ToArray();
batchPendingUpdates.Clear();
var deletes = batchPendingDeletes.ToArray(); var deletes = batchPendingDeletes.ToArray();
batchPendingDeletes.Clear(); batchPendingDeletes.Clear();
var inserts = batchPendingInserts.ToArray(); var inserts = batchPendingInserts.ToArray();
batchPendingInserts.Clear(); batchPendingInserts.Clear();
var updates = batchPendingUpdates.ToArray(); foreach (var h in updates) HitObjectUpdated?.Invoke(h);
batchPendingUpdates.Clear();
foreach (var h in deletes) HitObjectRemoved?.Invoke(h); foreach (var h in deletes) HitObjectRemoved?.Invoke(h);
foreach (var h in inserts) HitObjectAdded?.Invoke(h); foreach (var h in inserts) HitObjectAdded?.Invoke(h);
foreach (var h in updates) HitObjectUpdated?.Invoke(h);
updateInProgress.Value = false; updateInProgress.Value = false;
} }
@ -355,10 +356,12 @@ namespace osu.Game.Screens.Edit
private void processHitObject(HitObject hitObject) => hitObject.ApplyDefaults(ControlPointInfo, PlayableBeatmap.Difficulty); private void processHitObject(HitObject hitObject) => hitObject.ApplyDefaults(ControlPointInfo, PlayableBeatmap.Difficulty);
private void trackStartTime(HitObject hitObject) private void trackBindables(HitObject hitObject)
{ {
startTimeBindables[hitObject] = hitObject.StartTimeBindable.GetBoundCopy(); var bindables = new List<IUnbindable>(3);
startTimeBindables[hitObject].ValueChanged += _ =>
var startTimeBindable = hitObject.StartTimeBindable.GetBoundCopy();
startTimeBindable.ValueChanged += _ =>
{ {
// For now we'll remove and re-add the hitobject. This is not optimal and can be improved if required. // For now we'll remove and re-add the hitobject. This is not optimal and can be improved if required.
mutableHitObjects.Remove(hitObject); mutableHitObjects.Remove(hitObject);
@ -368,6 +371,20 @@ namespace osu.Game.Screens.Edit
Update(hitObject); Update(hitObject);
}; };
bindables.Add(startTimeBindable);
if (hitObject is IHasComboInformation hasCombo)
{
var comboIndexBindable = hasCombo.ComboIndexBindable.GetBoundCopy();
comboIndexBindable.ValueChanged += _ => Update(hitObject);
bindables.Add(comboIndexBindable);
var indexInCurrentComboBindable = hasCombo.IndexInCurrentComboBindable.GetBoundCopy();
indexInCurrentComboBindable.ValueChanged += _ => Update(hitObject);
bindables.Add(indexInCurrentComboBindable);
}
hitObjectBindables[hitObject] = bindables;
} }
private int findInsertionIndex(IReadOnlyList<HitObject> list, double startTime) private int findInsertionIndex(IReadOnlyList<HitObject> list, double startTime)