Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove osu!mania hold note ticks #25062

Merged
merged 23 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public TestSceneHitExplosion()
{
c.Add(hitExplosionPools[poolIndex].Get(e =>
{
e.Apply(new JudgementResult(new HitObject(), runCount % 6 == 0 ? new HoldNoteTickJudgement() : new ManiaJudgement()));
e.Apply(new JudgementResult(new HitObject(), new ManiaJudgement()));

e.Anchor = Anchor.Centre;
e.Origin = Anchor.Centre;
Expand Down
80 changes: 24 additions & 56 deletions osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ public void TestNoInput()
});

assertHeadJudgement(HitResult.Miss);
assertTickJudgement(HitResult.LargeTickMiss);
assertTailJudgement(HitResult.Miss);
assertNoteJudgement(HitResult.IgnoreMiss);
}
Expand All @@ -73,7 +72,6 @@ public void TestCorrectInput()
});

assertHeadJudgement(HitResult.Perfect);
assertTickJudgement(HitResult.LargeTickHit);
assertTailJudgement(HitResult.Perfect);
assertNoteJudgement(HitResult.IgnoreHit);
}
Expand All @@ -92,7 +90,6 @@ public void TestLateRelease()
});

assertHeadJudgement(HitResult.Perfect);
assertTickJudgement(HitResult.LargeTickHit);
assertTailJudgement(HitResult.Miss);
assertNoteJudgement(HitResult.IgnoreMiss);
}
Expand All @@ -111,7 +108,6 @@ public void TestPressTooEarlyAndReleaseAfterTail()
});

assertHeadJudgement(HitResult.Miss);
assertTickJudgement(HitResult.LargeTickMiss);
assertTailJudgement(HitResult.Miss);
}

Expand All @@ -129,7 +125,6 @@ public void TestPressTooEarlyAndReleaseAtTail()
});

assertHeadJudgement(HitResult.Miss);
assertTickJudgement(HitResult.LargeTickMiss);
assertTailJudgement(HitResult.Miss);
}

Expand All @@ -149,7 +144,6 @@ public void TestPressTooEarlyThenPressAtStartAndReleaseAfterTail()
});

assertHeadJudgement(HitResult.Perfect);
assertTickJudgement(HitResult.LargeTickHit);
assertTailJudgement(HitResult.Miss);
}

Expand All @@ -169,7 +163,6 @@ public void TestPressTooEarlyThenPressAtStartAndReleaseAtTail()
});

assertHeadJudgement(HitResult.Perfect);
assertTickJudgement(HitResult.LargeTickHit);
assertTailJudgement(HitResult.Perfect);
}

Expand All @@ -188,10 +181,31 @@ public void TestPressAtStartAndBreak()
});

assertHeadJudgement(HitResult.Perfect);
assertTickJudgement(HitResult.LargeTickMiss);
assertTailJudgement(HitResult.Miss);
}

/// <summary>
/// -----[ ]-----
/// xox o
/// </summary>
[Test]
public void TestPressAtStartThenReleaseAndImmediatelyRepress()
{
performTest(new List<ReplayFrame>
{
new ManiaReplayFrame(time_head, ManiaAction.Key1),
new ManiaReplayFrame(time_head + 1),
new ManiaReplayFrame(time_head + 2, ManiaAction.Key1),
new ManiaReplayFrame(time_tail),
});

assertHeadJudgement(HitResult.Perfect);
assertComboAtJudgement(0, 1);
assertTailJudgement(HitResult.Meh);
assertComboAtJudgement(1, 0);
assertComboAtJudgement(2, 1);
}

/// <summary>
/// -----[ ]-----
/// xo x o
Expand All @@ -208,7 +222,6 @@ public void TestPressAtStartThenBreakThenRepressAndReleaseAfterTail()
});

assertHeadJudgement(HitResult.Perfect);
assertTickJudgement(HitResult.LargeTickHit);
assertTailJudgement(HitResult.Miss);
}

Expand All @@ -228,7 +241,6 @@ public void TestPressAtStartThenBreakThenRepressAndReleaseAtTail()
});

assertHeadJudgement(HitResult.Perfect);
assertTickJudgement(HitResult.LargeTickHit);
assertTailJudgement(HitResult.Meh);
}

Expand All @@ -246,7 +258,6 @@ public void TestPressDuringNoteAndReleaseAfterTail()
});

assertHeadJudgement(HitResult.Miss);
assertTickJudgement(HitResult.LargeTickHit);
assertTailJudgement(HitResult.Miss);
}

Expand All @@ -264,7 +275,6 @@ public void TestPressDuringNoteAndReleaseAtTail()
});

