Update judgement processors with new hit results

This commit is contained in:
smoogipoo
2020-09-29 15:25:31 +09:00
parent a1394c1830
commit 31fae045fa
9 changed files with 47 additions and 73 deletions

View File

@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Catch.Scoring
{ {
public class CatchScoreProcessor : ScoreProcessor public class CatchScoreProcessor : ScoreProcessor
{ {
public override HitWindows CreateHitWindows() => new CatchHitWindows();
} }
} }

View File

@ -10,7 +10,5 @@ namespace osu.Game.Rulesets.Mania.Scoring
protected override double DefaultAccuracyPortion => 0.95; protected override double DefaultAccuracyPortion => 0.95;
protected override double DefaultComboPortion => 0.05; protected override double DefaultComboPortion => 0.05;
public override HitWindows CreateHitWindows() => new ManiaHitWindows();
} }
} }

View File

@ -25,7 +25,5 @@ namespace osu.Game.Rulesets.Osu.Scoring
return new OsuJudgementResult(hitObject, judgement); return new OsuJudgementResult(hitObject, judgement);
} }
} }
public override HitWindows CreateHitWindows() => new OsuHitWindows();
} }
} }

View File

@ -10,7 +10,5 @@ namespace osu.Game.Rulesets.Taiko.Scoring
protected override double DefaultAccuracyPortion => 0.75; protected override double DefaultAccuracyPortion => 0.75;
protected override double DefaultComboPortion => 0.25; protected override double DefaultComboPortion => 0.25;
public override HitWindows CreateHitWindows() => new TaikoHitWindows();
} }
} }

View File

@ -167,7 +167,7 @@ namespace osu.Game.Tests.Gameplay
beatmap.HitObjects.Add(new JudgeableHitObject { StartTime = 0 }); beatmap.HitObjects.Add(new JudgeableHitObject { StartTime = 0 });
for (double time = 0; time < 5000; time += 100) for (double time = 0; time < 5000; time += 100)
beatmap.HitObjects.Add(new JudgeableHitObject(false) { StartTime = time }); beatmap.HitObjects.Add(new JudgeableHitObject(HitResult.LargeBonus) { StartTime = time });
beatmap.HitObjects.Add(new JudgeableHitObject { StartTime = 5000 }); beatmap.HitObjects.Add(new JudgeableHitObject { StartTime = 5000 });
createProcessor(beatmap); createProcessor(beatmap);
@ -215,23 +215,23 @@ namespace osu.Game.Tests.Gameplay
private class JudgeableHitObject : HitObject private class JudgeableHitObject : HitObject
{ {
private readonly bool affectsCombo; private readonly HitResult maxResult;
public JudgeableHitObject(bool affectsCombo = true) public JudgeableHitObject(HitResult maxResult = HitResult.Perfect)
{ {
this.affectsCombo = affectsCombo; this.maxResult = maxResult;
} }
public override Judgement CreateJudgement() => new TestJudgement(affectsCombo); public override Judgement CreateJudgement() => new TestJudgement(maxResult);
protected override HitWindows CreateHitWindows() => new HitWindows(); protected override HitWindows CreateHitWindows() => new HitWindows();
private class TestJudgement : Judgement private class TestJudgement : Judgement
{ {
public override bool AffectsCombo { get; } public override HitResult MaxResult { get; }
public TestJudgement(bool affectsCombo) public TestJudgement(HitResult maxResult)
{ {
AffectsCombo = affectsCombo; MaxResult = maxResult;
} }
} }
} }

View File

