2024-06-29 16:08:40 +08:00
// 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 System.Collections.Generic ;
using System.Linq ;
using NUnit.Framework ;
using osu.Framework.Screens ;
using osu.Game.Beatmaps ;
using osu.Game.Beatmaps.ControlPoints ;
using osu.Game.Replays ;
using osu.Game.Rulesets.Judgements ;
using osu.Game.Rulesets.Mania.Mods ;
using osu.Game.Rulesets.Mania.Objects ;
using osu.Game.Rulesets.Mania.Replays ;
using osu.Game.Rulesets.Mania.Scoring ;
using osu.Game.Rulesets.Mods ;
using osu.Game.Rulesets.Objects ;
using osu.Game.Rulesets.Replays ;
using osu.Game.Rulesets.Scoring ;
using osu.Game.Scoring ;
using osu.Game.Screens.Play ;
using osu.Game.Tests.Visual ;
namespace osu.Game.Rulesets.Mania.Tests.Mods
{
public partial class TestSceneManiaModNoRelease : RateAdjustedBeatmapTestScene
{
private const double time_before_head = 250 ;
private const double time_head = 1500 ;
private const double time_during_hold_1 = 2500 ;
private const double time_tail = 4000 ;
private const double time_after_tail = 5250 ;
private List < JudgementResult > judgementResults = new List < JudgementResult > ( ) ;
/// <summary>
/// -----[ ]-----
/// o o
/// </summary>
[Test]
public void TestNoInput ( )
{
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_before_head ) ,
new ManiaReplayFrame ( time_after_tail ) ,
} ) ;
assertHeadJudgement ( HitResult . Miss ) ;
assertTailJudgement ( HitResult . Miss ) ;
assertNoteJudgement ( HitResult . IgnoreMiss ) ;
}
/// <summary>
/// -----[ ]-----
/// x o
/// </summary>
[Test]
public void TestCorrectInput ( )
{
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_head , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_tail ) ,
} ) ;
assertHeadJudgement ( HitResult . Perfect ) ;
assertTailJudgement ( HitResult . Perfect ) ;
assertNoteJudgement ( HitResult . IgnoreHit ) ;
}
/// <summary>
/// -----[ ]-----
/// x o
/// </summary>
[Test]
public void TestLateRelease ( )
{
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_head , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_after_tail ) ,
} ) ;
assertHeadJudgement ( HitResult . Perfect ) ;
assertTailJudgement ( HitResult . Perfect ) ;
assertNoteJudgement ( HitResult . IgnoreHit ) ;
}
/// <summary>
/// -----[ ]-----
/// x o
/// </summary>
[Test]
public void TestPressTooEarlyAndReleaseAfterTail ( )
{
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_before_head , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_after_tail , ManiaAction . Key1 ) ,
} ) ;
assertHeadJudgement ( HitResult . Miss ) ;
assertTailJudgement ( HitResult . Miss ) ;
}
/// <summary>
/// -----[ ]-----
/// x o
/// </summary>
[Test]
public void TestPressTooEarlyAndReleaseAtTail ( )
{
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_before_head , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_tail ) ,
} ) ;
assertHeadJudgement ( HitResult . Miss ) ;
assertTailJudgement ( HitResult . Miss ) ;
}
/// <summary>
/// -----[ ]-----
/// xo x o
/// </summary>
[Test]
public void TestPressTooEarlyThenPressAtStartAndReleaseAfterTail ( )
{
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_before_head , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_before_head + 10 ) ,
new ManiaReplayFrame ( time_head , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_after_tail ) ,
} ) ;
assertHeadJudgement ( HitResult . Perfect ) ;
assertTailJudgement ( HitResult . Perfect ) ;
}
/// <summary>
/// -----[ ]-----
/// xo x o
/// </summary>
[Test]
public void TestPressTooEarlyThenPressAtStartAndReleaseAtTail ( )
{
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_before_head , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_before_head + 10 ) ,
new ManiaReplayFrame ( time_head , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_tail ) ,
} ) ;
assertHeadJudgement ( HitResult . Perfect ) ;
assertTailJudgement ( HitResult . Perfect ) ;
}
/// <summary>
/// -----[ ]-----
/// xo o
/// </summary>
[Test]
public void TestPressAtStartAndBreak ( )
{
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_head , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_head + 10 ) ,
new ManiaReplayFrame ( time_after_tail ) ,
} ) ;
assertHeadJudgement ( HitResult . Perfect ) ;
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 ( 3 , 1 ) ;
}
/// <summary>
/// -----[ ]-----
/// xo x o
/// </summary>
[Test]
public void TestPressAtStartThenBreakThenRepressAndReleaseAfterTail ( )
{
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_head , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_head + 10 ) ,
new ManiaReplayFrame ( time_during_hold_1 , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_after_tail ) ,
} ) ;
assertHeadJudgement ( HitResult . Perfect ) ;
assertTailJudgement ( HitResult . Meh ) ;
}
/// <summary>
/// -----[ ]-----
/// xo x o o
/// </summary>
[Test]
public void TestPressAtStartThenBreakThenRepressAndReleaseAtTail ( )
{
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_head , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_head + 10 ) ,
new ManiaReplayFrame ( time_during_hold_1 , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_tail ) ,
} ) ;
assertHeadJudgement ( HitResult . Perfect ) ;
assertTailJudgement ( HitResult . Meh ) ;
}
/// <summary>
/// -----[ ]-----
/// x o
/// </summary>
[Test]
public void TestPressDuringNoteAndReleaseAfterTail ( )
{
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_during_hold_1 , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_after_tail ) ,
} ) ;
assertHeadJudgement ( HitResult . Miss ) ;
assertTailJudgement ( HitResult . Meh ) ;
}
/// <summary>
/// -----[ ]-----
/// x o o
/// </summary>
[Test]
public void TestPressDuringNoteAndReleaseAtTail ( )
{
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_during_hold_1 , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_tail ) ,
} ) ;
assertHeadJudgement ( HitResult . Miss ) ;
assertTailJudgement ( HitResult . Meh ) ;
}
/// <summary>
/// -----[ ]--------------
2024-07-01 19:34:33 +08:00
/// xo
2024-06-29 16:08:40 +08:00
/// </summary>
[Test]
2024-07-01 19:34:33 +08:00
public void TestPressAndReleaseAfterTailWithCloseByHead ( )
2024-06-29 16:08:40 +08:00
{
const int duration = 30 ;
var beatmap = new Beatmap < ManiaHitObject >
{
HitObjects =
{
// hold note is very short, to make the head still in range
new HoldNote
{
StartTime = time_head ,
Duration = duration ,
Column = 0 ,
}
} ,
BeatmapInfo =
{
Difficulty = new BeatmapDifficulty { SliderTickRate = 4 } ,
Ruleset = new ManiaRuleset ( ) . RulesetInfo
} ,
} ;
performTest ( new List < ReplayFrame >
{
2024-07-01 19:34:33 +08:00
new ManiaReplayFrame ( time_head + duration + 60 , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_head + duration + 70 ) ,
2024-06-29 16:08:40 +08:00
} , beatmap ) ;
2024-07-01 19:34:33 +08:00
assertHeadJudgement ( HitResult . Ok ) ;
2024-06-29 16:08:40 +08:00
assertTailJudgement ( HitResult . Perfect ) ;
}
/// <summary>
/// -----[ ]-O-------------
/// xo o
/// </summary>
[Test]
public void TestPressAndReleaseJustBeforeTailWithNearbyNoteAndCloseByHead ( )
{
Note note ;
const int duration = 50 ;
var beatmap = new Beatmap < ManiaHitObject >
{
HitObjects =
{
// hold note is very short, to make the head still in range
new HoldNote
{
StartTime = time_head ,
Duration = duration ,
Column = 0 ,
} ,
{
// Next note within tail lenience
note = new Note
{
StartTime = time_head + duration + 10
}
}
} ,
BeatmapInfo =
{
Difficulty = new BeatmapDifficulty { SliderTickRate = 4 } ,
Ruleset = new ManiaRuleset ( ) . RulesetInfo
} ,
} ;
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_head + duration , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_head + duration + 10 ) ,
} , beatmap ) ;
assertHeadJudgement ( HitResult . Good ) ;
assertTailJudgement ( HitResult . Perfect ) ;
assertHitObjectJudgement ( note , HitResult . Miss ) ;
}
/// <summary>
/// -----[ ]--O--
/// xo o
/// </summary>
[Test]
public void TestPressAndReleaseJustBeforeTailWithNearbyNote ( )
{
Note note ;
var beatmap = new Beatmap < ManiaHitObject >
{
HitObjects =
{
new HoldNote
{
StartTime = time_head ,
Duration = time_tail - time_head ,
Column = 0 ,
} ,
{
// Next note within tail lenience
note = new Note
{
StartTime = time_tail + 50
}
}
} ,
BeatmapInfo =
{
Difficulty = new BeatmapDifficulty { SliderTickRate = 4 } ,
Ruleset = new ManiaRuleset ( ) . RulesetInfo
} ,
} ;
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_tail - 10 , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_tail ) ,
} , beatmap ) ;
assertHeadJudgement ( HitResult . Miss ) ;
assertTailJudgement ( HitResult . Miss ) ;
assertHitObjectJudgement ( note , HitResult . Good ) ;
}
/// <summary>
/// -----[ ]-----
/// xo
/// </summary>
[Test]
public void TestPressAndReleaseJustAfterTail ( )
{
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_tail + 20 , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_tail + 30 ) ,
} ) ;
assertHeadJudgement ( HitResult . Miss ) ;
assertTailJudgement ( HitResult . Meh ) ;
}
/// <summary>
/// -----[ ]--O--
/// xo o
/// </summary>
[Test]
public void TestPressAndReleaseJustAfterTailWithNearbyNote ( )
{
// Next note within tail lenience
Note note = new Note { StartTime = time_tail + 50 } ;
var beatmap = new Beatmap < ManiaHitObject >
{
HitObjects =
{
new HoldNote
{
StartTime = time_head ,
Duration = time_tail - time_head ,
Column = 0 ,
} ,
note
} ,
BeatmapInfo =
{
Difficulty = new BeatmapDifficulty { SliderTickRate = 4 } ,
Ruleset = new ManiaRuleset ( ) . RulesetInfo
} ,
} ;
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_tail + 10 , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_tail + 20 ) ,
} , beatmap ) ;
assertHeadJudgement ( HitResult . Miss ) ;
assertTailJudgement ( HitResult . Miss ) ;
assertHitObjectJudgement ( note , HitResult . Great ) ;
}
/// <summary>
/// -----[ ]-----
/// xo o
/// </summary>
[Test]
public void TestPressAndReleaseAtTail ( )
{
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( time_tail , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( time_tail + 10 ) ,
} ) ;
assertHeadJudgement ( HitResult . Miss ) ;
assertTailJudgement ( HitResult . Meh ) ;
}
[Test]
public void TestMissReleaseAndHitSecondRelease ( )
{
var windows = new ManiaHitWindows ( ) ;
windows . SetDifficulty ( 10 ) ;
var beatmap = new Beatmap < ManiaHitObject >
{
HitObjects =
{
new HoldNote
{
StartTime = 1000 ,
Duration = 500 ,
Column = 0 ,
} ,
new HoldNote
{
StartTime = 1000 + 500 + windows . WindowFor ( HitResult . Miss ) + 10 ,
Duration = 500 ,
Column = 0 ,
} ,
} ,
BeatmapInfo =
{
Difficulty = new BeatmapDifficulty
{
SliderTickRate = 4 ,
OverallDifficulty = 10 ,
} ,
Ruleset = new ManiaRuleset ( ) . RulesetInfo
} ,
} ;
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( beatmap . HitObjects [ 1 ] . StartTime , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( beatmap . HitObjects [ 1 ] . GetEndTime ( ) ) ,
} , beatmap ) ;
AddAssert ( "first hold note missed" , ( ) = > judgementResults . Where ( j = > beatmap . HitObjects [ 0 ] . NestedHitObjects . Contains ( j . HitObject ) )
. All ( j = > ! j . Type . IsHit ( ) ) ) ;
AddAssert ( "second hold note hit" , ( ) = > judgementResults . Where ( j = > beatmap . HitObjects [ 1 ] . NestedHitObjects . Contains ( j . HitObject ) )
2024-06-29 16:46:16 +08:00
. All ( j = > j . Type . IsHit ( ) ) ) ;
2024-06-29 16:08:40 +08:00
}
[Test]
public void TestZeroLength ( )
{
var beatmap = new Beatmap < ManiaHitObject >
{
HitObjects =
{
new HoldNote
{
StartTime = 1000 ,
Duration = 0 ,
Column = 0 ,
} ,
} ,
BeatmapInfo = { Ruleset = new ManiaRuleset ( ) . RulesetInfo } ,
} ;
performTest ( new List < ReplayFrame >
{
new ManiaReplayFrame ( beatmap . HitObjects [ 0 ] . StartTime , ManiaAction . Key1 ) ,
new ManiaReplayFrame ( beatmap . HitObjects [ 0 ] . GetEndTime ( ) + 1 ) ,
} , beatmap ) ;
AddAssert ( "hold note hit" , ( ) = > judgementResults . Where ( j = > beatmap . HitObjects [ 0 ] . NestedHitObjects . Contains ( j . HitObject ) )
. All ( j = > j . Type . IsHit ( ) ) ) ;
}
private void assertHitObjectJudgement ( HitObject hitObject , HitResult result )
= > AddAssert ( $"object judged as {result}" , ( ) = > judgementResults . First ( j = > j . HitObject = = hitObject ) . Type , ( ) = > Is . EqualTo ( result ) ) ;
private void assertHeadJudgement ( HitResult result )
= > AddAssert ( $"head judged as {result}" , ( ) = > judgementResults . First ( j = > j . HitObject is Note ) . Type , ( ) = > Is . EqualTo ( result ) ) ;
private void assertTailJudgement ( HitResult result )
= > AddAssert ( $"tail judged as {result}" , ( ) = > judgementResults . Single ( j = > j . HitObject is TailNote ) . Type , ( ) = > Is . EqualTo ( 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 assertComboAtJudgement ( int judgementIndex , int combo )
= > AddAssert ( $"combo at judgement {judgementIndex} is {combo}" , ( ) = > judgementResults . ElementAt ( judgementIndex ) . ComboAfterJudgement , ( ) = > Is . EqualTo ( combo ) ) ;
private ScoreAccessibleReplayPlayer currentPlayer = null ! ;
private void performTest ( List < ReplayFrame > frames , Beatmap < ManiaHitObject > ? beatmap = null )
{
if ( beatmap = = null )
{
beatmap = new Beatmap < ManiaHitObject >
{
HitObjects =
{
new HoldNote
{
StartTime = time_head ,
Duration = time_tail - time_head ,
Column = 0 ,
}
} ,
BeatmapInfo =
{
Difficulty = new BeatmapDifficulty { SliderTickRate = 4 } ,
Ruleset = new ManiaRuleset ( ) . RulesetInfo ,
} ,
} ;
beatmap . ControlPointInfo . Add ( 0 , new EffectControlPoint { ScrollSpeed = 0.1f } ) ;
}
AddStep ( "load player" , ( ) = >
{
SelectedMods . Value = new List < Mod >
{
new ManiaModNoRelease ( )
} ;
Beatmap . Value = CreateWorkingBeatmap ( beatmap ) ;
var p = new ScoreAccessibleReplayPlayer ( new Score { Replay = new Replay { Frames = frames } } ) ;
p . OnLoadComplete + = _ = >
{
p . ScoreProcessor . NewJudgement + = result = >
{
if ( currentPlayer = = p ) judgementResults . Add ( result ) ;
} ;
} ;
LoadScreen ( currentPlayer = p ) ;
judgementResults = new List < JudgementResult > ( ) ;
} ) ;
AddUntilStep ( "Beatmap at 0" , ( ) = > Beatmap . Value . Track . CurrentTime = = 0 ) ;
AddUntilStep ( "Wait until player is loaded" , ( ) = > currentPlayer . IsCurrentScreen ( ) ) ;
AddUntilStep ( "Wait for completion" , ( ) = > currentPlayer . ScoreProcessor . HasCompleted . Value ) ;
}
private partial class ScoreAccessibleReplayPlayer : ReplayPlayer
{
public new ScoreProcessor ScoreProcessor = > base . ScoreProcessor ;
protected override bool PauseOnFocusLost = > false ;
public ScoreAccessibleReplayPlayer ( Score score )
: base ( score , new PlayerConfiguration
{
AllowPause = false ,
ShowResults = false ,
} )
{
}
}
}
}