assertHeadJudgement(HitResult.Miss);
assertTickJudgement(HitResult.LargeTickHit);
assertTailJudgement(HitResult.Meh);
}

Expand Down Expand Up @@ -358,7 +368,6 @@ public void TestPressAndReleaseJustBeforeTailWithNearbyNote()
}, beatmap);

assertHeadJudgement(HitResult.Miss);
assertTickJudgement(HitResult.LargeTickMiss);
assertTailJudgement(HitResult.Miss);

assertHitObjectJudgement(note, HitResult.Good);
Expand Down Expand Up @@ -405,7 +414,6 @@ public void TestPressAndReleaseJustAfterTailWithNearbyNote()
}, beatmap);

assertHeadJudgement(HitResult.Miss);
assertTickJudgement(HitResult.LargeTickMiss);
assertTailJudgement(HitResult.Miss);

assertHitObjectJudgement(note, HitResult.Great);
Expand All @@ -425,7 +433,6 @@ public void TestPressAndReleaseAtTail()
});

assertHeadJudgement(HitResult.Miss);
assertTickJudgement(HitResult.LargeTickMiss);
assertTailJudgement(HitResult.Meh);
}

Expand Down Expand Up @@ -476,42 +483,6 @@ public void TestMissReleaseAndHitSecondRelease()
.All(j => j.Type.IsHit()));
}

[Test]
public void TestHitTailBeforeLastTick()
{
const int tick_rate = 8;
const double tick_spacing = TimingControlPoint.DEFAULT_BEAT_LENGTH / tick_rate;
const double time_last_tick = time_head + tick_spacing * (int)((time_tail - time_head) / tick_spacing - 1);

var beatmap = new Beatmap<ManiaHitObject>
{
HitObjects =
{
new HoldNote
{
StartTime = time_head,
Duration = time_tail - time_head,
Column = 0,
}
},
BeatmapInfo =
{
Difficulty = new BeatmapDifficulty { SliderTickRate = tick_rate },
Ruleset = new ManiaRuleset().RulesetInfo
},
};

performTest(new List<ReplayFrame>
{
new ManiaReplayFrame(time_head, ManiaAction.Key1),
new ManiaReplayFrame(time_last_tick - 5)
}, beatmap);

assertHeadJudgement(HitResult.Perfect);
assertLastTickJudgement(HitResult.LargeTickMiss);
assertTailJudgement(HitResult.Ok);
}

[Test]
public void TestZeroLength()
{
Expand Down Expand Up @@ -551,11 +522,8 @@ private void assertTailJudgement(HitResult result)
private void assertNoteJudgement(HitResult result)
=> AddAssert($"hold note judged as {result}", () => judgementResults.Single(j => j.HitObject is HoldNote).Type, () => Is.EqualTo(result));

private void assertTickJudgement(HitResult result)
=> AddAssert($"any tick judged as {result}", () => judgementResults.Where(j => j.HitObject is HoldNoteTick).Select(j => j.Type), () => Does.Contain(result));

private void assertLastTickJudgement(HitResult result)
=> AddAssert($"last tick judged as {result}", () => judgementResults.Last(j => j.HitObject is HoldNoteTick).Type, () => Is.EqualTo(result));
private void assertComboAtJudgement(int judgementIndex, int combo)
=> AddAssert($"combo at judgement {judgementIndex} is {combo}", () => judgementResults.ElementAt(judgementIndex).ComboAfterJudgement, () => Is.EqualTo(combo));

private ScoreAccessibleReplayPlayer currentPlayer = null!;

Expand Down
13 changes: 13 additions & 0 deletions osu.Game.Rulesets.Mania/Judgements/HoldNoteBodyJudgement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Game.Rulesets.Scoring;

namespace osu.Game.Rulesets.Mania.Judgements
{
public class HoldNoteBodyJudgement : ManiaJudgement
{
public override HitResult MaxResult => HitResult.IgnoreHit;
public override HitResult MinResult => HitResult.ComboBreak;
}
}
12 changes: 0 additions & 12 deletions osu.Game.Rulesets.Mania/Judgements/HoldNoteTickJudgement.cs

This file was deleted.

40 changes: 13 additions & 27 deletions osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ public partial class DrawableHoldNote : DrawableManiaHitObject<HoldNote>, IKeyBi

public DrawableHoldNoteHead Head => headContainer.Child;
public DrawableHoldNoteTail Tail => tailContainer.Child;
public DrawableHoldNoteBody Body => bodyContainer.Child;

private Container<DrawableHoldNoteHead> headContainer;
private Container<DrawableHoldNoteTail> tailContainer;
private Container<DrawableHoldNoteTick> tickContainer;
private Container<DrawableHoldNoteBody> bodyContainer;

private PausableSkinnableSound slidingSample;

Expand All @@ -59,11 +60,6 @@ public partial class DrawableHoldNote : DrawableManiaHitObject<HoldNote>, IKeyBi
/// </summary>
public double? HoldStartTime { get; private set; }

/// <summary>
/// Time at which the hold note has been broken, i.e. released too early, resulting in a reduced score.
/// </summary>
public double? HoldBrokenTime { get; private set; }

/// <summary>
/// Whether the hold note has been released potentially without having caused a break.
/// </summary>
Expand Down Expand Up @@ -103,22 +99,21 @@ private void load()
headContainer = new Container<DrawableHoldNoteHead> { RelativeSizeAxes = Axes.Both }
}
},
bodyContainer = new Container<DrawableHoldNoteBody> { RelativeSizeAxes = Axes.Both },
bodyPiece = new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.HoldNoteBody), _ => new DefaultBodyPiece
{
RelativeSizeAxes = Axes.Both,
})
{
RelativeSizeAxes = Axes.X
},
tickContainer = new Container<DrawableHoldNoteTick> { RelativeSizeAxes = Axes.Both },
tailContainer = new Container<DrawableHoldNoteTail> { RelativeSizeAxes = Axes.Both },
slidingSample = new PausableSkinnableSound { Looping = true }
});

