Skip to content

Commit

Permalink
Merge pull request #26694 from chandler14362/hit-object-result-alloca…
Browse files Browse the repository at this point in the history
…tions

Avoid closure allocations when applying hit object results
  • Loading branch information
smoogipoo committed Feb 6, 2024
2 parents c093fe6 + fb80d76 commit c18cd65
Show file tree
Hide file tree
Showing 27 changed files with 123 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (timeOffset >= 0)
// todo: implement judgement logic
ApplyResult(r => r.Type = HitResult.Perfect);
ApplyResult(HitResult.Perfect);
}

protected override void UpdateHitStateTransforms(ArmedState state)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using osu.Framework.Graphics.Textures;
using osu.Game.Audio;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osuTK;
using osuTK.Graphics;

Expand Down Expand Up @@ -49,7 +48,12 @@ private void load(TextureStore textures)
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (timeOffset >= 0)
ApplyResult(r => r.Type = IsHovered ? HitResult.Perfect : HitResult.Miss);
{
if (IsHovered)
ApplyMaxResult();
else
ApplyMinResult();
}
}

protected override double InitialLifetimeOffset => time_preempt;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osuTK;
using osuTK.Graphics;

Expand All @@ -24,7 +23,7 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (timeOffset >= 0)
// todo: implement judgement logic
ApplyResult(r => r.Type = HitResult.Perfect);
ApplyMaxResult();
}

protected override void UpdateHitStateTransforms(ArmedState state)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using osu.Game.Audio;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Pippidon.UI;
using osu.Game.Rulesets.Scoring;
using osuTK;
using osuTK.Graphics;

Expand Down Expand Up @@ -49,7 +48,12 @@ private void load(PippidonPlayfield playfield, TextureStore textures)
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (timeOffset >= 0)
ApplyResult(r => r.Type = currentLane.Value == HitObject.Lane ? HitResult.Perfect : HitResult.Miss);
{
if (currentLane.Value == HitObject.Lane)
ApplyMaxResult();
else
ApplyMinResult();
}
}

protected override void UpdateHitStateTransforms(ArmedState state)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,12 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
if (CheckPosition == null) return;

if (timeOffset >= 0 && Result != null)
ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? r.Judgement.MaxResult : r.Judgement.MinResult);
{
if (CheckPosition.Invoke(HitObject))
ApplyMaxResult();
else
ApplyMinResult();
}
}

