Merge pull request #27364 from EVAST9919/spinner-alloc

Reduce osu spinner allocations
This commit is contained in:
Dean Herbert 2024-02-25 09:36:02 +08:00 committed by GitHub
commit e8d2abc4f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 36 additions and 10 deletions

View File

@ -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()

View File

@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.ObjectExtensions;
@ -33,14 +32,16 @@ protected override void LoadComplete()
drawableSpinner.HitObjectApplied += resetState;
}
private RotationRecord lastRecord;
public void SetRotation(float currentRotation)
{
// If we've gone back in time, it's fine to work with a fresh set of records for now
if (records.Count > 0 && Time.Current < records.Last().Time)
if (records.Count > 0 && Time.Current < lastRecord.Time)
records.Clear();
// Never calculate SPM by same time of record to avoid 0 / 0 = NaN or X / 0 = Infinity result.
if (records.Count > 0 && Precision.AlmostEquals(Time.Current, records.Last().Time))
if (records.Count > 0 && Precision.AlmostEquals(Time.Current, lastRecord.Time))
return;
if (records.Count > 0)
@ -52,11 +53,12 @@ record = records.Dequeue();
result.Value = (currentRotation - record.Rotation) / (Time.Current - record.Time) * 1000 * 60 / 360;
}
records.Enqueue(new RotationRecord { Rotation = currentRotation, Time = Time.Current });
records.Enqueue(lastRecord = new RotationRecord { Rotation = currentRotation, Time = Time.Current });
}
private void resetState(DrawableHitObject hitObject)
{
lastRecord = default;
result.Value = 0;
records.Clear();
}

View File

@ -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<H
public virtual IEnumerable<HitSampleInfo> GetSamples() => HitObject.Samples;
private readonly List<DrawableHitObject> nestedHitObjects = new List<DrawableHitObject>();
public IReadOnlyList<DrawableHitObject> NestedHitObjects => nestedHitObjects;
public SlimReadOnlyListWrapper<DrawableHitObject> NestedHitObjects => nestedHitObjects.AsSlimReadOnly();
/// <summary>
/// Whether this object should handle any user input events.