maskedContents.AddRange(new[]
{
bodyPiece.CreateProxy(),
tickContainer.CreateProxy(),
tailContainer.CreateProxy(),
});
}
Expand All @@ -136,7 +131,6 @@ protected override void OnApply()

sizingContainer.Size = Vector2.One;
HoldStartTime = null;
HoldBrokenTime = null;
releaseTime = null;
}

Expand All @@ -154,8 +148,8 @@ protected override void AddNestedHitObject(DrawableHitObject hitObject)
tailContainer.Child = tail;
break;

case DrawableHoldNoteTick tick:
tickContainer.Add(tick);
case DrawableHoldNoteBody body:
bodyContainer.Child = body;
break;
}
}
Expand All @@ -165,7 +159,7 @@ protected override void ClearNestedHitObjects()
base.ClearNestedHitObjects();
headContainer.Clear(false);
tailContainer.Clear(false);
tickContainer.Clear(false);
bodyContainer.Clear(false);
}

protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject)
Expand All @@ -178,8 +172,8 @@ protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject)
case HeadNote head:
return new DrawableHoldNoteHead(head);

case HoldNoteTick tick:
return new DrawableHoldNoteTick(tick);
case HoldNoteBody body:
return new DrawableHoldNoteBody(body);
}

return base.CreateNestedHitObject(hitObject);
Expand Down Expand Up @@ -266,20 +260,15 @@ protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (Tail.AllJudged)
{
foreach (var tick in tickContainer)
{
if (!tick.Judged)
tick.MissForcefully();
}

if (Tail.IsHit)
ApplyResult(r => r.Type = r.Judgement.MaxResult);
else
MissForcefully();
}

if (Tail.Judged && !Tail.IsHit)
HoldBrokenTime = Time.Current;
// Make sure that the hold note is fully judged by giving the body a judgement.
if (Tail.AllJudged && !Body.AllJudged)
Body.TriggerResult(Tail.IsHit);
}

public override void MissForcefully()
Expand Down Expand Up @@ -342,12 +331,9 @@ public void OnReleased(KeyBindingReleaseEvent<ManiaAction> e)
return;

Tail.UpdateResult();
endHold();

// If the key has been released too early, the user should not receive full score for the release
if (!Tail.IsHit)
HoldBrokenTime = Time.Current;
Body.TriggerResult(Tail.IsHit);

endHold();
releaseTime = Time.Current;
}

Expand Down
30 changes: 30 additions & 0 deletions osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteBody.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

#nullable disable
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider this temporary for now. DrawableHitObject is not properly annotated for its nullable ctor argument, and I don't want to use null! in this case.


namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
public partial class DrawableHoldNoteBody : DrawableManiaHitObject<HoldNoteBody>
{
public bool HasHoldBreak => AllJudged && !IsHit;

public override bool DisplayResult => false;

public DrawableHoldNoteBody()
: this(null)
{
}

public DrawableHoldNoteBody(HoldNoteBody hitObject)
: base(hitObject)
{
}

internal void TriggerResult(bool hit)
{
if (!AllJudged)
ApplyResult(r => r.Type = hit ? r.Judgement.MaxResult : r.Judgement.MinResult);
}
}
}