protected override void UpdateHitStateTransforms(ArmedState state)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
if (Tail.AllJudged)
{
if (Tail.IsHit)
ApplyResult(r => r.Type = r.Judgement.MaxResult);
ApplyMaxResult();
else
MissForcefully();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ internal void TriggerResult(bool hit)
{
if (AllJudged) return;

ApplyResult(r => r.Type = hit ? r.Judgement.MaxResult : r.Judgement.MinResult);
if (hit)
ApplyMaxResult();
else
ApplyMinResult();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ protected override void UpdateHitStateTransforms(ArmedState state)
/// <summary>
/// Causes this <see cref="DrawableManiaHitObject"/> to get missed, disregarding all conditions in implementations of <see cref="DrawableHitObject.CheckForResult"/>.
/// </summary>
public virtual void MissForcefully() => ApplyResult(r => r.Type = r.Judgement.MinResult);
public virtual void MissForcefully() => ApplyMinResult();
}

public abstract partial class DrawableManiaHitObject<TObject> : DrawableManiaHitObject
Expand Down
6 changes: 3 additions & 3 deletions osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,18 +89,18 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
if (!userTriggered)
{
if (!HitObject.HitWindows.CanBeHit(timeOffset))
ApplyResult(r => r.Type = r.Judgement.MinResult);
ApplyMinResult();

return;
}

var result = HitObject.HitWindows.ResultFor(timeOffset);

if (result == HitResult.None)
return;

result = GetCappedResult(result);

ApplyResult(r => r.Type = result);
ApplyResult(result);
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
if (auto && !userTriggered && timeOffset > hitOffset && CheckHittable?.Invoke(this, Time.Current, HitResult.Great) == ClickAction.Hit)
{
// force success
ApplyResult(r => r.Type = HitResult.Great);
ApplyResult(HitResult.Great);
}
else
base.CheckForResult(userTriggered, timeOffset);
Expand Down
2 changes: 1 addition & 1 deletion osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLateFade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
if (shouldHit && !userTriggered && timeOffset >= 0)
{
// force success
ApplyResult(r => r.Type = HitResult.Great);
ApplyResult(HitResult.Great);
}
else
base.CheckForResult(userTriggered, timeOffset);
Expand Down
25 changes: 14 additions & 11 deletions osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
if (!userTriggered)
{
if (!HitObject.HitWindows.CanBeHit(timeOffset))
ApplyResult(r => r.Type = r.Judgement.MinResult);
ApplyMinResult();

return;
}
Expand All @@ -169,19 +169,22 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
if (result == HitResult.None || clickAction != ClickAction.Hit)
return;

ApplyResult(r =>
Vector2? hitPosition = null;

// Todo: This should also consider misses, but they're a little more interesting to handle, since we don't necessarily know the position at the time of a miss.
if (result.IsHit())
{
var circleResult = (OsuHitCircleJudgementResult)r;
var localMousePosition = ToLocalSpace(inputManager.CurrentState.Mouse.Position);
hitPosition = HitObject.StackedPosition + (localMousePosition - DrawSize / 2);
}

// Todo: This should also consider misses, but they're a little more interesting to handle, since we don't necessarily know the position at the time of a miss.
if (result.IsHit())
{
var localMousePosition = ToLocalSpace(inputManager.CurrentState.Mouse.Position);
circleResult.CursorPositionAtHit = HitObject.StackedPosition + (localMousePosition - DrawSize / 2);
}
ApplyResult<(HitResult result, Vector2? position)>((r, state) =>
{
var circleResult = (OsuHitCircleJudgementResult)r;
circleResult.Type = result;
});
circleResult.Type = state.result;
circleResult.CursorPositionAtHit = state.position;
}, (result, hitPosition));
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,12 @@ protected override void UpdateInitialTransforms()
/// <summary>
/// Causes this <see cref="DrawableOsuHitObject"/> to get hit, disregarding all conditions in implementations of <see cref="DrawableHitObject.CheckForResult"/>.
/// </summary>
public void HitForcefully() => ApplyResult(r => r.Type = r.Judgement.MaxResult);
public void HitForcefully() => ApplyMaxResult();

/// <summary>
/// Causes this <see cref="DrawableOsuHitObject"/> to get missed, disregarding all conditions in implementations of <see cref="DrawableHitObject.CheckForResult"/>.
/// </summary>
public void MissForcefully() => ApplyResult(r => r.Type = r.Judgement.MinResult);
public void MissForcefully() => ApplyMinResult();

private RectangleF parentScreenSpaceRectangle => ((DrawableOsuHitObject)ParentHitObject)?.parentScreenSpaceRectangle ?? Parent!.ScreenSpaceDrawQuad.AABBFloat;

