diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 5de14ae579..65b2ef75c4 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -25,7 +25,7 @@ public class DrawableJudgement : Container private OsuColour colours; - protected readonly Judgement Judgement; + protected readonly JudgementResult Result; public readonly DrawableHitObject JudgedObject; @@ -34,11 +34,11 @@ public class DrawableJudgement : Container /// /// Creates a drawable which visualises a . /// - /// The judgement to visualise. + /// The judgement to visualise. /// The object which was judged. - public DrawableJudgement(Judgement judgement, DrawableHitObject judgedObject) + public DrawableJudgement(JudgementResult result, DrawableHitObject judgedObject) { - Judgement = judgement; + Result = result; JudgedObject = judgedObject; Size = new Vector2(judgement_size); @@ -49,11 +49,11 @@ private void load(OsuColour colours) { this.colours = colours; - Child = new SkinnableDrawable($"Play/{Judgement.Result}", _ => JudgementText = new OsuSpriteText + Child = new SkinnableDrawable($"Play/{Result.Type}", _ => JudgementText = new OsuSpriteText { - Text = Judgement.Result.GetDescription().ToUpperInvariant(), + Text = Result.Type.GetDescription().ToUpperInvariant(), Font = @"Venera", - Colour = judgementColour(Judgement.Result), + Colour = judgementColour(Result.Type), Scale = new Vector2(0.85f, 1), TextSize = 12 }, restrictSize: false); @@ -65,7 +65,7 @@ protected override void LoadComplete() this.FadeInFromZero(100, Easing.OutQuint); - switch (Judgement.Result) + switch (Result.Type) { case HitResult.None: break; diff --git a/osu.Game/Rulesets/Judgements/Judgement.cs b/osu.Game/Rulesets/Judgements/Judgement.cs index 63378e57cc..5fddbe0b0a 100644 --- a/osu.Game/Rulesets/Judgements/Judgement.cs +++ b/osu.Game/Rulesets/Judgements/Judgement.cs @@ -1,74 +1,44 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Judgements { public class Judgement { - /// - /// Whether this judgement is the result of a hit or a miss. - /// - public HitResult Result; - /// /// The maximum that can be achieved. /// public virtual HitResult MaxResult => HitResult.Perfect; /// - /// The combo prior to this judgement occurring. - /// - public int ComboAtJudgement; - - /// - /// The highest combo achieved prior to this judgement occurring. - /// - public int HighestComboAtJudgement; - - /// - /// Whether this has a result. - /// - public bool HasResult => Result > HitResult.None; - - /// - /// Whether a successful hit occurred. - /// - public bool IsHit => Result > HitResult.Miss; - - /// - /// The offset from a perfect hit at which this judgement occurred. - /// Populated when added via . - /// - public double TimeOffset { get; set; } - - /// - /// Whether the should affect the current combo. + /// Whether this should affect the current combo. /// public virtual bool AffectsCombo => true; /// - /// Whether the should be counted as base (combo) or bonus score. + /// Whether this should be counted as base (combo) or bonus score. /// public virtual bool IsBonus => !AffectsCombo; /// - /// The numeric representation for the result achieved. - /// - public int NumericResult => NumericResultFor(Result); - - /// - /// The numeric representation for the maximum achievable result. + /// The numeric score representation for the maximum achievable result. /// public int MaxNumericResult => NumericResultFor(MaxResult); /// - /// Convert a to a numeric score representation. + /// Retrieves the numeric score representation of a . /// - /// The value to convert. - /// The number. + /// The to find the numeric score representation for. + /// The numeric score representation of . protected virtual int NumericResultFor(HitResult result) => result > HitResult.Miss ? 1 : 0; + + /// + /// Retrieves the numeric score representation of a . + /// + /// The to find the numeric score representation for. + /// The numeric score representation of . + public int NumericResultFor(JudgementResult result) => NumericResultFor(result.Type); } } diff --git a/osu.Game/Rulesets/Judgements/JudgementResult.cs b/osu.Game/Rulesets/Judgements/JudgementResult.cs new file mode 100644 index 0000000000..6971fcf593 --- /dev/null +++ b/osu.Game/Rulesets/Judgements/JudgementResult.cs @@ -0,0 +1,51 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Rulesets.Judgements +{ + public class JudgementResult + { + /// + /// Whether this is the result of a hit or a miss. + /// + public HitResult Type; + + /// + /// The which this applies for. + /// + public readonly Judgement Judgement; + + /// + /// The offset from a perfect hit at which this occurred. + /// Populated when added via . + /// + public double TimeOffset { get; internal set; } + + /// + /// The combo prior to this judgement occurring. + /// + public int ComboAtJudgement { get; internal set; } + + /// + /// The highest combo achieved prior to this judgement occurring. + /// + public int HighestComboAtJudgement { get; internal set; } + + /// + /// Whether this has a result. + /// + public bool HasResult => Type > HitResult.None; + + /// + /// Whether a successful hit occurred. + /// + public bool IsHit => Type > HitResult.Miss; + + public JudgementResult(Judgement judgement) + { + Judgement = judgement; + } + } +} diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index b767834e5d..27de18177f 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -35,8 +35,8 @@ public abstract class DrawableHitObject : SkinReloadableDrawable, IHasAccentColo private readonly Lazy> nestedHitObjects = new Lazy>(); public IEnumerable NestedHitObjects => nestedHitObjects.IsValueCreated ? nestedHitObjects.Value : Enumerable.Empty(); - public event Action OnJudgement; - public event Action OnJudgementRemoved; + public event Action OnJudgement; + public event Action OnJudgementRemoved; /// /// Whether a visible judgement should be displayed when this representation is hit. @@ -46,7 +46,7 @@ public abstract class DrawableHitObject : SkinReloadableDrawable, IHasAccentColo /// /// Whether this and all of its nested s have been hit. /// - public bool IsHit => HitObject.Judgements.All(j => j.IsHit) && NestedHitObjects.All(n => n.IsHit); + public bool IsHit => Results.All(j => j.IsHit) && NestedHitObjects.All(n => n.IsHit); /// /// Whether this and all of its nested s have been judged. @@ -57,7 +57,10 @@ public abstract class DrawableHitObject : SkinReloadableDrawable, IHasAccentColo /// Whether this has been judged. /// Note: This does NOT include nested hitobjects. /// - public bool Judged => HitObject.Judgements.All(h => h.HasResult); + public bool Judged => Results.All(h => h.HasResult); + + private readonly List results = new List(); + public IReadOnlyList Results => results; private bool judgementOccurred; @@ -74,6 +77,9 @@ public abstract class DrawableHitObject : SkinReloadableDrawable, IHasAccentColo protected DrawableHitObject(HitObject hitObject) { HitObject = hitObject; + + foreach (var j in hitObject.Judgements) + results.Add(CreateJudgementResult(j)); } [BackgroundDependencyLoader] @@ -135,17 +141,17 @@ protected override void Update() { var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; - for (int i = HitObject.Judgements.Count - 1; i >= 0; i--) + for (int i = Results.Count - 1; i >= 0; i--) { - var judgement = HitObject.Judgements[i]; + var judgement = Results[i]; if (judgement.TimeOffset + endTime <= Time.Current) break; - judgement.Result = HitResult.None; - State.Value = ArmedState.Idle; - OnJudgementRemoved?.Invoke(this, judgement); + + judgement.Type = HitResult.None; + State.Value = ArmedState.Idle; } } @@ -161,8 +167,8 @@ protected override void UpdateAfterChildren() protected virtual void AddNested(DrawableHitObject h) { - h.OnJudgement += (d, j) => OnJudgement?.Invoke(d, j); - h.OnJudgementRemoved += (d, j) => OnJudgementRemoved?.Invoke(d, j); + h.OnJudgement += (d, r) => OnJudgement?.Invoke(d, r); + h.OnJudgementRemoved += (d, r) => OnJudgementRemoved?.Invoke(d, r); h.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j); nestedHitObjects.Value.Add(h); @@ -172,18 +178,21 @@ protected virtual void AddNested(DrawableHitObject h) /// Notifies that a new judgement has occurred for this . /// /// The . - protected void ApplyJudgement(T judgement, Action application) - where T : Judgement + protected void ApplyResult(JudgementResult result, Action application) { - judgementOccurred = true; + // Todo: Unsure if we want to keep this + if (!Results.Contains(result)) + throw new ArgumentException($"The applied judgement result must be a part of {Results}."); - application?.Invoke(judgement); + application?.Invoke(result); + + judgementOccurred = true; // Ensure that the judgement is given a valid time offset, because this may not get set by the caller var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; - judgement.TimeOffset = Time.Current - endTime; + result.TimeOffset = Time.Current - endTime; - switch (judgement.Result) + switch (result.Type) { case HitResult.None: break; @@ -195,7 +204,7 @@ protected void ApplyJudgement(T judgement, Action application) break; } - OnJudgement?.Invoke(this, judgement); + OnJudgement?.Invoke(this, result); } /// @@ -224,7 +233,7 @@ protected bool UpdateJudgement(bool userTriggered) /// /// Checks if any judgements have occurred for this . This method must construct - /// all s and notify of them through . + /// all s and notify of them through . /// /// Whether the user triggered this check. /// The offset from the end time at which this check occurred. A > 0 @@ -232,6 +241,8 @@ protected bool UpdateJudgement(bool userTriggered) protected virtual void CheckForJudgements(bool userTriggered, double timeOffset) { } + + protected virtual JudgementResult CreateJudgementResult(Judgement judgement) => new JudgementResult(judgement); } public abstract class DrawableHitObject : DrawableHitObject diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index fa8c11df7f..ccd3fb6e69 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -28,7 +28,7 @@ public abstract class ScoreProcessor /// /// Invoked when a new judgement has occurred. This occurs after the judgement has been processed by the . /// - public event Action NewJudgement; + public event Action NewJudgement; /// /// Additional conditions on top of that cause a failing state. @@ -144,9 +144,10 @@ protected void UpdateFailed() /// Notifies subscribers of that a new judgement has occurred. /// /// The judgement to notify subscribers of. - protected void NotifyNewJudgement(Judgement judgement) + /// The judgement scoring result to notify subscribers of. + protected void NotifyNewJudgement(JudgementResult result) { - NewJudgement?.Invoke(judgement); + NewJudgement?.Invoke(result); if (HasCompleted) AllJudged?.Invoke(); @@ -209,32 +210,47 @@ public ScoreProcessor(RulesetContainer rulesetContainer) Mode.ValueChanged += _ => updateScore(); } - /// - /// Simulates an autoplay of s that will be judged by this - /// by adding s for each in the . - /// - /// This is required for to work, otherwise will be used. - /// - /// - /// The containing the s that will be judged by this . - protected virtual void SimulateAutoplay(Beatmap beatmap) { } + protected virtual void ApplyBeatmap(Beatmap beatmap) + { + } + + protected virtual void SimulateAutoplay(Beatmap beatmap) + { + foreach (var obj in beatmap.HitObjects) + simulate(obj); + + void simulate(HitObject obj) + { + foreach (var nested in obj.NestedHitObjects) + simulate(nested); + + foreach (var judgement in obj.Judgements) + AddJudgement(new JudgementResult(judgement) { Type = judgement.MaxResult }); + } + } /// /// Adds a judgement to this ScoreProcessor. /// /// The judgement to add. - protected void AddJudgement(Judgement judgement) + /// The judgement scoring result. + protected void AddJudgement(JudgementResult result) { - OnNewJudgement(judgement); + OnNewJudgement(result); updateScore(); UpdateFailed(); - NotifyNewJudgement(judgement); + NotifyNewJudgement(result); } - protected void RemoveJudgement(Judgement judgement) + /// + /// Removes a judgement from this ScoreProcessor. + /// + /// The judgement to remove. + /// The judgement scoring result. + protected void RemoveJudgement(JudgementResult result) { - OnJudgementRemoved(judgement); + OnJudgementRemoved(result); updateScore(); } @@ -242,16 +258,17 @@ protected void RemoveJudgement(Judgement judgement) /// Applies a judgement. /// /// The judgement to apply/ - protected virtual void OnNewJudgement(Judgement judgement) + /// The judgement scoring result. + protected virtual void OnNewJudgement(JudgementResult result) { - judgement.ComboAtJudgement = Combo; - judgement.HighestComboAtJudgement = HighestCombo; + result.ComboAtJudgement = Combo; + result.HighestComboAtJudgement = HighestCombo; JudgedHits++; - if (judgement.AffectsCombo) + if (result.Judgement.AffectsCombo) { - switch (judgement.Result) + switch (result.Type) { case HitResult.None: break; @@ -264,15 +281,15 @@ protected virtual void OnNewJudgement(Judgement judgement) } } - if (judgement.IsBonus) + if (result.Judgement.IsBonus) { - if (judgement.IsHit) - bonusScore += judgement.NumericResult; + if (result.IsHit) + bonusScore += result.Judgement.NumericResultFor(result); } else { - baseScore += judgement.NumericResult; - rollingMaxBaseScore += judgement.MaxNumericResult; + baseScore += result.Judgement.NumericResultFor(result); + rollingMaxBaseScore += result.Judgement.MaxNumericResult; } } @@ -280,22 +297,23 @@ protected virtual void OnNewJudgement(Judgement judgement) /// Removes a judgement. This should reverse everything in . /// /// The judgement to remove. - protected virtual void OnJudgementRemoved(Judgement judgement) + /// The judgement scoring result. + protected virtual void OnJudgementRemoved(JudgementResult result) { - Combo.Value = judgement.ComboAtJudgement; - HighestCombo.Value = judgement.HighestComboAtJudgement; + Combo.Value = result.ComboAtJudgement; + HighestCombo.Value = result.HighestComboAtJudgement; JudgedHits--; - if (judgement.IsBonus) + if (result.Judgement.IsBonus) { - if (judgement.IsHit) - bonusScore -= judgement.NumericResult; + if (result.IsHit) + bonusScore -= result.Judgement.NumericResultFor(result); } else { - baseScore -= judgement.NumericResult; - rollingMaxBaseScore -= judgement.MaxNumericResult; + baseScore -= result.Judgement.NumericResultFor(result); + rollingMaxBaseScore -= result.Judgement.MaxNumericResult; } } diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index ee34e2df04..e890cccc3c 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -182,8 +182,8 @@ protected override void Dispose(bool isDisposing) public abstract class RulesetContainer : RulesetContainer where TObject : HitObject { - public event Action OnJudgement; - public event Action OnJudgementRemoved; + public event Action OnJudgement; + public event Action OnJudgementRemoved; /// /// The Beatmap @@ -290,8 +290,8 @@ private void loadObjects() if (drawableObject == null) continue; - drawableObject.OnJudgement += (d, j) => OnJudgement?.Invoke(j); - drawableObject.OnJudgementRemoved += (d, j) => OnJudgementRemoved?.Invoke(j); + drawableObject.OnJudgement += (_, r) => OnJudgement?.Invoke(r); + drawableObject.OnJudgementRemoved += (_, r) => OnJudgementRemoved?.Invoke(r); Playfield.Add(drawableObject); } diff --git a/osu.Game/Screens/Play/HUD/StandardHealthDisplay.cs b/osu.Game/Screens/Play/HUD/StandardHealthDisplay.cs index ab446550a6..b551b1f7a6 100644 --- a/osu.Game/Screens/Play/HUD/StandardHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/StandardHealthDisplay.cs @@ -92,9 +92,9 @@ public StandardHealthDisplay() }; } - public void Flash(Judgement judgement) + public void Flash(JudgementResult result) { - if (judgement.Result == HitResult.Miss) + if (result.Type == HitResult.Miss) return; fill.FadeEdgeEffectTo(Math.Min(1, fill.EdgeEffect.Colour.Linear.A + (1f - base_glow_opacity) / glow_max_hits), 50, Easing.OutQuint)