From d2f5e696e77072138dc0bafd5e62b3567d165f07 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Fri, 11 Aug 2023 22:34:04 +0200 Subject: [PATCH 01/10] Fix DrawableHitObject state not synchronizing with hitobject edits --- .../Objects/Drawables/DrawableHitObject.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index bf649a0a15..f141263e27 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -260,7 +260,6 @@ namespace osu.Game.Rulesets.Objects.Drawables } StartTimeBindable.BindTo(HitObject.StartTimeBindable); - StartTimeBindable.BindValueChanged(onStartTimeChanged); if (HitObject is IHasComboInformation combo) { @@ -311,9 +310,6 @@ namespace osu.Game.Rulesets.Objects.Drawables samplesBindable.UnbindFrom(HitObject.SamplesBindable); - // Changes in start time trigger state updates. When a new hitobject is applied, OnApply() automatically performs a state update anyway. - StartTimeBindable.ValueChanged -= onStartTimeChanged; - // When a new hitobject is applied, the samples will be cleared before re-populating. // In order to stop this needless update, the event is unbound and re-bound as late as possible in Apply(). samplesBindable.CollectionChanged -= onSamplesChanged; @@ -333,6 +329,8 @@ namespace osu.Game.Rulesets.Objects.Drawables Entry.NestedEntries.RemoveAll(nestedEntry => nestedEntry is SyntheticHitObjectEntry); ClearNestedHitObjects(); + // Changes in state trigger defaults applied trigger state updates. + // When a new hitobject is applied, OnApply() automatically performs a state update anyway. HitObject.DefaultsApplied -= onDefaultsApplied; entry.RevertResult -= onRevertResult; @@ -375,8 +373,6 @@ namespace osu.Game.Rulesets.Objects.Drawables private void onSamplesChanged(object sender, NotifyCollectionChangedEventArgs e) => LoadSamples(); - private void onStartTimeChanged(ValueChangedEvent startTime) => updateState(State.Value, true); - private void onNewResult(DrawableHitObject drawableHitObject, JudgementResult result) => OnNewResult?.Invoke(drawableHitObject, result); private void onRevertResult() @@ -394,6 +390,13 @@ namespace osu.Game.Rulesets.Objects.Drawables Debug.Assert(Entry != null); Apply(Entry); + // Applied defaults indicate a change in hit object state. + if (Result is not null) + { + Result.TimeOffset = 0; + updateState(State.Value, true); + } + DefaultsApplied?.Invoke(this); } From 5d1ccc2601a739e2d8ed61b8d9b64a0efa580f7f Mon Sep 17 00:00:00 2001 From: OliBomby Date: Fri, 11 Aug 2023 23:39:28 +0200 Subject: [PATCH 02/10] Ensure invariant of monotone time --- osu.Game/Rulesets/UI/HitObjectContainer.cs | 30 ++++++++++++++++++- osu.Game/Rulesets/UI/Playfield.cs | 35 ++++++++++++++++++---- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index 099be486b3..e919e4d088 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -51,6 +51,11 @@ namespace osu.Game.Rulesets.UI [Resolved(CanBeNull = true)] private IPooledHitObjectProvider pooledObjectProvider { get; set; } + /// + /// Invoked when a is updated. + /// + public event Action HitObjectUpdated; + public HitObjectContainer() { RelativeSizeAxes = Axes.Both; @@ -108,6 +113,7 @@ namespace osu.Game.Rulesets.UI drawable.OnNewResult += onNewResult; bindStartTime(drawable); + bindUpdated(drawable); AddInternal(drawable); } @@ -116,7 +122,7 @@ namespace osu.Game.Rulesets.UI drawable.OnNewResult -= onNewResult; unbindStartTime(drawable); - + unbindUpdated(drawable); RemoveInternal(drawable, false); } @@ -176,6 +182,27 @@ namespace osu.Game.Rulesets.UI startTimeMap.Clear(); } + private void bindUpdated(DrawableHitObject hitObject) + { + hitObject.DefaultsApplied += onDefaultsApplied; + } + + private void unbindUpdated(DrawableHitObject hitObject) + { + hitObject.DefaultsApplied += onDefaultsApplied; + } + + private void unbindAllUpdated() + { + foreach (var h in AliveObjects) + unbindUpdated(h); + } + + private void onDefaultsApplied(DrawableHitObject obj) + { + HitObjectUpdated?.Invoke(obj.HitObject); + } + protected override int Compare(Drawable x, Drawable y) { if (!(x is DrawableHitObject xObj) || !(y is DrawableHitObject yObj)) @@ -192,6 +219,7 @@ namespace osu.Game.Rulesets.UI { base.Dispose(isDisposing); unbindAllStartTimes(); + unbindAllUpdated(); } } } diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index e9c35555c8..9a4d082a06 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.UI private readonly HitObjectEntryManager entryManager = new HitObjectEntryManager(); - private readonly Stack judgedEntries; + private readonly LinkedList judgedEntries; /// /// Creates a new . @@ -125,12 +125,13 @@ namespace osu.Game.Rulesets.UI h.NewResult += onNewResult; h.HitObjectUsageBegan += o => HitObjectUsageBegan?.Invoke(o); h.HitObjectUsageFinished += o => HitObjectUsageFinished?.Invoke(o); + h.HitObjectUpdated += onHitObjectUpdated; })); entryManager.OnEntryAdded += onEntryAdded; entryManager.OnEntryRemoved += onEntryRemoved; - judgedEntries = new Stack(); + judgedEntries = new LinkedList(); } [BackgroundDependencyLoader] @@ -270,15 +271,16 @@ namespace osu.Game.Rulesets.UI } // When rewinding, revert future judgements in the reverse order. - while (judgedEntries.Count > 0) + while (judgedEntries.Last is not null) { - var result = judgedEntries.Peek().Result; + var result = judgedEntries.Last.Value.Result; Debug.Assert(result?.RawTime != null); if (Time.Current >= result.RawTime.Value) break; - revertResult(judgedEntries.Pop()); + revertResult(judgedEntries.Last.Value); + judgedEntries.RemoveLast(); } } @@ -471,10 +473,31 @@ namespace osu.Game.Rulesets.UI #endregion + private void onHitObjectUpdated(HitObject _) + { + // The time of judged entries may have changed, so we need to re-sort the list to preserve the invariant of monotone time. + // Insertion sort on linked-list is O(n) for nearly-sorted lists, which is the case here. + var current = judgedEntries.First; + + while (current?.Next is not null) + { + var next = current.Next; + + if (current.Value.Result?.RawTime > next.Value.Result?.RawTime) + { + judgedEntries.Remove(next); + judgedEntries.AddBefore(current, next); + current = next.Previous; + } + else + current = next; + } + } + private void onNewResult(DrawableHitObject drawable, JudgementResult result) { Debug.Assert(result != null && drawable.Entry?.Result == result && result.RawTime != null); - judgedEntries.Push(drawable.Entry.AsNonNull()); + judgedEntries.AddLast(drawable.Entry.AsNonNull()); NewResult?.Invoke(drawable, result); } From 90f2acaf0a9d1bfa5ac8d4cc653798604a3fdf21 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Fri, 11 Aug 2023 23:50:00 +0200 Subject: [PATCH 03/10] Fix typo --- osu.Game/Rulesets/UI/HitObjectContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index e919e4d088..76cfc049e3 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -189,7 +189,7 @@ namespace osu.Game.Rulesets.UI private void unbindUpdated(DrawableHitObject hitObject) { - hitObject.DefaultsApplied += onDefaultsApplied; + hitObject.DefaultsApplied -= onDefaultsApplied; } private void unbindAllUpdated() From b9d0a8a9f69fadacf1d1578fccd9101798583d47 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Sun, 13 Aug 2023 15:15:37 +0200 Subject: [PATCH 04/10] Fix TestSceneFruitRandomness --- osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs index de3d9d6530..8e7f77285c 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs @@ -26,6 +26,8 @@ namespace osu.Game.Rulesets.Catch.Tests AddSliderStep("start time", 500, 600, 0, x => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = x; + drawableFruit.RefreshStateTransforms(); + drawableBanana.RefreshStateTransforms(); }); } @@ -44,6 +46,8 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("Initialize start time", () => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time; + drawableFruit.RefreshStateTransforms(); + drawableBanana.RefreshStateTransforms(); fruitRotation = drawableFruit.DisplayRotation; bananaRotation = drawableBanana.DisplayRotation; @@ -54,6 +58,8 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("change start time", () => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = another_start_time; + drawableFruit.RefreshStateTransforms(); + drawableBanana.RefreshStateTransforms(); }); AddAssert("fruit rotation is changed", () => drawableFruit.DisplayRotation != fruitRotation); @@ -64,6 +70,8 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("reset start time", () => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time; + drawableFruit.RefreshStateTransforms(); + drawableBanana.RefreshStateTransforms(); }); AddAssert("rotation and size restored", () => From 82de7385d1c07dc0bd3e21a46ee6220e82a59244 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 21 Aug 2023 12:59:58 +0200 Subject: [PATCH 05/10] Revert "Fix TestSceneFruitRandomness" This reverts commit b9d0a8a9f69fadacf1d1578fccd9101798583d47. --- osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs index 8e7f77285c..de3d9d6530 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs @@ -26,8 +26,6 @@ namespace osu.Game.Rulesets.Catch.Tests AddSliderStep("start time", 500, 600, 0, x => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = x; - drawableFruit.RefreshStateTransforms(); - drawableBanana.RefreshStateTransforms(); }); } @@ -46,8 +44,6 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("Initialize start time", () => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time; - drawableFruit.RefreshStateTransforms(); - drawableBanana.RefreshStateTransforms(); fruitRotation = drawableFruit.DisplayRotation; bananaRotation = drawableBanana.DisplayRotation; @@ -58,8 +54,6 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("change start time", () => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = another_start_time; - drawableFruit.RefreshStateTransforms(); - drawableBanana.RefreshStateTransforms(); }); AddAssert("fruit rotation is changed", () => drawableFruit.DisplayRotation != fruitRotation); @@ -70,8 +64,6 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("reset start time", () => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time; - drawableFruit.RefreshStateTransforms(); - drawableBanana.RefreshStateTransforms(); }); AddAssert("rotation and size restored", () => From c7b1c75379983860a2dec8bd2de92d4331a0fc75 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 21 Aug 2023 13:00:01 +0200 Subject: [PATCH 06/10] Revert "Fix typo" This reverts commit 90f2acaf0a9d1bfa5ac8d4cc653798604a3fdf21. --- osu.Game/Rulesets/UI/HitObjectContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index 76cfc049e3..e919e4d088 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -189,7 +189,7 @@ namespace osu.Game.Rulesets.UI private void unbindUpdated(DrawableHitObject hitObject) { - hitObject.DefaultsApplied -= onDefaultsApplied; + hitObject.DefaultsApplied += onDefaultsApplied; } private void unbindAllUpdated() From 5bc11ed35806ac8fac87c82118ff904905df3127 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 21 Aug 2023 13:02:23 +0200 Subject: [PATCH 07/10] Revert "Ensure invariant of monotone time" This reverts commit 5d1ccc2601a739e2d8ed61b8d9b64a0efa580f7f. --- osu.Game/Rulesets/UI/HitObjectContainer.cs | 30 +------------------ osu.Game/Rulesets/UI/Playfield.cs | 35 ++++------------------ 2 files changed, 7 insertions(+), 58 deletions(-) diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index e919e4d088..099be486b3 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -51,11 +51,6 @@ namespace osu.Game.Rulesets.UI [Resolved(CanBeNull = true)] private IPooledHitObjectProvider pooledObjectProvider { get; set; } - /// - /// Invoked when a is updated. - /// - public event Action HitObjectUpdated; - public HitObjectContainer() { RelativeSizeAxes = Axes.Both; @@ -113,7 +108,6 @@ namespace osu.Game.Rulesets.UI drawable.OnNewResult += onNewResult; bindStartTime(drawable); - bindUpdated(drawable); AddInternal(drawable); } @@ -122,7 +116,7 @@ namespace osu.Game.Rulesets.UI drawable.OnNewResult -= onNewResult; unbindStartTime(drawable); - unbindUpdated(drawable); + RemoveInternal(drawable, false); } @@ -182,27 +176,6 @@ namespace osu.Game.Rulesets.UI startTimeMap.Clear(); } - private void bindUpdated(DrawableHitObject hitObject) - { - hitObject.DefaultsApplied += onDefaultsApplied; - } - - private void unbindUpdated(DrawableHitObject hitObject) - { - hitObject.DefaultsApplied += onDefaultsApplied; - } - - private void unbindAllUpdated() - { - foreach (var h in AliveObjects) - unbindUpdated(h); - } - - private void onDefaultsApplied(DrawableHitObject obj) - { - HitObjectUpdated?.Invoke(obj.HitObject); - } - protected override int Compare(Drawable x, Drawable y) { if (!(x is DrawableHitObject xObj) || !(y is DrawableHitObject yObj)) @@ -219,7 +192,6 @@ namespace osu.Game.Rulesets.UI { base.Dispose(isDisposing); unbindAllStartTimes(); - unbindAllUpdated(); } } } diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 9a4d082a06..e9c35555c8 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.UI private readonly HitObjectEntryManager entryManager = new HitObjectEntryManager(); - private readonly LinkedList judgedEntries; + private readonly Stack judgedEntries; /// /// Creates a new . @@ -125,13 +125,12 @@ namespace osu.Game.Rulesets.UI h.NewResult += onNewResult; h.HitObjectUsageBegan += o => HitObjectUsageBegan?.Invoke(o); h.HitObjectUsageFinished += o => HitObjectUsageFinished?.Invoke(o); - h.HitObjectUpdated += onHitObjectUpdated; })); entryManager.OnEntryAdded += onEntryAdded; entryManager.OnEntryRemoved += onEntryRemoved; - judgedEntries = new LinkedList(); + judgedEntries = new Stack(); } [BackgroundDependencyLoader] @@ -271,16 +270,15 @@ namespace osu.Game.Rulesets.UI } // When rewinding, revert future judgements in the reverse order. - while (judgedEntries.Last is not null) + while (judgedEntries.Count > 0) { - var result = judgedEntries.Last.Value.Result; + var result = judgedEntries.Peek().Result; Debug.Assert(result?.RawTime != null); if (Time.Current >= result.RawTime.Value) break; - revertResult(judgedEntries.Last.Value); - judgedEntries.RemoveLast(); + revertResult(judgedEntries.Pop()); } } @@ -473,31 +471,10 @@ namespace osu.Game.Rulesets.UI #endregion - private void onHitObjectUpdated(HitObject _) - { - // The time of judged entries may have changed, so we need to re-sort the list to preserve the invariant of monotone time. - // Insertion sort on linked-list is O(n) for nearly-sorted lists, which is the case here. - var current = judgedEntries.First; - - while (current?.Next is not null) - { - var next = current.Next; - - if (current.Value.Result?.RawTime > next.Value.Result?.RawTime) - { - judgedEntries.Remove(next); - judgedEntries.AddBefore(current, next); - current = next.Previous; - } - else - current = next; - } - } - private void onNewResult(DrawableHitObject drawable, JudgementResult result) { Debug.Assert(result != null && drawable.Entry?.Result == result && result.RawTime != null); - judgedEntries.AddLast(drawable.Entry.AsNonNull()); + judgedEntries.Push(drawable.Entry.AsNonNull()); NewResult?.Invoke(drawable, result); } From c82e997644529adb475bec516ead328d260c1fda Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 21 Aug 2023 13:02:41 +0200 Subject: [PATCH 08/10] Revert "Revert "Fix TestSceneFruitRandomness"" This reverts commit 82de7385d1c07dc0bd3e21a46ee6220e82a59244. --- osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs index de3d9d6530..8e7f77285c 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs @@ -26,6 +26,8 @@ namespace osu.Game.Rulesets.Catch.Tests AddSliderStep("start time", 500, 600, 0, x => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = x; + drawableFruit.RefreshStateTransforms(); + drawableBanana.RefreshStateTransforms(); }); } @@ -44,6 +46,8 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("Initialize start time", () => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time; + drawableFruit.RefreshStateTransforms(); + drawableBanana.RefreshStateTransforms(); fruitRotation = drawableFruit.DisplayRotation; bananaRotation = drawableBanana.DisplayRotation; @@ -54,6 +58,8 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("change start time", () => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = another_start_time; + drawableFruit.RefreshStateTransforms(); + drawableBanana.RefreshStateTransforms(); }); AddAssert("fruit rotation is changed", () => drawableFruit.DisplayRotation != fruitRotation); @@ -64,6 +70,8 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("reset start time", () => { drawableFruit.HitObject.StartTime = drawableBanana.HitObject.StartTime = initial_start_time; + drawableFruit.RefreshStateTransforms(); + drawableBanana.RefreshStateTransforms(); }); AddAssert("rotation and size restored", () => From e283aa2843104bf58bf027486cee0d595c65fa3a Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 21 Aug 2023 13:09:31 +0200 Subject: [PATCH 09/10] Update inline comments --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index f141263e27..c442fac0b8 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -330,7 +330,7 @@ namespace osu.Game.Rulesets.Objects.Drawables ClearNestedHitObjects(); // Changes in state trigger defaults applied trigger state updates. - // When a new hitobject is applied, OnApply() automatically performs a state update anyway. + // When a new hitobject is applied, OnApply() automatically performs a state update. HitObject.DefaultsApplied -= onDefaultsApplied; entry.RevertResult -= onRevertResult; @@ -391,6 +391,8 @@ namespace osu.Game.Rulesets.Objects.Drawables Apply(Entry); // Applied defaults indicate a change in hit object state. + // We need to update the judgement result time to the new end time + // and update state to ensure the hit object fades out at the correct time. if (Result is not null) { Result.TimeOffset = 0; From 5be533578499d25c54e18ea76ec2aae2a32a9b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Aug 2023 09:37:54 +0200 Subject: [PATCH 10/10] Reword comment to be better --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index c442fac0b8..e31656e0ff 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -329,8 +329,8 @@ namespace osu.Game.Rulesets.Objects.Drawables Entry.NestedEntries.RemoveAll(nestedEntry => nestedEntry is SyntheticHitObjectEntry); ClearNestedHitObjects(); - // Changes in state trigger defaults applied trigger state updates. - // When a new hitobject is applied, OnApply() automatically performs a state update. + // Changes to `HitObject` properties trigger default application, which triggers `State` updates. + // When a new hitobject is applied, `OnApply()` automatically performs a state update. HitObject.DefaultsApplied -= onDefaultsApplied; entry.RevertResult -= onRevertResult;