mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 17:23:22 +08:00
Encapsulate common logic of ScoreProcessor
This commit is contained in:
parent
ed856851a1
commit
1da8cc8690
126
osu.Game/Rulesets/Scoring/JudgementProcessor.cs
Normal file
126
osu.Game/Rulesets/Scoring/JudgementProcessor.cs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Framework.Extensions.TypeExtensions;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Scoring
|
||||||
|
{
|
||||||
|
public abstract class JudgementProcessor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum number of hits that can be judged.
|
||||||
|
/// </summary>
|
||||||
|
protected int MaxHits { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The total number of judged <see cref="HitObject"/>s at the current point in time.
|
||||||
|
/// </summary>
|
||||||
|
public int JudgedHits { get; private set; }
|
||||||
|
|
||||||
|
protected JudgementProcessor(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
|
Reset(false);
|
||||||
|
SimulateAutoplay(beatmap);
|
||||||
|
Reset(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies any properties of the <see cref="IBeatmap"/> which affect scoring to this <see cref="ScoreProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The <see cref="IBeatmap"/> to read properties from.</param>
|
||||||
|
protected virtual void ApplyBeatmap(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
||||||
|
public void ApplyResult(JudgementResult result)
|
||||||
|
{
|
||||||
|
JudgedHits++;
|
||||||
|
|
||||||
|
ApplyResultInternal(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">The judgement scoring result.</param>
|
||||||
|
public void RevertResult(JudgementResult result)
|
||||||
|
{
|
||||||
|
JudgedHits--;
|
||||||
|
|
||||||
|
RevertResultInternal(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Any changes applied via this method can be reverted via <see cref="RevertResultInternal"/>.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
||||||
|
protected abstract void ApplyResultInternal(JudgementResult result);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/> via <see cref="ApplyResultInternal"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">The judgement scoring result.</param>
|
||||||
|
protected abstract void RevertResultInternal(JudgementResult result);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets this <see cref="JudgementProcessor"/> to a default state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="storeResults">Whether to store the current state of the <see cref="JudgementProcessor"/> for future use.</param>
|
||||||
|
protected virtual void Reset(bool storeResults)
|
||||||
|
{
|
||||||
|
if (storeResults)
|
||||||
|
MaxHits = JudgedHits;
|
||||||
|
|
||||||
|
JudgedHits = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the <see cref="JudgementResult"/> that represents the scoring result for a <see cref="HitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObject">The <see cref="HitObject"/> which was judged.</param>
|
||||||
|
/// <param name="judgement">The <see cref="Judgement"/> that provides the scoring information.</param>
|
||||||
|
protected virtual JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new JudgementResult(hitObject, judgement);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Simulates an autoplay of the <see cref="IBeatmap"/> to determine scoring values.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This provided temporarily. DO NOT USE.</remarks>
|
||||||
|
/// <param name="beatmap">The <see cref="IBeatmap"/> to simulate.</param>
|
||||||
|
protected virtual void SimulateAutoplay(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
foreach (var obj in beatmap.HitObjects)
|
||||||
|
simulate(obj);
|
||||||
|
|
||||||
|
void simulate(HitObject obj)
|
||||||
|
{
|
||||||
|
foreach (var nested in obj.NestedHitObjects)
|
||||||
|
simulate(nested);
|
||||||
|
|
||||||
|
var judgement = obj.CreateJudgement();
|
||||||
|
if (judgement == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var result = CreateResult(obj, judgement);
|
||||||
|
if (result == null)
|
||||||
|
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
||||||
|
|
||||||
|
result.Type = judgement.MaxResult;
|
||||||
|
|
||||||
|
ApplyResult(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,6 @@ using System.Diagnostics;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Extensions.TypeExtensions;
|
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
@ -17,7 +16,7 @@ using osu.Game.Scoring;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Scoring
|
namespace osu.Game.Rulesets.Scoring
|
||||||
{
|
{
|
||||||
public class ScoreProcessor
|
public class ScoreProcessor : JudgementProcessor
|
||||||
{
|
{
|
||||||
private const double base_portion = 0.3;
|
private const double base_portion = 0.3;
|
||||||
private const double combo_portion = 0.7;
|
private const double combo_portion = 0.7;
|
||||||
@ -95,16 +94,6 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HasFailed { get; private set; }
|
public bool HasFailed { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The maximum number of hits that can be judged.
|
|
||||||
/// </summary>
|
|
||||||
protected int MaxHits { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The total number of judged <see cref="HitObject"/>s at the current point in time.
|
|
||||||
/// </summary>
|
|
||||||
public int JudgedHits { get; private set; }
|
|
||||||
|
|
||||||
private double maxHighestCombo;
|
private double maxHighestCombo;
|
||||||
|
|
||||||
private double maxBaseScore;
|
private double maxBaseScore;
|
||||||
@ -115,8 +104,14 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
private double scoreMultiplier = 1;
|
private double scoreMultiplier = 1;
|
||||||
|
|
||||||
public ScoreProcessor(IBeatmap beatmap)
|
public ScoreProcessor(IBeatmap beatmap)
|
||||||
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
Debug.Assert(base_portion + combo_portion == 1.0);
|
Debug.Assert(base_portion + combo_portion == 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
Combo.ValueChanged += combo => HighestCombo.Value = Math.Max(HighestCombo.Value, combo.NewValue);
|
Combo.ValueChanged += combo => HighestCombo.Value = Math.Max(HighestCombo.Value, combo.NewValue);
|
||||||
Accuracy.ValueChanged += accuracy =>
|
Accuracy.ValueChanged += accuracy =>
|
||||||
@ -126,12 +121,6 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
Rank.Value = mod.AdjustRank(Rank.Value, accuracy.NewValue);
|
Rank.Value = mod.AdjustRank(Rank.Value, accuracy.NewValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
ApplyBeatmap(beatmap);
|
|
||||||
|
|
||||||
Reset(false);
|
|
||||||
SimulateAutoplay(beatmap);
|
|
||||||
Reset(true);
|
|
||||||
|
|
||||||
if (maxBaseScore == 0 || maxHighestCombo == 0)
|
if (maxBaseScore == 0 || maxHighestCombo == 0)
|
||||||
{
|
{
|
||||||
Mode.Value = ScoringMode.Classic;
|
Mode.Value = ScoringMode.Classic;
|
||||||
@ -150,80 +139,9 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Applies any properties of the <see cref="IBeatmap"/> which affect scoring to this <see cref="ScoreProcessor"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="beatmap">The <see cref="IBeatmap"/> to read properties from.</param>
|
|
||||||
protected virtual void ApplyBeatmap(IBeatmap beatmap)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Simulates an autoplay of the <see cref="IBeatmap"/> to determine scoring values.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>This provided temporarily. DO NOT USE.</remarks>
|
|
||||||
/// <param name="beatmap">The <see cref="IBeatmap"/> to simulate.</param>
|
|
||||||
protected virtual void SimulateAutoplay(IBeatmap beatmap)
|
|
||||||
{
|
|
||||||
foreach (var obj in beatmap.HitObjects)
|
|
||||||
simulate(obj);
|
|
||||||
|
|
||||||
void simulate(HitObject obj)
|
|
||||||
{
|
|
||||||
foreach (var nested in obj.NestedHitObjects)
|
|
||||||
simulate(nested);
|
|
||||||
|
|
||||||
var judgement = obj.CreateJudgement();
|
|
||||||
if (judgement == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var result = CreateResult(obj, judgement);
|
|
||||||
if (result == null)
|
|
||||||
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
|
||||||
|
|
||||||
result.Type = judgement.MaxResult;
|
|
||||||
|
|
||||||
ApplyResult(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
|
||||||
public void ApplyResult(JudgementResult result)
|
|
||||||
{
|
|
||||||
ApplyResultInternal(result);
|
|
||||||
|
|
||||||
updateScore();
|
|
||||||
updateFailed(result);
|
|
||||||
|
|
||||||
NewJudgement?.Invoke(result);
|
|
||||||
|
|
||||||
if (HasCompleted)
|
|
||||||
AllJudged?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="result">The judgement scoring result.</param>
|
|
||||||
public void RevertResult(JudgementResult result)
|
|
||||||
{
|
|
||||||
RevertResultInternal(result);
|
|
||||||
updateScore();
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Dictionary<HitResult, int> scoreResultCounts = new Dictionary<HitResult, int>();
|
private readonly Dictionary<HitResult, int> scoreResultCounts = new Dictionary<HitResult, int>();
|
||||||
|
|
||||||
/// <summary>
|
protected sealed override void ApplyResultInternal(JudgementResult result)
|
||||||
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Any changes applied via this method can be reverted via <see cref="RevertResultInternal"/>.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
|
||||||
protected virtual void ApplyResultInternal(JudgementResult result)
|
|
||||||
{
|
{
|
||||||
result.ComboAtJudgement = Combo.Value;
|
result.ComboAtJudgement = Combo.Value;
|
||||||
result.HighestComboAtJudgement = HighestCombo.Value;
|
result.HighestComboAtJudgement = HighestCombo.Value;
|
||||||
@ -233,8 +151,6 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
if (HasFailed)
|
if (HasFailed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JudgedHits++;
|
|
||||||
|
|
||||||
if (result.Judgement.AffectsCombo)
|
if (result.Judgement.AffectsCombo)
|
||||||
{
|
{
|
||||||
switch (result.Type)
|
switch (result.Type)
|
||||||
@ -267,13 +183,17 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
}
|
}
|
||||||
|
|
||||||
Health.Value += HealthAdjustmentFactorFor(result) * result.Judgement.HealthIncreaseFor(result);
|
Health.Value += HealthAdjustmentFactorFor(result) * result.Judgement.HealthIncreaseFor(result);
|
||||||
|
|
||||||
|
updateScore();
|
||||||
|
updateFailed(result);
|
||||||
|
|
||||||
|
NewJudgement?.Invoke(result);
|
||||||
|
|
||||||
|
if (HasCompleted)
|
||||||
|
AllJudged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
protected sealed override void RevertResultInternal(JudgementResult result)
|
||||||
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/> via <see cref="ApplyResultInternal"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="result">The judgement scoring result.</param>
|
|
||||||
protected virtual void RevertResultInternal(JudgementResult result)
|
|
||||||
{
|
{
|
||||||
Combo.Value = result.ComboAtJudgement;
|
Combo.Value = result.ComboAtJudgement;
|
||||||
HighestCombo.Value = result.HighestComboAtJudgement;
|
HighestCombo.Value = result.HighestComboAtJudgement;
|
||||||
@ -284,8 +204,6 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
if (result.FailedAtJudgement)
|
if (result.FailedAtJudgement)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JudgedHits--;
|
|
||||||
|
|
||||||
if (result.Judgement.IsBonus)
|
if (result.Judgement.IsBonus)
|
||||||
{
|
{
|
||||||
if (result.IsHit)
|
if (result.IsHit)
|
||||||
@ -372,18 +290,18 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// Resets this ScoreProcessor to a default state.
|
/// Resets this ScoreProcessor to a default state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="storeResults">Whether to store the current state of the <see cref="ScoreProcessor"/> for future use.</param>
|
/// <param name="storeResults">Whether to store the current state of the <see cref="ScoreProcessor"/> for future use.</param>
|
||||||
protected virtual void Reset(bool storeResults)
|
protected override void Reset(bool storeResults)
|
||||||
{
|
{
|
||||||
|
base.Reset(storeResults);
|
||||||
|
|
||||||
scoreResultCounts.Clear();
|
scoreResultCounts.Clear();
|
||||||
|
|
||||||
if (storeResults)
|
if (storeResults)
|
||||||
{
|
{
|
||||||
MaxHits = JudgedHits;
|
|
||||||
maxHighestCombo = HighestCombo.Value;
|
maxHighestCombo = HighestCombo.Value;
|
||||||
maxBaseScore = baseScore;
|
maxBaseScore = baseScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
JudgedHits = 0;
|
|
||||||
baseScore = 0;
|
baseScore = 0;
|
||||||
rollingMaxBaseScore = 0;
|
rollingMaxBaseScore = 0;
|
||||||
bonusScore = 0;
|
bonusScore = 0;
|
||||||
@ -425,13 +343,6 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// Create a <see cref="HitWindows"/> for this processor.
|
/// Create a <see cref="HitWindows"/> for this processor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual HitWindows CreateHitWindows() => new HitWindows();
|
public virtual HitWindows CreateHitWindows() => new HitWindows();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates the <see cref="JudgementResult"/> that represents the scoring result for a <see cref="HitObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hitObject">The <see cref="HitObject"/> which was judged.</param>
|
|
||||||
/// <param name="judgement">The <see cref="Judgement"/> that provides the scoring information.</param>
|
|
||||||
protected virtual JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new JudgementResult(hitObject, judgement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ScoringMode
|
public enum ScoringMode
|
||||||
|
Loading…
Reference in New Issue
Block a user