Expand Down
11 changes: 7 additions & 4 deletions osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,10 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
if (HitObject.ClassicSliderBehaviour)
{
// Classic behaviour means a slider is judged proportionally to the number of nested hitobjects hit. This is the classic osu!stable scoring.
ApplyResult(r =>
ApplyResult(static (r, hitObject) =>
{
int totalTicks = NestedHitObjects.Count;
int hitTicks = NestedHitObjects.Count(h => h.IsHit);
int totalTicks = hitObject.NestedHitObjects.Count;
int hitTicks = hitObject.NestedHitObjects.Count(h => h.IsHit);
if (hitTicks == totalTicks)
r.Type = HitResult.Great;
Expand All @@ -312,7 +312,10 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
{
// If only the nested hitobjects are judged, then the slider's own judgement is ignored for scoring purposes.
// But the slider needs to still be judged with a reasonable hit/miss result for visual purposes (hit/miss transforms, etc).
ApplyResult(r => r.Type = NestedHitObjects.Any(h => h.Result.IsHit) ? r.Judgement.MaxResult : r.Judgement.MinResult);
ApplyResult(static (r, hitObject) =>
{
r.Type = hitObject.NestedHitObjects.Any(h => h.Result.IsHit) ? r.Judgement.MaxResult : r.Judgement.MinResult;
});
}
}

Expand Down
11 changes: 6 additions & 5 deletions osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -258,15 +258,16 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
foreach (var tick in ticks.Where(t => !t.Result.HasResult))
tick.TriggerResult(false);

ApplyResult(r =>
ApplyResult(static (r, hitObject) =>
{
if (Progress >= 1)
var spinner = (DrawableSpinner)hitObject;
if (spinner.Progress >= 1)
r.Type = HitResult.Great;
else if (Progress > .9)
else if (spinner.Progress > .9)
r.Type = HitResult.Ok;
else if (Progress > .75)
else if (spinner.Progress > .75)
r.Type = HitResult.Meh;
else if (Time.Current >= HitObject.EndTime)
else if (spinner.Time.Current >= spinner.HitObject.EndTime)
r.Type = r.Judgement.MinResult;
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ protected override void OnApply()
/// Apply a judgement result.
/// </summary>
/// <param name="hit">Whether this tick was reached.</param>
internal void TriggerResult(bool hit) => ApplyResult(r => r.Type = hit ? r.Judgement.MaxResult : r.Judgement.MinResult);
internal void TriggerResult(bool hit)
{
if (hit)
ApplyMaxResult();
else
ApplyMinResult();
}
}
}
8 changes: 6 additions & 2 deletions osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
if (timeOffset < 0)
return;

ApplyResult(r => r.Type = r.Judgement.MaxResult);
ApplyMaxResult();
}

protected override void UpdateHitStateTransforms(ArmedState state)
Expand Down Expand Up @@ -192,7 +192,11 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
if (!ParentHitObject.Judged)
return;

ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
ApplyResult(static (r, hitObject) =>
{
var drumRoll = (StrongNestedHit)hitObject;
r.Type = drumRoll.ParentHitObject!.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult;
});
}

public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e) => false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,22 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
if (!userTriggered)
{
if (timeOffset > HitObject.HitWindow)
ApplyResult(r => r.Type = r.Judgement.MinResult);
ApplyMinResult();
return;
}

if (Math.Abs(timeOffset) > HitObject.HitWindow)
return;

ApplyResult(r => r.Type = r.Judgement.MaxResult);
ApplyMaxResult();
}

public override void OnKilled()
{
base.OnKilled();

if (Time.Current > HitObject.GetEndTime() && !Judged)
ApplyResult(r => r.Type = r.Judgement.MinResult);
ApplyMinResult();
}

protected override void UpdateHitStateTransforms(ArmedState state)
Expand Down Expand Up @@ -105,7 +105,11 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
if (!ParentHitObject.Judged)
return;

ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
ApplyResult(static (r, hitObject) =>
{
var nestedHit = (StrongNestedHit)hitObject;
r.Type = nestedHit.ParentHitObject!.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult;
});
}

public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e) => false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public DrawableFlyingHit(DrawableDrumRollTick drumRollTick)
protected override void LoadComplete()
{
base.LoadComplete();
ApplyResult(r => r.Type = r.Judgement.MaxResult);
ApplyMaxResult();
}

protected override void LoadSamples()
Expand Down
12 changes: 6 additions & 6 deletions osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
if (!userTriggered)
{
if (!HitObject.HitWindows.CanBeHit(timeOffset))
ApplyResult(r => r.Type = r.Judgement.MinResult);
ApplyMinResult();
return;
}

Expand All @@ -108,9 +108,9 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
return;

if (!validActionPressed)
ApplyResult(r => r.Type = r.Judgement.MinResult);
ApplyMinResult();
else
ApplyResult(r => r.Type = result);
ApplyResult(result);
}

public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
Expand Down Expand Up @@ -209,19 +209,19 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)

if (!ParentHitObject.Result.IsHit)
{
ApplyResult(r => r.Type = r.Judgement.MinResult);
ApplyMinResult();
return;
}

if (!userTriggered)
{
if (timeOffset - ParentHitObject.Result.TimeOffset > SECOND_HIT_WINDOW)
ApplyResult(r => r.Type = r.Judgement.MinResult);
ApplyMinResult();
return;
}

if (Math.Abs(timeOffset - ParentHitObject.Result.TimeOffset) <= SECOND_HIT_WINDOW)
ApplyResult(r => r.Type = r.Judgement.MaxResult);
ApplyMaxResult();
}

public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public override void OnKilled()
// it can happen that the hit window of the nested strong hit extends past the lifetime of the parent object.
// this is a safety to prevent such cases from causing the nested hit to never be judged and as such prevent gameplay from completing.
if (!Judged && Time.Current > ParentHitObject?.HitObject.GetEndTime())
ApplyResult(r => r.Type = r.Judgement.MinResult);
ApplyMinResult();
}
}
}

0 comments on commit c18cd65

Please sign in to comment.