From 1fb19e712922871adca31db706afd27ebb0a247f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 24 Feb 2024 20:18:30 +0300 Subject: [PATCH] Reduce allocations in DrawableSpinner --- .../Objects/Drawables/DrawableSpinner.cs | 32 ++++++++++++++++--- .../Objects/Drawables/DrawableHitObject.cs | 4 ++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 11120e49b5..8c21e6a6bc 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -279,10 +279,9 @@ protected override void Update() if (HandleUserInput) { bool isValidSpinningTime = Time.Current >= HitObject.StartTime && Time.Current <= HitObject.EndTime; - bool correctButtonPressed = (OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false); RotationTracker.Tracking = !Result.HasResult - && correctButtonPressed + && correctButtonPressed() && isValidSpinningTime; } @@ -292,11 +291,34 @@ protected override void Update() // Ticks can theoretically be judged at any point in the spinner's duration. // A tick must be alive to correctly play back samples, // but for performance reasons, we only want to keep the next tick alive. - var next = NestedHitObjects.FirstOrDefault(h => !h.Judged); + DrawableHitObject nextTick = null; + + foreach (var nested in NestedHitObjects) + { + if (!nested.Judged) + { + nextTick = nested; + break; + } + } // See default `LifetimeStart` as set in `DrawableSpinnerTick`. - if (next?.LifetimeStart == double.MaxValue) - next.LifetimeStart = HitObject.StartTime; + if (nextTick?.LifetimeStart == double.MaxValue) + nextTick.LifetimeStart = HitObject.StartTime; + } + + private bool correctButtonPressed() + { + if (OsuActionInputManager == null) + return false; + + foreach (var action in OsuActionInputManager.PressedActions) + { + if (action == OsuAction.LeftButton || action == OsuAction.RightButton) + return true; + } + + return false; } protected override void UpdateAfterChildren() diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 16bd4b565c..de05219212 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -11,10 +11,12 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ListExtensions; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; +using osu.Framework.Lists; using osu.Framework.Threading; using osu.Framework.Utils; using osu.Game.Audio; @@ -65,7 +67,7 @@ public abstract partial class DrawableHitObject : PoolableDrawableWithLifetime GetSamples() => HitObject.Samples; private readonly List nestedHitObjects = new List(); - public IReadOnlyList NestedHitObjects => nestedHitObjects; + public SlimReadOnlyListWrapper NestedHitObjects => nestedHitObjects.AsSlimReadOnly(); /// /// Whether this object should handle any user input events.