@ -17,13 +17,13 @@ namespace osu.Game.Tests.Gameplay
[Test] [Test]
public void TestNoScoreIncreaseFromMiss() public void TestNoScoreIncreaseFromMiss()
{ {
var beatmap = new Beatmap<TestHitObject> { HitObjects = { new TestHitObject() } }; var beatmap = new Beatmap<HitObject> { HitObjects = { new HitObject() } };
var scoreProcessor = new ScoreProcessor(); var scoreProcessor = new ScoreProcessor();
scoreProcessor.ApplyBeatmap(beatmap); scoreProcessor.ApplyBeatmap(beatmap);
// Apply a miss judgement // Apply a miss judgement
scoreProcessor.ApplyResult(new JudgementResult(new TestHitObject(), new TestJudgement()) { Type = HitResult.Miss }); scoreProcessor.ApplyResult(new JudgementResult(new HitObject(), new TestJudgement()) { Type = HitResult.Miss });
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(0.0)); Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(0.0));
} }
@ -31,37 +31,25 @@ namespace osu.Game.Tests.Gameplay
[Test] [Test]
public void TestOnlyBonusScore() public void TestOnlyBonusScore()
{ {
var beatmap = new Beatmap<TestBonusHitObject> { HitObjects = { new TestBonusHitObject() } }; var beatmap = new Beatmap<HitObject> { HitObjects = { new HitObject() } };
var scoreProcessor = new ScoreProcessor(); var scoreProcessor = new ScoreProcessor();
scoreProcessor.ApplyBeatmap(beatmap); scoreProcessor.ApplyBeatmap(beatmap);
// Apply a judgement // Apply a judgement
scoreProcessor.ApplyResult(new JudgementResult(new TestBonusHitObject(), new TestBonusJudgement()) { Type = HitResult.Perfect }); scoreProcessor.ApplyResult(new JudgementResult(new HitObject(), new TestJudgement(HitResult.LargeBonus)) { Type = HitResult.LargeBonus });
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(100)); Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(Judgement.LARGE_BONUS_SCORE));
}
private class TestHitObject : HitObject
{
public override Judgement CreateJudgement() => new TestJudgement();
} }
private class TestJudgement : Judgement private class TestJudgement : Judgement
{ {
protected override int NumericResultFor(HitResult result) => 100; public override HitResult MaxResult { get; }
}
private class TestBonusHitObject : HitObject public TestJudgement(HitResult maxResult = HitResult.Perfect)
{ {
public override Judgement CreateJudgement() => new TestBonusJudgement(); MaxResult = maxResult;
} }
private class TestBonusJudgement : Judgement
{
public override bool AffectsCombo => false;
protected override int NumericResultFor(HitResult result) => 100;
} }
} }
} }

View File

@ -115,7 +115,7 @@ namespace osu.Game.Rulesets.Scoring
{ {
base.ApplyResultInternal(result); base.ApplyResultInternal(result);
if (!result.Judgement.IsBonus) if (!result.Type.IsBonus())
healthIncreases.Add((result.HitObject.GetEndTime() + result.TimeOffset, GetHealthIncreaseFor(result))); healthIncreases.Add((result.HitObject.GetEndTime() + result.TimeOffset, GetHealthIncreaseFor(result)));
} }

View File

