mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 10:33:30 +08:00
Remove abstract ScoreProcessor class
This commit is contained in:
parent
c126cd8b01
commit
48f1dad4aa
@ -2,23 +2,21 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Scoring
|
namespace osu.Game.Rulesets.Catch.Scoring
|
||||||
{
|
{
|
||||||
public class CatchScoreProcessor : ScoreProcessor<CatchHitObject>
|
public class CatchScoreProcessor : ScoreProcessor
|
||||||
{
|
{
|
||||||
public CatchScoreProcessor(DrawableRuleset<CatchHitObject> drawableRuleset)
|
public CatchScoreProcessor(IBeatmap beatmap)
|
||||||
: base(drawableRuleset)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private float hpDrainRate;
|
private float hpDrainRate;
|
||||||
|
|
||||||
protected override void ApplyBeatmap(Beatmap<CatchHitObject> beatmap)
|
protected override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
base.ApplyBeatmap(beatmap);
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
TimeRange.Value = BeatmapDifficulty.DifficultyRange(beatmap.Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450);
|
TimeRange.Value = BeatmapDifficulty.DifficultyRange(beatmap.Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this);
|
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(Beatmap);
|
||||||
|
|
||||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
||||||
|
|
||||||
|
@ -3,13 +3,11 @@
|
|||||||
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Scoring
|
namespace osu.Game.Rulesets.Mania.Scoring
|
||||||
{
|
{
|
||||||
internal class ManiaScoreProcessor : ScoreProcessor<ManiaHitObject>
|
internal class ManiaScoreProcessor : ScoreProcessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The hit HP multiplier at OD = 0.
|
/// The hit HP multiplier at OD = 0.
|
||||||
@ -51,12 +49,12 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private double hpMultiplier = 1;
|
private double hpMultiplier = 1;
|
||||||
|
|
||||||
public ManiaScoreProcessor(DrawableRuleset<ManiaHitObject> drawableRuleset)
|
public ManiaScoreProcessor(IBeatmap beatmap)
|
||||||
: base(drawableRuleset)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ApplyBeatmap(Beatmap<ManiaHitObject> beatmap)
|
protected override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
base.ApplyBeatmap(beatmap);
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
@ -65,7 +63,7 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
|||||||
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_miss_min, hp_multiplier_miss_mid, hp_multiplier_miss_max);
|
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_miss_min, hp_multiplier_miss_mid, hp_multiplier_miss_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void SimulateAutoplay(Beatmap<ManiaHitObject> beatmap)
|
protected override void SimulateAutoplay(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
protected override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages);
|
protected override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages);
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
|
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(Beatmap);
|
||||||
|
|
||||||
public override int Variant => (int)(Beatmap.Stages.Count == 1 ? PlayfieldType.Single : PlayfieldType.Dual) + Beatmap.TotalColumns;
|
public override int Variant => (int)(Beatmap.Stages.Count == 1 ? PlayfieldType.Single : PlayfieldType.Dual) + Beatmap.TotalColumns;
|
||||||
|
|
||||||
|
@ -5,22 +5,20 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Scoring
|
namespace osu.Game.Rulesets.Osu.Scoring
|
||||||
{
|
{
|
||||||
internal class OsuScoreProcessor : ScoreProcessor<OsuHitObject>
|
internal class OsuScoreProcessor : ScoreProcessor
|
||||||
{
|
{
|
||||||
public OsuScoreProcessor(DrawableRuleset<OsuHitObject> drawableRuleset)
|
public OsuScoreProcessor(IBeatmap beatmap)
|
||||||
: base(drawableRuleset)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private float hpDrainRate;
|
private float hpDrainRate;
|
||||||
|
|
||||||
protected override void ApplyBeatmap(Beatmap<OsuHitObject> beatmap)
|
protected override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
base.ApplyBeatmap(beatmap);
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; // always show the gameplay cursor
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; // always show the gameplay cursor
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new OsuScoreProcessor(this);
|
public override ScoreProcessor CreateScoreProcessor() => new OsuScoreProcessor(Beatmap);
|
||||||
|
|
||||||
protected override Playfield CreatePlayfield() => new OsuPlayfield();
|
protected override Playfield CreatePlayfield() => new OsuPlayfield();
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Scoring
|
namespace osu.Game.Rulesets.Taiko.Scoring
|
||||||
{
|
{
|
||||||
internal class TaikoScoreProcessor : ScoreProcessor<TaikoHitObject>
|
internal class TaikoScoreProcessor : ScoreProcessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A value used for calculating <see cref="hpMultiplier"/>.
|
/// A value used for calculating <see cref="hpMultiplier"/>.
|
||||||
@ -31,16 +31,16 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private double hpMissMultiplier;
|
private double hpMissMultiplier;
|
||||||
|
|
||||||
public TaikoScoreProcessor(DrawableRuleset<TaikoHitObject> drawableRuleset)
|
public TaikoScoreProcessor(IBeatmap beatmap)
|
||||||
: base(drawableRuleset)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ApplyBeatmap(Beatmap<TaikoHitObject> beatmap)
|
protected override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
base.ApplyBeatmap(beatmap);
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
hpMultiplier = 1 / (object_count_factor * beatmap.HitObjects.FindAll(o => o is Hit).Count * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98));
|
hpMultiplier = 1 / (object_count_factor * beatmap.HitObjects.OfType<Hit>().Count() * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98));
|
||||||
|
|
||||||
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120);
|
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120);
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
new BarLineGenerator<BarLine>(Beatmap).BarLines.ForEach(bar => Playfield.Add(bar.Major ? new DrawableBarLineMajor(bar) : new DrawableBarLine(bar)));
|
new BarLineGenerator<BarLine>(Beatmap).BarLines.ForEach(bar => Playfield.Add(bar.Major ? new DrawableBarLineMajor(bar) : new DrawableBarLine(bar)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(this);
|
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(Beatmap);
|
||||||
|
|
||||||
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new TaikoPlayfieldAdjustmentContainer();
|
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new TaikoPlayfieldAdjustmentContainer();
|
||||||
|
|
||||||
|
@ -13,13 +13,16 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Scoring
|
namespace osu.Game.Rulesets.Scoring
|
||||||
{
|
{
|
||||||
public abstract class ScoreProcessor
|
public class ScoreProcessor
|
||||||
{
|
{
|
||||||
|
private const double base_portion = 0.3;
|
||||||
|
private const double combo_portion = 0.7;
|
||||||
|
private const double max_score = 1000000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked when the <see cref="ScoreProcessor"/> is in a failed state.
|
/// Invoked when the <see cref="ScoreProcessor"/> is in a failed state.
|
||||||
/// This may occur regardless of whether an <see cref="AllJudged"/> event is invoked.
|
/// This may occur regardless of whether an <see cref="AllJudged"/> event is invoked.
|
||||||
@ -67,11 +70,6 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Bindable<IReadOnlyList<Mod>> Mods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
public readonly Bindable<IReadOnlyList<Mod>> Mods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a <see cref="HitWindows"/> for this processor.
|
|
||||||
/// </summary>
|
|
||||||
public virtual HitWindows CreateHitWindows() => new HitWindows();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current rank.
|
/// The current rank.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -90,132 +88,23 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether all <see cref="Judgement"/>s have been processed.
|
/// Whether all <see cref="Judgement"/>s have been processed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool HasCompleted => false;
|
public bool HasCompleted => JudgedHits == MaxHits;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The total number of judged <see cref="HitObject"/>s at the current point in time.
|
|
||||||
/// </summary>
|
|
||||||
public int JudgedHits { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this ScoreProcessor has already triggered the failed state.
|
/// Whether this ScoreProcessor has already triggered the failed state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool HasFailed { get; private set; }
|
public bool HasFailed { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default conditions for failing.
|
/// The maximum number of hits that can be judged.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual bool DefaultFailCondition => Precision.AlmostBigger(Health.MinValue, Health.Value);
|
|
||||||
|
|
||||||
protected ScoreProcessor()
|
|
||||||
{
|
|
||||||
Combo.ValueChanged += delegate { HighestCombo.Value = Math.Max(HighestCombo.Value, Combo.Value); };
|
|
||||||
Accuracy.ValueChanged += delegate
|
|
||||||
{
|
|
||||||
Rank.Value = rankFrom(Accuracy.Value);
|
|
||||||
foreach (var mod in Mods.Value.OfType<IApplicableToScoreProcessor>())
|
|
||||||
Rank.Value = mod.AdjustRank(Rank.Value, Accuracy.Value);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScoreRank rankFrom(double acc)
|
|
||||||
{
|
|
||||||
if (acc == 1)
|
|
||||||
return ScoreRank.X;
|
|
||||||
if (acc > 0.95)
|
|
||||||
return ScoreRank.S;
|
|
||||||
if (acc > 0.9)
|
|
||||||
return ScoreRank.A;
|
|
||||||
if (acc > 0.8)
|
|
||||||
return ScoreRank.B;
|
|
||||||
if (acc > 0.7)
|
|
||||||
return ScoreRank.C;
|
|
||||||
|
|
||||||
return ScoreRank.D;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resets this ScoreProcessor to a default state.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="storeResults">Whether to store the current state of the <see cref="ScoreProcessor"/> for future use.</param>
|
|
||||||
protected virtual void Reset(bool storeResults)
|
|
||||||
{
|
|
||||||
TotalScore.Value = 0;
|
|
||||||
Accuracy.Value = 1;
|
|
||||||
Health.Value = 1;
|
|
||||||
Combo.Value = 0;
|
|
||||||
Rank.Value = ScoreRank.X;
|
|
||||||
HighestCombo.Value = 0;
|
|
||||||
|
|
||||||
JudgedHits = 0;
|
|
||||||
|
|
||||||
HasFailed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the score is in a failed state and notifies subscribers.
|
|
||||||
/// <para>
|
|
||||||
/// This can only ever notify subscribers once.
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
protected void UpdateFailed(JudgementResult result)
|
|
||||||
{
|
|
||||||
if (HasFailed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!DefaultFailCondition && FailConditions?.Invoke(this, result) != true)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (Failed?.Invoke() != false)
|
|
||||||
HasFailed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Notifies subscribers of <see cref="NewJudgement"/> that a new judgement has occurred.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="result">The judgement scoring result to notify subscribers of.</param>
|
|
||||||
protected void NotifyNewJudgement(JudgementResult result)
|
|
||||||
{
|
|
||||||
NewJudgement?.Invoke(result);
|
|
||||||
|
|
||||||
if (HasCompleted)
|
|
||||||
AllJudged?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieve a score populated with data for the current play this processor is responsible for.
|
|
||||||
/// </summary>
|
|
||||||
public virtual void PopulateScore(ScoreInfo score)
|
|
||||||
{
|
|
||||||
score.TotalScore = (long)Math.Round(TotalScore.Value);
|
|
||||||
score.Combo = Combo.Value;
|
|
||||||
score.MaxCombo = HighestCombo.Value;
|
|
||||||
score.Accuracy = Math.Round(Accuracy.Value, 4);
|
|
||||||
score.Rank = Rank.Value;
|
|
||||||
score.Date = DateTimeOffset.Now;
|
|
||||||
|
|
||||||
var hitWindows = CreateHitWindows();
|
|
||||||
|
|
||||||
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r > HitResult.None && hitWindows.IsHitResultAllowed(r)))
|
|
||||||
score.Statistics[result] = GetStatistic(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract int GetStatistic(HitResult result);
|
|
||||||
|
|
||||||
public abstract double GetStandardisedScore();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ScoreProcessor<TObject> : ScoreProcessor
|
|
||||||
where TObject : HitObject
|
|
||||||
{
|
|
||||||
private const double base_portion = 0.3;
|
|
||||||
private const double combo_portion = 0.7;
|
|
||||||
private const double max_score = 1000000;
|
|
||||||
|
|
||||||
public sealed override bool HasCompleted => JudgedHits == MaxHits;
|
|
||||||
|
|
||||||
protected int MaxHits { get; private set; }
|
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;
|
||||||
@ -225,17 +114,22 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
|
|
||||||
private double scoreMultiplier = 1;
|
private double scoreMultiplier = 1;
|
||||||
|
|
||||||
public ScoreProcessor(DrawableRuleset<TObject> drawableRuleset)
|
public ScoreProcessor(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
Debug.Assert(base_portion + combo_portion == 1.0);
|
Debug.Assert(base_portion + combo_portion == 1.0);
|
||||||
|
|
||||||
drawableRuleset.OnNewResult += applyResult;
|
Combo.ValueChanged += combo => HighestCombo.Value = Math.Max(HighestCombo.Value, combo.NewValue);
|
||||||
drawableRuleset.OnRevertResult += revertResult;
|
Accuracy.ValueChanged += accuracy =>
|
||||||
|
{
|
||||||
|
Rank.Value = rankFrom(accuracy.NewValue);
|
||||||
|
foreach (var mod in Mods.Value.OfType<IApplicableToScoreProcessor>())
|
||||||
|
Rank.Value = mod.AdjustRank(Rank.Value, accuracy.NewValue);
|
||||||
|
};
|
||||||
|
|
||||||
ApplyBeatmap(drawableRuleset.Beatmap);
|
ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
Reset(false);
|
Reset(false);
|
||||||
SimulateAutoplay(drawableRuleset.Beatmap);
|
SimulateAutoplay(beatmap);
|
||||||
Reset(true);
|
Reset(true);
|
||||||
|
|
||||||
if (maxBaseScore == 0 || maxHighestCombo == 0)
|
if (maxBaseScore == 0 || maxHighestCombo == 0)
|
||||||
@ -257,19 +151,19 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies any properties of the <see cref="Beatmap{TObject}"/> which affect scoring to this <see cref="ScoreProcessor{TObject}"/>.
|
/// Applies any properties of the <see cref="IBeatmap"/> which affect scoring to this <see cref="ScoreProcessor"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="beatmap">The <see cref="Beatmap{TObject}"/> to read properties from.</param>
|
/// <param name="beatmap">The <see cref="IBeatmap"/> to read properties from.</param>
|
||||||
protected virtual void ApplyBeatmap(Beatmap<TObject> beatmap)
|
protected virtual void ApplyBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Simulates an autoplay of the <see cref="Beatmap{TObject}"/> to determine scoring values.
|
/// Simulates an autoplay of the <see cref="IBeatmap"/> to determine scoring values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>This provided temporarily. DO NOT USE.</remarks>
|
/// <remarks>This provided temporarily. DO NOT USE.</remarks>
|
||||||
/// <param name="beatmap">The <see cref="Beatmap{TObject}"/> to simulate.</param>
|
/// <param name="beatmap">The <see cref="IBeatmap"/> to simulate.</param>
|
||||||
protected virtual void SimulateAutoplay(Beatmap<TObject> beatmap)
|
protected virtual void SimulateAutoplay(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
foreach (var obj in beatmap.HitObjects)
|
foreach (var obj in beatmap.HitObjects)
|
||||||
simulate(obj);
|
simulate(obj);
|
||||||
@ -289,7 +183,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
|
|
||||||
result.Type = judgement.MaxResult;
|
result.Type = judgement.MaxResult;
|
||||||
|
|
||||||
applyResult(result);
|
ApplyResult(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,22 +191,26 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
||||||
private void applyResult(JudgementResult result)
|
public void ApplyResult(JudgementResult result)
|
||||||
{
|
{
|
||||||
ApplyResult(result);
|
ApplyResultInternal(result);
|
||||||
updateScore();
|
|
||||||
|
|
||||||
UpdateFailed(result);
|
updateScore();
|
||||||
NotifyNewJudgement(result);
|
updateFailed(result);
|
||||||
|
|
||||||
|
NewJudgement?.Invoke(result);
|
||||||
|
|
||||||
|
if (HasCompleted)
|
||||||
|
AllJudged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/>.
|
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="result">The judgement scoring result.</param>
|
/// <param name="result">The judgement scoring result.</param>
|
||||||
private void revertResult(JudgementResult result)
|
public void RevertResult(JudgementResult result)
|
||||||
{
|
{
|
||||||
RevertResult(result);
|
RevertResultInternal(result);
|
||||||
updateScore();
|
updateScore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,10 +220,10 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Any changes applied via this method can be reverted via <see cref="RevertResult"/>.
|
/// Any changes applied via this method can be reverted via <see cref="RevertResultInternal"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
||||||
protected virtual void ApplyResult(JudgementResult result)
|
protected virtual void ApplyResultInternal(JudgementResult result)
|
||||||
{
|
{
|
||||||
result.ComboAtJudgement = Combo.Value;
|
result.ComboAtJudgement = Combo.Value;
|
||||||
result.HighestComboAtJudgement = HighestCombo.Value;
|
result.HighestComboAtJudgement = HighestCombo.Value;
|
||||||
@ -372,10 +270,10 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/> via <see cref="ApplyResult"/>.
|
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/> via <see cref="ApplyResultInternal"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="result">The judgement scoring result.</param>
|
/// <param name="result">The judgement scoring result.</param>
|
||||||
protected virtual void RevertResult(JudgementResult result)
|
protected virtual void RevertResultInternal(JudgementResult result)
|
||||||
{
|
{
|
||||||
Combo.Value = result.ComboAtJudgement;
|
Combo.Value = result.ComboAtJudgement;
|
||||||
HighestCombo.Value = result.HighestComboAtJudgement;
|
HighestCombo.Value = result.HighestComboAtJudgement;
|
||||||
@ -432,11 +330,49 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetStatistic(HitResult result) => scoreResultCounts.GetOrDefault(result);
|
/// <summary>
|
||||||
|
/// Checks if the score is in a failed state and notifies subscribers.
|
||||||
|
/// <para>
|
||||||
|
/// This can only ever notify subscribers once.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
private void updateFailed(JudgementResult result)
|
||||||
|
{
|
||||||
|
if (HasFailed)
|
||||||
|
return;
|
||||||
|
|
||||||
public override double GetStandardisedScore() => getScore(ScoringMode.Standardised);
|
if (!DefaultFailCondition && FailConditions?.Invoke(this, result) != true)
|
||||||
|
return;
|
||||||
|
|
||||||
protected override void Reset(bool storeResults)
|
if (Failed?.Invoke() != false)
|
||||||
|
HasFailed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScoreRank rankFrom(double acc)
|
||||||
|
{
|
||||||
|
if (acc == 1)
|
||||||
|
return ScoreRank.X;
|
||||||
|
if (acc > 0.95)
|
||||||
|
return ScoreRank.S;
|
||||||
|
if (acc > 0.9)
|
||||||
|
return ScoreRank.A;
|
||||||
|
if (acc > 0.8)
|
||||||
|
return ScoreRank.B;
|
||||||
|
if (acc > 0.7)
|
||||||
|
return ScoreRank.C;
|
||||||
|
|
||||||
|
return ScoreRank.D;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetStatistic(HitResult result) => scoreResultCounts.GetOrDefault(result);
|
||||||
|
|
||||||
|
public double GetStandardisedScore() => getScore(ScoringMode.Standardised);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets this ScoreProcessor to a default state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="storeResults">Whether to store the current state of the <see cref="ScoreProcessor"/> for future use.</param>
|
||||||
|
protected virtual void Reset(bool storeResults)
|
||||||
{
|
{
|
||||||
scoreResultCounts.Clear();
|
scoreResultCounts.Clear();
|
||||||
|
|
||||||
@ -447,13 +383,49 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
maxBaseScore = baseScore;
|
maxBaseScore = baseScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Reset(storeResults);
|
JudgedHits = 0;
|
||||||
|
|
||||||
baseScore = 0;
|
baseScore = 0;
|
||||||
rollingMaxBaseScore = 0;
|
rollingMaxBaseScore = 0;
|
||||||
bonusScore = 0;
|
bonusScore = 0;
|
||||||
|
|
||||||
|
TotalScore.Value = 0;
|
||||||
|
Accuracy.Value = 1;
|
||||||
|
Health.Value = 1;
|
||||||
|
Combo.Value = 0;
|
||||||
|
Rank.Value = ScoreRank.X;
|
||||||
|
HighestCombo.Value = 0;
|
||||||
|
|
||||||
|
HasFailed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve a score populated with data for the current play this processor is responsible for.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void PopulateScore(ScoreInfo score)
|
||||||
|
{
|
||||||
|
score.TotalScore = (long)Math.Round(TotalScore.Value);
|
||||||
|
score.Combo = Combo.Value;
|
||||||
|
score.MaxCombo = HighestCombo.Value;
|
||||||
|
score.Accuracy = Math.Round(Accuracy.Value, 4);
|
||||||
|
score.Rank = Rank.Value;
|
||||||
|
score.Date = DateTimeOffset.Now;
|
||||||
|
|
||||||
|
var hitWindows = CreateHitWindows();
|
||||||
|
|
||||||
|
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r > HitResult.None && hitWindows.IsHitResultAllowed(r)))
|
||||||
|
score.Statistics[result] = GetStatistic(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default conditions for failing.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool DefaultFailCondition => Precision.AlmostBigger(Health.MinValue, Health.Value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a <see cref="HitWindows"/> for this processor.
|
||||||
|
/// </summary>
|
||||||
|
public virtual HitWindows CreateHitWindows() => new HitWindows();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the <see cref="JudgementResult"/> that represents the scoring result for a <see cref="HitObject"/>.
|
/// Creates the <see cref="JudgementResult"/> that represents the scoring result for a <see cref="HitObject"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -45,6 +45,10 @@ namespace osu.Game.Rulesets.UI
|
|||||||
public abstract class DrawableRuleset<TObject> : DrawableRuleset, IProvideCursor, ICanAttachKeyCounter
|
public abstract class DrawableRuleset<TObject> : DrawableRuleset, IProvideCursor, ICanAttachKeyCounter
|
||||||
where TObject : HitObject
|
where TObject : HitObject
|
||||||
{
|
{
|
||||||
|
public override event Action<JudgementResult> OnNewResult;
|
||||||
|
|
||||||
|
public override event Action<JudgementResult> OnRevertResult;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The selected variant.
|
/// The selected variant.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -91,16 +95,6 @@ namespace osu.Game.Rulesets.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked when a <see cref="JudgementResult"/> has been applied by a <see cref="DrawableHitObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
public event Action<JudgementResult> OnNewResult;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked when a <see cref="JudgementResult"/> is being reverted by a <see cref="DrawableHitObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
public event Action<JudgementResult> OnRevertResult;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The beatmap.
|
/// The beatmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -309,7 +303,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// <returns>The Playfield.</returns>
|
/// <returns>The Playfield.</returns>
|
||||||
protected abstract Playfield CreatePlayfield();
|
protected abstract Playfield CreatePlayfield();
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new ScoreProcessor<TObject>(this);
|
public override ScoreProcessor CreateScoreProcessor() => new ScoreProcessor(Beatmap);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies the active mods to this DrawableRuleset.
|
/// Applies the active mods to this DrawableRuleset.
|
||||||
@ -366,6 +360,16 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class DrawableRuleset : CompositeDrawable
|
public abstract class DrawableRuleset : CompositeDrawable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a <see cref="JudgementResult"/> has been applied by a <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
public abstract event Action<JudgementResult> OnNewResult;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a <see cref="JudgementResult"/> is being reverted by a <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
public abstract event Action<JudgementResult> OnRevertResult;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether a replay is currently loaded.
|
/// Whether a replay is currently loaded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -140,6 +140,9 @@ namespace osu.Game.Screens.Play
|
|||||||
// bind clock into components that require it
|
// bind clock into components that require it
|
||||||
DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused);
|
DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused);
|
||||||
|
|
||||||
|
DrawableRuleset.OnNewResult += ScoreProcessor.ApplyResult;
|
||||||
|
DrawableRuleset.OnRevertResult += ScoreProcessor.RevertResult;
|
||||||
|
|
||||||
// Bind ScoreProcessor to ourselves
|
// Bind ScoreProcessor to ourselves
|
||||||
ScoreProcessor.AllJudged += onCompletion;
|
ScoreProcessor.AllJudged += onCompletion;
|
||||||
ScoreProcessor.Failed += onFail;
|
ScoreProcessor.Failed += onFail;
|
||||||
|
Loading…
Reference in New Issue
Block a user