1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-07 15:17:30 +08:00

Merge pull request #10399 from peppy/editor-beatmap-batch-change-support

Add editor beatmap batch change support
This commit is contained in:
Dan Balasescu 2020-10-07 14:57:51 +09:00 committed by GitHub
commit 338b4c56ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 86 additions and 30 deletions

View File

@ -239,10 +239,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
private void deleteSelected() private void deleteSelected()
{ {
ChangeHandler?.BeginChange(); ChangeHandler?.BeginChange();
EditorBeatmap?.RemoveRange(selectedBlueprints.Select(b => b.HitObject));
foreach (var h in selectedBlueprints.ToList())
EditorBeatmap?.Remove(h.HitObject);
ChangeHandler?.EndChange(); ChangeHandler?.EndChange();
} }

View File

@ -484,8 +484,7 @@ namespace osu.Game.Screens.Edit
protected void Cut() protected void Cut()
{ {
Copy(); Copy();
foreach (var h in editorBeatmap.SelectedHitObjects.ToArray()) editorBeatmap.RemoveRange(editorBeatmap.SelectedHitObjects.ToArray());
editorBeatmap.Remove(h);
} }
protected void Copy() protected void Copy()

View File

@ -91,14 +91,19 @@ namespace osu.Game.Screens.Edit
private readonly HashSet<HitObject> pendingUpdates = new HashSet<HitObject>(); private readonly HashSet<HitObject> pendingUpdates = new HashSet<HitObject>();
private bool isBatchApplying;
/// <summary> /// <summary>
/// Adds a collection of <see cref="HitObject"/>s to this <see cref="EditorBeatmap"/>. /// Adds a collection of <see cref="HitObject"/>s to this <see cref="EditorBeatmap"/>.
/// </summary> /// </summary>
/// <param name="hitObjects">The <see cref="HitObject"/>s to add.</param> /// <param name="hitObjects">The <see cref="HitObject"/>s to add.</param>
public void AddRange(IEnumerable<HitObject> hitObjects) public void AddRange(IEnumerable<HitObject> hitObjects)
{
ApplyBatchChanges(_ =>
{ {
foreach (var h in hitObjects) foreach (var h in hitObjects)
Add(h); Add(h);
});
} }
/// <summary> /// <summary>
@ -126,6 +131,10 @@ namespace osu.Game.Screens.Edit
mutableHitObjects.Insert(index, hitObject); mutableHitObjects.Insert(index, hitObject);
if (isBatchApplying)
batchPendingInserts.Add(hitObject);
else
{
// must be run after any change to hitobject ordering // must be run after any change to hitobject ordering
beatmapProcessor?.PreProcess(); beatmapProcessor?.PreProcess();
processHitObject(hitObject); processHitObject(hitObject);
@ -133,6 +142,7 @@ namespace osu.Game.Screens.Edit
HitObjectAdded?.Invoke(hitObject); HitObjectAdded?.Invoke(hitObject);
} }
}
/// <summary> /// <summary>
/// Updates a <see cref="HitObject"/>, invoking <see cref="HitObject.ApplyDefaults"/> and re-processing the beatmap. /// Updates a <see cref="HitObject"/>, invoking <see cref="HitObject.ApplyDefaults"/> and re-processing the beatmap.
@ -159,6 +169,19 @@ namespace osu.Game.Screens.Edit
return true; return true;
} }
/// <summary>
/// Removes a collection of <see cref="HitObject"/>s to this <see cref="EditorBeatmap"/>.
/// </summary>
/// <param name="hitObjects">The <see cref="HitObject"/>s to remove.</param>
public void RemoveRange(IEnumerable<HitObject> hitObjects)
{
ApplyBatchChanges(_ =>
{
foreach (var h in hitObjects)
Remove(h);
});
}
/// <summary> /// <summary>
/// Finds the index of a <see cref="HitObject"/> in this <see cref="EditorBeatmap"/>. /// Finds the index of a <see cref="HitObject"/> in this <see cref="EditorBeatmap"/>.
/// </summary> /// </summary>
@ -180,6 +203,10 @@ namespace osu.Game.Screens.Edit
bindable.UnbindAll(); bindable.UnbindAll();
startTimeBindables.Remove(hitObject); startTimeBindables.Remove(hitObject);
if (isBatchApplying)
batchPendingDeletes.Add(hitObject);
else
{
// must be run after any change to hitobject ordering // must be run after any change to hitobject ordering
beatmapProcessor?.PreProcess(); beatmapProcessor?.PreProcess();
processHitObject(hitObject); processHitObject(hitObject);
@ -187,15 +214,45 @@ namespace osu.Game.Screens.Edit
HitObjectRemoved?.Invoke(hitObject); HitObjectRemoved?.Invoke(hitObject);
} }
}
private readonly List<HitObject> batchPendingInserts = new List<HitObject>();
private readonly List<HitObject> batchPendingDeletes = new List<HitObject>();
/// <summary>
/// Apply a batch of operations in one go, without performing Pre/Postprocessing each time.
/// </summary>
/// <param name="applyFunction">The function which will apply the batch changes.</param>
public void ApplyBatchChanges(Action<EditorBeatmap> applyFunction)
{
if (isBatchApplying)
throw new InvalidOperationException("Attempting to perform a batch application from within an existing batch");
isBatchApplying = true;
applyFunction(this);
beatmapProcessor?.PreProcess();
foreach (var h in batchPendingDeletes) processHitObject(h);
foreach (var h in batchPendingInserts) processHitObject(h);
beatmapProcessor?.PostProcess();
foreach (var h in batchPendingDeletes) HitObjectRemoved?.Invoke(h);
foreach (var h in batchPendingInserts) HitObjectAdded?.Invoke(h);
batchPendingDeletes.Clear();
batchPendingInserts.Clear();
isBatchApplying = false;
}
/// <summary> /// <summary>
/// Clears all <see cref="HitObjects"/> from this <see cref="EditorBeatmap"/>. /// Clears all <see cref="HitObjects"/> from this <see cref="EditorBeatmap"/>.
/// </summary> /// </summary>
public void Clear() public void Clear() => RemoveRange(HitObjects.ToArray());
{
foreach (var h in HitObjects.ToArray())
Remove(h);
}
protected override void Update() protected override void Update()
{ {

View File

@ -68,16 +68,19 @@ namespace osu.Game.Screens.Edit
toRemove.Sort(); toRemove.Sort();
toAdd.Sort(); toAdd.Sort();
editorBeatmap.ApplyBatchChanges(eb =>
{
// Apply the changes. // Apply the changes.
for (int i = toRemove.Count - 1; i >= 0; i--) for (int i = toRemove.Count - 1; i >= 0; i--)
editorBeatmap.RemoveAt(toRemove[i]); eb.RemoveAt(toRemove[i]);
if (toAdd.Count > 0) if (toAdd.Count > 0)
{ {
IBeatmap newBeatmap = readBeatmap(newState); IBeatmap newBeatmap = readBeatmap(newState);
foreach (var i in toAdd) foreach (var i in toAdd)
editorBeatmap.Insert(i, newBeatmap.HitObjects[i]); eb.Insert(i, newBeatmap.HitObjects[i]);
} }
});
} }
private string readString(byte[] state) => Encoding.UTF8.GetString(state); private string readString(byte[] state) => Encoding.UTF8.GetString(state);