@ -71,7 +71,6 @@ namespace osu.Game.Rulesets.Scoring
private double maxBaseScore; private double maxBaseScore;
private double rollingMaxBaseScore; private double rollingMaxBaseScore;
private double baseScore; private double baseScore;
private double bonusScore;
private readonly List<HitEvent> hitEvents = new List<HitEvent>(); private readonly List<HitEvent> hitEvents = new List<HitEvent>();
private HitObject lastHitObject; private HitObject lastHitObject;
@ -116,14 +115,15 @@ namespace osu.Game.Rulesets.Scoring
if (result.FailedAtJudgement) if (result.FailedAtJudgement)
return; return;
if (result.Judgement.AffectsCombo) if (!result.Type.IsScorable())
return;
if (result.Type.AffectsCombo())
{ {
switch (result.Type) switch (result.Type)
{ {
case HitResult.None:
break;
case HitResult.Miss: case HitResult.Miss:
case HitResult.LargeTickMiss:
Combo.Value = 0; Combo.Value = 0;
break; break;
@ -133,22 +133,16 @@ namespace osu.Game.Rulesets.Scoring
} }
} }
double scoreIncrease = result.Type == HitResult.Miss ? 0 : result.Judgement.NumericResultFor(result); double scoreIncrease = result.Type.IsHit() ? result.Judgement.NumericResultFor(result) : 0;
if (result.Judgement.IsBonus) if (!result.Type.IsBonus())
{ {
if (result.IsHit)
bonusScore += scoreIncrease;
}
else
{
if (result.HasResult)
scoreResultCounts[result.Type] = scoreResultCounts.GetOrDefault(result.Type) + 1;
baseScore += scoreIncrease; baseScore += scoreIncrease;
rollingMaxBaseScore += result.Judgement.MaxNumericResult; rollingMaxBaseScore += result.Judgement.MaxNumericResult;
} }
scoreResultCounts[result.Type] = scoreResultCounts.GetOrDefault(result.Type) + 1;
hitEvents.Add(CreateHitEvent(result)); hitEvents.Add(CreateHitEvent(result));
lastHitObject = result.HitObject; lastHitObject = result.HitObject;
@ -171,22 +165,19 @@ namespace osu.Game.Rulesets.Scoring
if (result.FailedAtJudgement) if (result.FailedAtJudgement)
return; return;
double scoreIncrease = result.Type == HitResult.Miss ? 0 : result.Judgement.NumericResultFor(result); if (!result.Type.IsScorable())
return;
if (result.Judgement.IsBonus) double scoreIncrease = result.Type.IsHit() ? result.Judgement.NumericResultFor(result) : 0;
{
if (result.IsHit)
bonusScore -= scoreIncrease;
}
else
{
if (result.HasResult)
scoreResultCounts[result.Type] = scoreResultCounts.GetOrDefault(result.Type) - 1;
if (!result.Type.IsBonus())
{
baseScore -= scoreIncrease; baseScore -= scoreIncrease;
rollingMaxBaseScore -= result.Judgement.MaxNumericResult; rollingMaxBaseScore -= result.Judgement.MaxNumericResult;
} }
scoreResultCounts[result.Type] = scoreResultCounts.GetOrDefault(result.Type) - 1;
Debug.Assert(hitEvents.Count > 0); Debug.Assert(hitEvents.Count > 0);
lastHitObject = hitEvents[^1].LastHitObject; lastHitObject = hitEvents[^1].LastHitObject;
hitEvents.RemoveAt(hitEvents.Count - 1); hitEvents.RemoveAt(hitEvents.Count - 1);
@ -207,7 +198,7 @@ namespace osu.Game.Rulesets.Scoring
return GetScore(mode, maxHighestCombo, return GetScore(mode, maxHighestCombo,
maxBaseScore > 0 ? baseScore / maxBaseScore : 0, maxBaseScore > 0 ? baseScore / maxBaseScore : 0,
maxHighestCombo > 0 ? (double)HighestCombo.Value / maxHighestCombo : 0, maxHighestCombo > 0 ? (double)HighestCombo.Value / maxHighestCombo : 0,
bonusScore); scoreResultCounts);
} }
/// <summary> /// <summary>
@ -217,9 +208,9 @@ namespace osu.Game.Rulesets.Scoring
/// <param name="maxCombo">The maximum combo achievable in the beatmap.</param> /// <param name="maxCombo">The maximum combo achievable in the beatmap.</param>
/// <param name="accuracyRatio">The accuracy percentage achieved by the player.</param> /// <param name="accuracyRatio">The accuracy percentage achieved by the player.</param>
/// <param name="comboRatio">The proportion of <paramref name="maxCombo"/> achieved by the player.</param> /// <param name="comboRatio">The proportion of <paramref name="maxCombo"/> achieved by the player.</param>
/// <param name="bonusScore">Any bonus score to be added.</param> /// <param name="statistics">Any statistics to be factored in.</param>
/// <returns>The total score.</returns> /// <returns>The total score.</returns>
public double GetScore(ScoringMode mode, int maxCombo, double accuracyRatio, double comboRatio, double bonusScore) public double GetScore(ScoringMode mode, int maxCombo, double accuracyRatio, double comboRatio, Dictionary<HitResult, int> statistics)
{ {
switch (mode) switch (mode)
{ {
@ -228,14 +219,18 @@ namespace osu.Game.Rulesets.Scoring
double accuracyScore = accuracyPortion * accuracyRatio; double accuracyScore = accuracyPortion * accuracyRatio;
double comboScore = comboPortion * comboRatio; double comboScore = comboPortion * comboRatio;
return (max_score * (accuracyScore + comboScore) + bonusScore) * scoreMultiplier; return (max_score * (accuracyScore + comboScore) + getBonusScore(statistics)) * scoreMultiplier;
case ScoringMode.Classic: case ScoringMode.Classic:
// should emulate osu-stable's scoring as closely as we can (https://osu.ppy.sh/help/wiki/Score/ScoreV1) // should emulate osu-stable's scoring as closely as we can (https://osu.ppy.sh/help/wiki/Score/ScoreV1)
return bonusScore + (accuracyRatio * maxCombo * 300) * (1 + Math.Max(0, (comboRatio * maxCombo) - 1) * scoreMultiplier / 25); return getBonusScore(statistics) + (accuracyRatio * maxCombo * 300) * (1 + Math.Max(0, (comboRatio * maxCombo) - 1) * scoreMultiplier / 25);
} }
} }
private double getBonusScore(Dictionary<HitResult, int> statistics)
=> statistics.GetOrDefault(HitResult.SmallBonus) * Judgement.SMALL_BONUS_SCORE
+ statistics.GetOrDefault(HitResult.LargeBonus) * Judgement.LARGE_BONUS_SCORE;
private ScoreRank rankFrom(double acc) private ScoreRank rankFrom(double acc)
{ {
if (acc == 1) if (acc == 1)
@ -282,7 +277,6 @@ namespace osu.Game.Rulesets.Scoring
baseScore = 0; baseScore = 0;
rollingMaxBaseScore = 0; rollingMaxBaseScore = 0;
bonusScore = 0;
TotalScore.Value = 0; TotalScore.Value = 0;
Accuracy.Value = 1; Accuracy.Value = 1;
@ -309,9 +303,7 @@ namespace osu.Game.Rulesets.Scoring
score.Rank = Rank.Value; score.Rank = Rank.Value;
score.Date = DateTimeOffset.Now; score.Date = DateTimeOffset.Now;
var hitWindows = CreateHitWindows(); foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r.IsScorable()))
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r > HitResult.None && hitWindows.IsHitResultAllowed(r)))
score.Statistics[result] = GetStatistic(result); score.Statistics[result] = GetStatistic(result);
score.HitEvents = hitEvents; score.HitEvents = hitEvents;
@ -320,6 +312,7 @@ namespace osu.Game.Rulesets.Scoring
/// <summary> /// <summary>
/// Create a <see cref="HitWindows"/> for this processor. /// Create a <see cref="HitWindows"/> for this processor.
/// </summary> /// </summary>
[Obsolete("Method is now unused.")] // Can be removed 20210328
public virtual HitWindows CreateHitWindows() => new HitWindows(); public virtual HitWindows CreateHitWindows() => new HitWindows();
} }

View File

@ -181,7 +181,7 @@ namespace osu.Game.Scoring
scoreProcessor.Mods.Value = score.Mods; scoreProcessor.Mods.Value = score.Mods;
Value = (long)Math.Round(scoreProcessor.GetScore(ScoringMode.Value, beatmapMaxCombo, score.Accuracy, (double)score.MaxCombo / beatmapMaxCombo, 0)); Value = (long)Math.Round(scoreProcessor.GetScore(ScoringMode.Value, beatmapMaxCombo, score.Accuracy, (double)score.MaxCombo / beatmapMaxCombo, score.Statistics));
} }
} }