mirror of
https://github.com/ppy/osu.git
synced 2025-03-06 13:37:46 +08:00
Merge pull request #24627 from bdach/no-custom-hitwindows
Rewrite `TestSceneObjectOrderedHitPolicy` to not rely on custom hitwindows
This commit is contained in:
commit
d01b065b4a
@ -1,15 +1,12 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Extensions.TypeExtensions;
|
using osu.Framework.Extensions.TypeExtensions;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Replays;
|
using osu.Game.Replays;
|
||||||
@ -19,6 +16,7 @@ using osu.Game.Rulesets.Objects.Types;
|
|||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Replays;
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
|
using osu.Game.Rulesets.Osu.Scoring;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
@ -30,8 +28,13 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
public partial class TestSceneObjectOrderedHitPolicy : RateAdjustedBeatmapTestScene
|
public partial class TestSceneObjectOrderedHitPolicy : RateAdjustedBeatmapTestScene
|
||||||
{
|
{
|
||||||
private const double early_miss_window = 1000; // time after -1000 to -500 is considered a miss
|
private readonly OsuHitWindows referenceHitWindows;
|
||||||
private const double late_miss_window = 500; // time after +500 is considered a miss
|
|
||||||
|
public TestSceneObjectOrderedHitPolicy()
|
||||||
|
{
|
||||||
|
referenceHitWindows = new OsuHitWindows();
|
||||||
|
referenceHitWindows.SetDifficulty(0);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests clicking a future circle before the first circle's start time, while the first circle HAS NOT been judged.
|
/// Tests clicking a future circle before the first circle's start time, while the first circle HAS NOT been judged.
|
||||||
@ -46,12 +49,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_first_circle,
|
StartTime = time_first_circle,
|
||||||
Position = positionFirstCircle
|
Position = positionFirstCircle
|
||||||
},
|
},
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_second_circle,
|
StartTime = time_second_circle,
|
||||||
Position = positionSecondCircle
|
Position = positionSecondCircle
|
||||||
@ -65,7 +68,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Miss);
|
addJudgementAssert(hitObjects[0], HitResult.Miss);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Miss);
|
addJudgementAssert(hitObjects[1], HitResult.Miss);
|
||||||
addJudgementOffsetAssert(hitObjects[0], late_miss_window);
|
// note lock prevented the object from being hit, so the judgement offset should be very late.
|
||||||
|
addJudgementOffsetAssert(hitObjects[0], referenceHitWindows.WindowFor(HitResult.Meh));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -81,12 +85,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_first_circle,
|
StartTime = time_first_circle,
|
||||||
Position = positionFirstCircle
|
Position = positionFirstCircle
|
||||||
},
|
},
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_second_circle,
|
StartTime = time_second_circle,
|
||||||
Position = positionSecondCircle
|
Position = positionSecondCircle
|
||||||
@ -100,7 +104,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Miss);
|
addJudgementAssert(hitObjects[0], HitResult.Miss);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Miss);
|
addJudgementAssert(hitObjects[1], HitResult.Miss);
|
||||||
addJudgementOffsetAssert(hitObjects[0], late_miss_window);
|
// note lock prevented the object from being hit, so the judgement offset should be very late.
|
||||||
|
addJudgementOffsetAssert(hitObjects[0], referenceHitWindows.WindowFor(HitResult.Meh));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -116,12 +121,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_first_circle,
|
StartTime = time_first_circle,
|
||||||
Position = positionFirstCircle
|
Position = positionFirstCircle
|
||||||
},
|
},
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_second_circle,
|
StartTime = time_second_circle,
|
||||||
Position = positionSecondCircle
|
Position = positionSecondCircle
|
||||||
@ -135,7 +140,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Miss);
|
addJudgementAssert(hitObjects[0], HitResult.Miss);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Miss);
|
addJudgementAssert(hitObjects[1], HitResult.Miss);
|
||||||
addJudgementOffsetAssert(hitObjects[0], late_miss_window);
|
// note lock prevented the object from being hit, so the judgement offset should be very late.
|
||||||
|
addJudgementOffsetAssert(hitObjects[0], referenceHitWindows.WindowFor(HitResult.Meh));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -151,12 +157,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_first_circle,
|
StartTime = time_first_circle,
|
||||||
Position = positionFirstCircle
|
Position = positionFirstCircle
|
||||||
},
|
},
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_second_circle,
|
StartTime = time_second_circle,
|
||||||
Position = positionSecondCircle
|
Position = positionSecondCircle
|
||||||
@ -169,8 +175,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
new OsuReplayFrame { Time = time_first_circle - 100, Position = positionSecondCircle, Actions = { OsuAction.RightButton } }
|
new OsuReplayFrame { Time = time_first_circle - 100, Position = positionSecondCircle, Actions = { OsuAction.RightButton } }
|
||||||
});
|
});
|
||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Great);
|
addJudgementAssert(hitObjects[0], HitResult.Meh);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Great);
|
addJudgementAssert(hitObjects[1], HitResult.Meh);
|
||||||
addJudgementOffsetAssert(hitObjects[0], -200); // time_first_circle - 200
|
addJudgementOffsetAssert(hitObjects[0], -200); // time_first_circle - 200
|
||||||
addJudgementOffsetAssert(hitObjects[0], -200); // time_second_circle - first_circle_time - 100
|
addJudgementOffsetAssert(hitObjects[0], -200); // time_second_circle - first_circle_time - 100
|
||||||
}
|
}
|
||||||
@ -188,12 +194,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_first_circle,
|
StartTime = time_first_circle,
|
||||||
Position = positionFirstCircle
|
Position = positionFirstCircle
|
||||||
},
|
},
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_second_circle,
|
StartTime = time_second_circle,
|
||||||
Position = positionSecondCircle
|
Position = positionSecondCircle
|
||||||
@ -206,8 +212,8 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
new OsuReplayFrame { Time = time_first_circle, Position = positionSecondCircle, Actions = { OsuAction.RightButton } }
|
new OsuReplayFrame { Time = time_first_circle, Position = positionSecondCircle, Actions = { OsuAction.RightButton } }
|
||||||
});
|
});
|
||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Great);
|
addJudgementAssert(hitObjects[0], HitResult.Meh);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Great);
|
addJudgementAssert(hitObjects[1], HitResult.Ok);
|
||||||
addJudgementOffsetAssert(hitObjects[0], -200); // time_first_circle - 200
|
addJudgementOffsetAssert(hitObjects[0], -200); // time_first_circle - 200
|
||||||
addJudgementOffsetAssert(hitObjects[1], -100); // time_second_circle - first_circle_time
|
addJudgementOffsetAssert(hitObjects[1], -100); // time_second_circle - first_circle_time
|
||||||
}
|
}
|
||||||
@ -225,19 +231,19 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_circle,
|
StartTime = time_circle,
|
||||||
Position = positionCircle
|
Position = positionCircle
|
||||||
},
|
},
|
||||||
new TestSlider
|
new Slider
|
||||||
{
|
{
|
||||||
StartTime = time_slider,
|
StartTime = time_slider,
|
||||||
Position = positionSlider,
|
Position = positionSlider,
|
||||||
Path = new SliderPath(PathType.Linear, new[]
|
Path = new SliderPath(PathType.Linear, new[]
|
||||||
{
|
{
|
||||||
Vector2.Zero,
|
Vector2.Zero,
|
||||||
new Vector2(25, 0),
|
new Vector2(50, 0),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -267,19 +273,19 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_circle,
|
StartTime = time_circle,
|
||||||
Position = positionCircle
|
Position = positionCircle
|
||||||
},
|
},
|
||||||
new TestSlider
|
new Slider
|
||||||
{
|
{
|
||||||
StartTime = time_slider,
|
StartTime = time_slider,
|
||||||
Position = positionSlider,
|
Position = positionSlider,
|
||||||
Path = new SliderPath(PathType.Linear, new[]
|
Path = new SliderPath(PathType.Linear, new[]
|
||||||
{
|
{
|
||||||
Vector2.Zero,
|
Vector2.Zero,
|
||||||
new Vector2(25, 0),
|
new Vector2(50, 0),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -287,11 +293,11 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
performTest(hitObjects, new List<ReplayFrame>
|
performTest(hitObjects, new List<ReplayFrame>
|
||||||
{
|
{
|
||||||
new OsuReplayFrame { Time = time_slider, Position = positionSlider, Actions = { OsuAction.LeftButton } },
|
new OsuReplayFrame { Time = time_slider, Position = positionSlider, Actions = { OsuAction.LeftButton } },
|
||||||
new OsuReplayFrame { Time = time_circle + late_miss_window - 100, Position = positionCircle, Actions = { OsuAction.RightButton } },
|
new OsuReplayFrame { Time = time_circle + referenceHitWindows.WindowFor(HitResult.Meh) - 100, Position = positionCircle, Actions = { OsuAction.RightButton } },
|
||||||
new OsuReplayFrame { Time = time_circle + late_miss_window - 90, Position = positionSlider, Actions = { OsuAction.LeftButton } },
|
new OsuReplayFrame { Time = time_circle + referenceHitWindows.WindowFor(HitResult.Meh) - 90, Position = positionSlider, Actions = { OsuAction.LeftButton } },
|
||||||
});
|
});
|
||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Great);
|
addJudgementAssert(hitObjects[0], HitResult.Ok);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Great);
|
addJudgementAssert(hitObjects[1], HitResult.Great);
|
||||||
addJudgementAssert("slider head", () => ((Slider)hitObjects[1]).HeadCircle, HitResult.LargeTickHit);
|
addJudgementAssert("slider head", () => ((Slider)hitObjects[1]).HeadCircle, HitResult.LargeTickHit);
|
||||||
addJudgementAssert("slider tick", () => ((Slider)hitObjects[1]).NestedHitObjects[1] as SliderTick, HitResult.LargeTickHit);
|
addJudgementAssert("slider tick", () => ((Slider)hitObjects[1]).NestedHitObjects[1] as SliderTick, HitResult.LargeTickHit);
|
||||||
@ -304,7 +310,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
public void TestHitCircleBeforeSpinner()
|
public void TestHitCircleBeforeSpinner()
|
||||||
{
|
{
|
||||||
const double time_spinner = 1500;
|
const double time_spinner = 1500;
|
||||||
const double time_circle = 1800;
|
const double time_circle = 1600;
|
||||||
Vector2 positionCircle = Vector2.Zero;
|
Vector2 positionCircle = Vector2.Zero;
|
||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
@ -315,7 +321,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
Position = new Vector2(256, 192),
|
Position = new Vector2(256, 192),
|
||||||
EndTime = time_spinner + 1000,
|
EndTime = time_spinner + 1000,
|
||||||
},
|
},
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_circle,
|
StartTime = time_circle,
|
||||||
Position = positionCircle
|
Position = positionCircle
|
||||||
@ -333,7 +339,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Great);
|
addJudgementAssert(hitObjects[0], HitResult.Great);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Great);
|
addJudgementAssert(hitObjects[1], HitResult.Meh);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -346,12 +352,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
var hitObjects = new List<OsuHitObject>
|
var hitObjects = new List<OsuHitObject>
|
||||||
{
|
{
|
||||||
new TestHitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = time_circle,
|
StartTime = time_circle,
|
||||||
Position = positionCircle
|
Position = positionCircle
|
||||||
},
|
},
|
||||||
new TestSlider
|
new Slider
|
||||||
{
|
{
|
||||||
StartTime = time_slider,
|
StartTime = time_slider,
|
||||||
Position = positionSlider,
|
Position = positionSlider,
|
||||||
@ -380,20 +386,20 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
() => judgementResults.Single(r => r.HitObject == hitObject).Type, () => Is.EqualTo(result));
|
() => judgementResults.Single(r => r.HitObject == hitObject).Type, () => Is.EqualTo(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addJudgementAssert(string name, Func<OsuHitObject> hitObject, HitResult result)
|
private void addJudgementAssert(string name, Func<OsuHitObject?> hitObject, HitResult result)
|
||||||
{
|
{
|
||||||
AddAssert($"{name} judgement is {result}",
|
AddAssert($"{name} judgement is {result}",
|
||||||
() => judgementResults.Single(r => r.HitObject == hitObject()).Type == result);
|
() => judgementResults.Single(r => r.HitObject == hitObject()).Type, () => Is.EqualTo(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addJudgementOffsetAssert(OsuHitObject hitObject, double offset)
|
private void addJudgementOffsetAssert(OsuHitObject hitObject, double offset)
|
||||||
{
|
{
|
||||||
AddAssert($"({hitObject.GetType().ReadableName()} @ {hitObject.StartTime}) judged at {offset}",
|
AddAssert($"({hitObject.GetType().ReadableName()} @ {hitObject.StartTime}) judged at {offset}",
|
||||||
() => Precision.AlmostEquals(judgementResults.Single(r => r.HitObject == hitObject).TimeOffset, offset, 100));
|
() => judgementResults.Single(r => r.HitObject == hitObject).TimeOffset, () => Is.EqualTo(offset).Within(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScoreAccessibleReplayPlayer currentPlayer;
|
private ScoreAccessibleReplayPlayer currentPlayer = null!;
|
||||||
private List<JudgementResult> judgementResults;
|
private List<JudgementResult> judgementResults = null!;
|
||||||
|
|
||||||
private void performTest(List<OsuHitObject> hitObjects, List<ReplayFrame> frames)
|
private void performTest(List<OsuHitObject> hitObjects, List<ReplayFrame> frames)
|
||||||
{
|
{
|
||||||
@ -402,7 +408,11 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
Beatmap.Value = CreateWorkingBeatmap(new Beatmap<OsuHitObject>
|
Beatmap.Value = CreateWorkingBeatmap(new Beatmap<OsuHitObject>
|
||||||
{
|
{
|
||||||
HitObjects = hitObjects,
|
HitObjects = hitObjects,
|
||||||
Difficulty = new BeatmapDifficulty { SliderTickRate = 3 },
|
Difficulty = new BeatmapDifficulty
|
||||||
|
{
|
||||||
|
OverallDifficulty = 0,
|
||||||
|
SliderTickRate = 3
|
||||||
|
},
|
||||||
BeatmapInfo =
|
BeatmapInfo =
|
||||||
{
|
{
|
||||||
Ruleset = new OsuRuleset().RulesetInfo
|
Ruleset = new OsuRuleset().RulesetInfo
|
||||||
@ -430,28 +440,6 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
|
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestHitCircle : HitCircle
|
|
||||||
{
|
|
||||||
protected override HitWindows CreateHitWindows() => new TestHitWindows();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestSlider : Slider
|
|
||||||
{
|
|
||||||
public TestSlider()
|
|
||||||
{
|
|
||||||
SliderVelocity = 0.1f;
|
|
||||||
|
|
||||||
DefaultsApplied += _ =>
|
|
||||||
{
|
|
||||||
HeadCircle.HitWindows = new TestHitWindows();
|
|
||||||
TailCircle.HitWindows = new TestHitWindows();
|
|
||||||
|
|
||||||
HeadCircle.HitWindows.SetDifficulty(0);
|
|
||||||
TailCircle.HitWindows.SetDifficulty(0);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestSpinner : Spinner
|
private class TestSpinner : Spinner
|
||||||
{
|
{
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
|
||||||
@ -461,19 +449,6 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestHitWindows : HitWindows
|
|
||||||
{
|
|
||||||
private static readonly DifficultyRange[] ranges =
|
|
||||||
{
|
|
||||||
new DifficultyRange(HitResult.Great, 500, 500, 500),
|
|
||||||
new DifficultyRange(HitResult.Miss, early_miss_window, early_miss_window, early_miss_window),
|
|
||||||
};
|
|
||||||
|
|
||||||
public override bool IsHitResultAllowed(HitResult result) => result == HitResult.Great || result == HitResult.Miss;
|
|
||||||
|
|
||||||
protected override DifficultyRange[] GetRanges() => ranges;
|
|
||||||
}
|
|
||||||
|
|
||||||
private partial class ScoreAccessibleReplayPlayer : ReplayPlayer
|
private partial class ScoreAccessibleReplayPlayer : ReplayPlayer
|
||||||
{
|
{
|
||||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user