From 305003997279cc9a17797487943afb702c61e995 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Wed, 29 Mar 2017 17:57:36 +0900 Subject: [PATCH 1/7] Implement partial judgements + make Result non-nullable. --- .../Objects/Drawables/DrawableHitCircle.cs | 2 +- .../Objects/Drawable/DrawableDrumRollTick.cs | 2 +- .../Objects/Drawable/DrawableHit.cs | 2 +- .../Objects/Drawable/DrawableStrongHit.cs | 5 ++-- .../Objects/Drawable/DrawableSwell.cs | 2 +- .../Modes/Judgements/IPartialJudgement.cs | 26 +++++++++++++++++++ osu.Game/Modes/Judgements/Judgement.cs | 2 +- .../Objects/Drawables/DrawableHitObject.cs | 19 +++++++++++--- osu.Game/Modes/Objects/Drawables/HitResult.cs | 11 ++++++++ osu.Game/Modes/UI/HitRenderer.cs | 2 +- osu.Game/osu.Game.csproj | 1 + 11 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 osu.Game/Modes/Judgements/IPartialJudgement.cs diff --git a/osu.Game.Modes.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Modes.Osu/Objects/Drawables/DrawableHitCircle.cs index dcc25a997a..68c5ec0a45 100644 --- a/osu.Game.Modes.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Modes.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -38,7 +38,7 @@ namespace osu.Game.Modes.Osu.Objects.Drawables Colour = AccentColour, Hit = () => { - if (Judgement.Result.HasValue) return false; + if (Judgement.Result != HitResult.None) return false; Judgement.PositionOffset = Vector2.Zero; //todo: set to correct value UpdateJudgement(true); diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableDrumRollTick.cs b/osu.Game.Modes.Taiko/Objects/Drawable/DrawableDrumRollTick.cs index 1e270c6751..5217fd9085 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableDrumRollTick.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawable/DrawableDrumRollTick.cs @@ -47,7 +47,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable protected override bool HandleKeyPress(Key key) { - return !Judgement.Result.HasValue && UpdateJudgement(true); + return Judgement.Result == HitResult.None && UpdateJudgement(true); } } } diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableHit.cs b/osu.Game.Modes.Taiko/Objects/Drawable/DrawableHit.cs index ae328fe9ca..c8a7355e3c 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableHit.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawable/DrawableHit.cs @@ -68,7 +68,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable protected override bool HandleKeyPress(Key key) { - if (Judgement.Result.HasValue) + if (Judgement.Result != HitResult.None) return false; validKeyPressed = HitKeys.Contains(key); diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongHit.cs b/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongHit.cs index 5e225e1dce..a77fd1d6be 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongHit.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongHit.cs @@ -5,6 +5,7 @@ using OpenTK.Input; using System; using System.Linq; using osu.Framework.Input; +using osu.Game.Modes.Objects.Drawables; namespace osu.Game.Modes.Taiko.Objects.Drawable { @@ -27,7 +28,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable protected override void CheckJudgement(bool userTriggered) { - if (!Judgement.Result.HasValue) + if (Judgement.Result == HitResult.None) { base.CheckJudgement(userTriggered); return; @@ -45,7 +46,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable protected override bool HandleKeyPress(Key key) { // Check if we've handled the first key - if (!Judgement.Result.HasValue) + if (Judgement.Result == HitResult.None) { // First key hasn't been handled yet, attempt to handle it bool handled = base.HandleKeyPress(key); diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableSwell.cs b/osu.Game.Modes.Taiko/Objects/Drawable/DrawableSwell.cs index 15584ac73f..22fa4dea6f 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableSwell.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawable/DrawableSwell.cs @@ -64,7 +64,7 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable protected override bool HandleKeyPress(Key key) { - if (Judgement.Result.HasValue) + if (Judgement.Result != HitResult.None) return false; UpdateJudgement(true); diff --git a/osu.Game/Modes/Judgements/IPartialJudgement.cs b/osu.Game/Modes/Judgements/IPartialJudgement.cs new file mode 100644 index 0000000000..2ca1ffce4d --- /dev/null +++ b/osu.Game/Modes/Judgements/IPartialJudgement.cs @@ -0,0 +1,26 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Modes.Objects.Drawables; +using osu.Game.Modes.Scoring; + +namespace osu.Game.Modes.Judgements +{ + /// + /// Inidicates that the judgement this is attached to is a partial judgement and the scoring value may change. + /// + /// This judgement will be continually processed by + /// unless the result is a miss and will trigger a full re-process of the when changed. + /// + /// + public interface IPartialJudgement + { + /// + /// Indicates that this partial judgement has changed and requires a full re-process of the . + /// + /// This is set to false once the judgement has been re-processed. + /// + /// + bool Changed { get; set; } + } +} diff --git a/osu.Game/Modes/Judgements/Judgement.cs b/osu.Game/Modes/Judgements/Judgement.cs index d916fc15de..5b1e4ddac6 100644 --- a/osu.Game/Modes/Judgements/Judgement.cs +++ b/osu.Game/Modes/Judgements/Judgement.cs @@ -10,7 +10,7 @@ namespace osu.Game.Modes.Judgements /// /// Whether this judgement is the result of a hit or a miss. /// - public HitResult? Result; + public HitResult Result; /// /// The offset at which this judgement occurred. diff --git a/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs index 3998a3e385..2939980ac6 100644 --- a/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs @@ -93,16 +93,26 @@ namespace osu.Game.Modes.Objects.Drawables /// Whether a hit was processed. protected bool UpdateJudgement(bool userTriggered) { - if (Judgement.Result != null) + IPartialJudgement partial = Judgement as IPartialJudgement; + + // Never re-process non-partial hits, or partial judgements that were previously judged as misses + if (Judgement.Result != HitResult.None && (partial == null || Judgement.Result == HitResult.Miss)) return false; + // Update the judgement state double endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; - Judgement.TimeOffset = Time.Current - endTime; + // Update the judgement state + bool hadResult = Judgement.Result != HitResult.None; CheckJudgement(userTriggered); - if (Judgement.Result == null) + // Don't process judgements with no result + if (Judgement.Result == HitResult.None) + return false; + + // Don't process judgements that previously had results but the results were unchanged + if (hadResult && partial?.Changed != true) return false; switch (Judgement.Result) @@ -117,6 +127,9 @@ namespace osu.Game.Modes.Objects.Drawables OnJudgement?.Invoke(this); + if (partial != null) + partial.Changed = false; + return true; } diff --git a/osu.Game/Modes/Objects/Drawables/HitResult.cs b/osu.Game/Modes/Objects/Drawables/HitResult.cs index 1bbf9269bb..e036610ae2 100644 --- a/osu.Game/Modes/Objects/Drawables/HitResult.cs +++ b/osu.Game/Modes/Objects/Drawables/HitResult.cs @@ -7,8 +7,19 @@ namespace osu.Game.Modes.Objects.Drawables { public enum HitResult { + /// + /// Indicates that the object has not been judged yet. + /// + [Description("")] + None, + /// + /// Indicates that the object has been judged as a miss. + /// [Description(@"Miss")] Miss, + /// + /// Indicates that the object has been judged as a hit. + /// [Description(@"Hit")] Hit, } diff --git a/osu.Game/Modes/UI/HitRenderer.cs b/osu.Game/Modes/UI/HitRenderer.cs index 3d108b895d..1681da2ba9 100644 --- a/osu.Game/Modes/UI/HitRenderer.cs +++ b/osu.Game/Modes/UI/HitRenderer.cs @@ -149,7 +149,7 @@ namespace osu.Game.Modes.UI public event Action OnJudgement; protected override Container Content => content; - protected override bool AllObjectsJudged => Playfield.HitObjects.Children.All(h => h.Judgement.Result.HasValue); + protected override bool AllObjectsJudged => Playfield.HitObjects.Children.All(h => h.Judgement.Result != HitResult.None); /// /// The playfield. diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a5bdf1df69..fcb45f91fd 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -97,6 +97,7 @@ + From c0dae89844d603fb6bd486f76d3a2235bafefbe1 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Wed, 29 Mar 2017 18:16:26 +0900 Subject: [PATCH 2/7] Implement partial strong hit judgements. --- .../Judgements/TaikoJudgement.cs | 6 ++--- .../Judgements/TaikoStrongHitJudgement.cs | 25 +++++++++++++++++++ .../Objects/Drawable/DrawableStrongHit.cs | 3 +++ .../osu.Game.Modes.Taiko.csproj | 1 + 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 osu.Game.Modes.Taiko/Judgements/TaikoStrongHitJudgement.cs diff --git a/osu.Game.Modes.Taiko/Judgements/TaikoJudgement.cs b/osu.Game.Modes.Taiko/Judgements/TaikoJudgement.cs index e50a685e24..f4745730db 100644 --- a/osu.Game.Modes.Taiko/Judgements/TaikoJudgement.cs +++ b/osu.Game.Modes.Taiko/Judgements/TaikoJudgement.cs @@ -22,7 +22,7 @@ namespace osu.Game.Modes.Taiko.Judgements /// The result value for the combo portion of the score. /// public int ResultValueForScore => NumericResultForScore(TaikoResult); - + /// /// The result value for the accuracy portion of the score. /// @@ -32,7 +32,7 @@ namespace osu.Game.Modes.Taiko.Judgements /// The maximum result value for the combo portion of the score. /// public int MaxResultValueForScore => NumericResultForScore(MAX_HIT_RESULT); - + /// /// The maximum result value for the accuracy portion of the score. /// @@ -45,7 +45,7 @@ namespace osu.Game.Modes.Taiko.Judgements /// /// Whether this Judgement has a secondary hit in the case of finishers. /// - public bool SecondHit; + public virtual bool SecondHit { get; set; } /// /// Computes the numeric result value for the combo portion of the score. diff --git a/osu.Game.Modes.Taiko/Judgements/TaikoStrongHitJudgement.cs b/osu.Game.Modes.Taiko/Judgements/TaikoStrongHitJudgement.cs new file mode 100644 index 0000000000..ee978d0026 --- /dev/null +++ b/osu.Game.Modes.Taiko/Judgements/TaikoStrongHitJudgement.cs @@ -0,0 +1,25 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Modes.Judgements; + +namespace osu.Game.Modes.Taiko.Judgements +{ + public class TaikoStrongHitJudgement : TaikoJudgement, IPartialJudgement + { + public bool Changed { get; set; } + + public override bool SecondHit + { + get { return base.SecondHit; } + set + { + if (base.SecondHit == value) + return; + base.SecondHit = value; + + Changed = true; + } + } + } +} diff --git a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongHit.cs b/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongHit.cs index a77fd1d6be..a6cb6ae7fa 100644 --- a/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongHit.cs +++ b/osu.Game.Modes.Taiko/Objects/Drawable/DrawableStrongHit.cs @@ -6,6 +6,7 @@ using System; using System.Linq; using osu.Framework.Input; using osu.Game.Modes.Objects.Drawables; +using osu.Game.Modes.Taiko.Judgements; namespace osu.Game.Modes.Taiko.Objects.Drawable { @@ -26,6 +27,8 @@ namespace osu.Game.Modes.Taiko.Objects.Drawable { } + protected override TaikoJudgement CreateJudgement() => new TaikoStrongHitJudgement(); + protected override void CheckJudgement(bool userTriggered) { if (Judgement.Result == HitResult.None) diff --git a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj index 07f9a5d4e6..60fe8cb51f 100644 --- a/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj +++ b/osu.Game.Modes.Taiko/osu.Game.Modes.Taiko.csproj @@ -50,6 +50,7 @@ + From c2d6faa7c25a1e22640fb50b3f10e9fe5e595537 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 30 Mar 2017 10:34:37 +0900 Subject: [PATCH 3/7] Change Judgements into HashSet to prevent duplicates. --- osu.Game/Modes/Scoring/ScoreProcessor.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Modes/Scoring/ScoreProcessor.cs b/osu.Game/Modes/Scoring/ScoreProcessor.cs index f14b306e18..b24ab090b3 100644 --- a/osu.Game/Modes/Scoring/ScoreProcessor.cs +++ b/osu.Game/Modes/Scoring/ScoreProcessor.cs @@ -110,7 +110,7 @@ namespace osu.Game.Modes.Scoring /// /// All judgements held by this ScoreProcessor. /// - protected readonly List Judgements = new List(); + protected readonly HashSet Judgements = new HashSet(); public override bool HasFailed => Health.Value == Health.MinValue; @@ -120,8 +120,6 @@ namespace osu.Game.Modes.Scoring protected ScoreProcessor(HitRenderer hitRenderer) { - Judgements.Capacity = hitRenderer.Beatmap.HitObjects.Count; - hitRenderer.OnJudgement += AddJudgement; ComputeTargets(hitRenderer.Beatmap); From 6287ba321da555faf353d801a855179ac58fc8ce Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 30 Mar 2017 10:51:14 +0900 Subject: [PATCH 4/7] Rewrite ScoreProcessor to have a new method for when existing judgements are changed. - OnNewJudgement: Keeps its previous functionality. It is now only invoked when a _new_ judgement has been added to the Judgements hashset. - OnJudgementChanged: Has a similar funcitonality to OnNewJudgement, but is only invoked whenever a judgement that was _previously_ in the Judgements hashset is changed. --- .../Tests/TestCaseTaikoPlayfield.cs | 4 +- .../Scoring/CatchScoreProcessor.cs | 2 +- .../Scoring/ManiaScoreProcessor.cs | 2 +- .../Scoring/OsuScoreProcessor.cs | 2 +- .../Scoring/TaikoScoreProcessor.cs | 79 ++++++++++++------- osu.Game/Modes/Judgements/Judgement.cs | 2 +- osu.Game/Modes/Scoring/ScoreProcessor.cs | 28 +++++-- 7 files changed, 75 insertions(+), 44 deletions(-) diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs b/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs index a6491bd07b..ca4fee1b4d 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseTaikoPlayfield.cs @@ -55,7 +55,6 @@ namespace osu.Desktop.VisualTests.Tests Result = HitResult.Hit, TaikoResult = hitResult, TimeOffset = 0, - ComboAtHit = 1, SecondHit = RNG.Next(10) == 0 } }); @@ -68,8 +67,7 @@ namespace osu.Desktop.VisualTests.Tests Judgement = new TaikoJudgement { Result = HitResult.Miss, - TimeOffset = 0, - ComboAtHit = 0 + TimeOffset = 0 } }); } diff --git a/osu.Game.Modes.Catch/Scoring/CatchScoreProcessor.cs b/osu.Game.Modes.Catch/Scoring/CatchScoreProcessor.cs index 766a492bf4..1b9bedf7fb 100644 --- a/osu.Game.Modes.Catch/Scoring/CatchScoreProcessor.cs +++ b/osu.Game.Modes.Catch/Scoring/CatchScoreProcessor.cs @@ -19,7 +19,7 @@ namespace osu.Game.Modes.Catch.Scoring { } - protected override void OnNewJugement(CatchJudgement judgement) + protected override void OnNewJudgement(CatchJudgement judgement) { } } diff --git a/osu.Game.Modes.Mania/Scoring/ManiaScoreProcessor.cs b/osu.Game.Modes.Mania/Scoring/ManiaScoreProcessor.cs index c6b223af6d..0f87030e25 100644 --- a/osu.Game.Modes.Mania/Scoring/ManiaScoreProcessor.cs +++ b/osu.Game.Modes.Mania/Scoring/ManiaScoreProcessor.cs @@ -19,7 +19,7 @@ namespace osu.Game.Modes.Mania.Scoring { } - protected override void OnNewJugement(ManiaJudgement judgement) + protected override void OnNewJudgement(ManiaJudgement judgement) { } } diff --git a/osu.Game.Modes.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Modes.Osu/Scoring/OsuScoreProcessor.cs index b71e7dbadd..0bd587e8ea 100644 --- a/osu.Game.Modes.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Modes.Osu/Scoring/OsuScoreProcessor.cs @@ -28,7 +28,7 @@ namespace osu.Game.Modes.Osu.Scoring Accuracy.Value = 1; } - protected override void OnNewJugement(OsuJudgement judgement) + protected override void OnNewJudgement(OsuJudgement judgement) { if (judgement != null) { diff --git a/osu.Game.Modes.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Modes.Taiko/Scoring/TaikoScoreProcessor.cs index 2ab31c5efb..fa7e18cadb 100644 --- a/osu.Game.Modes.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Modes.Taiko/Scoring/TaikoScoreProcessor.cs @@ -96,9 +96,9 @@ namespace osu.Game.Modes.Taiko.Scoring /// /// The multiple of the original score added to the combo portion of the score - /// for correctly hitting an accented hit object with both keys. + /// for correctly hitting a strong hit object with both keys. /// - private double accentedHitScale; + private double strongHitScale; private double hpIncreaseTick; private double hpIncreaseGreat; @@ -128,12 +128,12 @@ namespace osu.Game.Modes.Taiko.Scoring hpIncreaseGood = hpMultiplierNormal * hp_hit_good; hpIncreaseMiss = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.Difficulty.DrainRate, hp_miss_min, hp_miss_mid, hp_miss_max); - var accentedHits = beatmap.HitObjects.FindAll(o => o is Hit && o.IsStrong); + var strongHits = beatmap.HitObjects.FindAll(o => o is Hit && o.IsStrong); // This is a linear function that awards: - // 10 times bonus points for hitting an accented hit object with both keys with 30 accented hit objects in the map - // 3 times bonus points for hitting an accented hit object with both keys with 120 accented hit objects in the map - accentedHitScale = -7d / 90d * MathHelper.Clamp(accentedHits.Count, 30, 120) + 111d / 9d; + // 10 times bonus points for hitting a strong hit object with both keys with 30 strong hit objects in the map + // 3 times bonus points for hitting a strong hit object with both keys with 120 strong hit objects in the map + strongHitScale = -7d / 90d * MathHelper.Clamp(strongHits.Count, 30, 120) + 111d / 9d; foreach (var obj in beatmap.HitObjects) { @@ -179,7 +179,7 @@ namespace osu.Game.Modes.Taiko.Scoring maxComboPortion = comboPortion; } - protected override void OnNewJugement(TaikoJudgement judgement) + protected override void OnNewJudgement(TaikoJudgement judgement) { bool isTick = judgement is TaikoDrumRollTickJudgement; @@ -187,29 +187,12 @@ namespace osu.Game.Modes.Taiko.Scoring if (!isTick) totalHits++; + // Apply combo changes, must be done before the hit score is added + if (!isTick && judgement.Result == HitResult.Hit) + Combo.Value++; + // Apply score changes - if (judgement.Result == HitResult.Hit) - { - double baseValue = judgement.ResultValueForScore; - - // Add bonus points for hitting an accented hit object with the second key - if (judgement.SecondHit) - baseValue += baseValue * accentedHitScale; - - // Add score to portions - if (isTick) - bonusScore += baseValue; - else - { - Combo.Value++; - - // A relevance factor that needs to be applied to make higher combos more relevant - // Value is capped at 400 combo - double comboRelevance = Math.Min(Math.Log(400, combo_base), Math.Max(0.5, Math.Log(Combo.Value, combo_base))); - - comboPortion += baseValue * comboRelevance; - } - } + addHitScore(judgement); // Apply HP changes switch (judgement.Result) @@ -235,7 +218,43 @@ namespace osu.Game.Modes.Taiko.Scoring break; } - // Compute the new score + accuracy + calculateScore(); + } + + protected override void OnJudgementChanged(TaikoJudgement judgement) + { + // Apply score changes + addHitScore(judgement); + + calculateScore(); + } + + private void addHitScore(TaikoJudgement judgement) + { + if (judgement.Result != HitResult.Hit) + return; + + double baseValue = judgement.ResultValueForScore; + + // Add increased score for hitting a strong hit object with the second key + if (judgement.SecondHit) + baseValue *= strongHitScale; + + // Add score to portions + if (judgement is TaikoDrumRollTickJudgement) + bonusScore += baseValue; + else + { + // A relevance factor that needs to be applied to make higher combos more relevant + // Value is capped at 400 combo + double comboRelevance = Math.Min(Math.Log(400, combo_base), Math.Max(0.5, Math.Log(Combo.Value, combo_base))); + + comboPortion += baseValue * comboRelevance; + } + } + + private void calculateScore() + { int scoreForAccuracy = 0; int maxScoreForAccuracy = 0; diff --git a/osu.Game/Modes/Judgements/Judgement.cs b/osu.Game/Modes/Judgements/Judgement.cs index 5b1e4ddac6..677ec8bca9 100644 --- a/osu.Game/Modes/Judgements/Judgement.cs +++ b/osu.Game/Modes/Judgements/Judgement.cs @@ -20,7 +20,7 @@ namespace osu.Game.Modes.Judgements /// /// The combo after this judgement was processed. /// - public ulong? ComboAtHit; + public int ComboAtHit; /// /// The string representation for the result achieved. diff --git a/osu.Game/Modes/Scoring/ScoreProcessor.cs b/osu.Game/Modes/Scoring/ScoreProcessor.cs index b24ab090b3..4e902596ce 100644 --- a/osu.Game/Modes/Scoring/ScoreProcessor.cs +++ b/osu.Game/Modes/Scoring/ScoreProcessor.cs @@ -139,11 +139,13 @@ namespace osu.Game.Modes.Scoring /// The judgement to add. protected void AddJudgement(TJudgement judgement) { - Judgements.Add(judgement); - - OnNewJugement(judgement); - - judgement.ComboAtHit = (ulong)Combo.Value; + if (Judgements.Add(judgement)) + { + OnNewJudgement(judgement); + judgement.ComboAtHit = Combo.Value; + } + else + OnJudgementChanged(judgement); UpdateFailed(); } @@ -154,9 +156,21 @@ namespace osu.Game.Modes.Scoring } /// - /// Update any values that potentially need post-processing on a judgement change. + /// Updates any values that need post-processing. Invoked when a new judgement has occurred. + /// + /// This is not triggered when existing judgements are changed - for that see . + /// /// /// The judgement that triggered this calculation. - protected abstract void OnNewJugement(TJudgement judgement); + protected abstract void OnNewJudgement(TJudgement judgement); + + /// + /// Updates any values that need post-processing. Invoked when an existing judgement has changed. + /// + /// This is not triggered when a new judgement has occurred - for that see . + /// + /// + /// The judgement that triggered this calculation. + protected virtual void OnJudgementChanged(TJudgement judgement) { } } } \ No newline at end of file From 49575c34476adb06e3d81789bfbac8cd2b733304 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 31 Mar 2017 11:54:12 +0900 Subject: [PATCH 5/7] Special case not needed. --- osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs index 2939980ac6..ed8269876e 100644 --- a/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Modes/Objects/Drawables/DrawableHitObject.cs @@ -95,8 +95,8 @@ namespace osu.Game.Modes.Objects.Drawables { IPartialJudgement partial = Judgement as IPartialJudgement; - // Never re-process non-partial hits, or partial judgements that were previously judged as misses - if (Judgement.Result != HitResult.None && (partial == null || Judgement.Result == HitResult.Miss)) + // Never re-process non-partial hits + if (Judgement.Result != HitResult.None && partial == null) return false; // Update the judgement state From cd915a32bef6b2f8bead9b4d6007528c21011b93 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 31 Mar 2017 11:58:24 +0900 Subject: [PATCH 6/7] Let's use a List for now. --- osu.Game/Modes/Scoring/ScoreProcessor.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Modes/Scoring/ScoreProcessor.cs b/osu.Game/Modes/Scoring/ScoreProcessor.cs index 314d4fa194..4c42f2a384 100644 --- a/osu.Game/Modes/Scoring/ScoreProcessor.cs +++ b/osu.Game/Modes/Scoring/ScoreProcessor.cs @@ -110,7 +110,7 @@ namespace osu.Game.Modes.Scoring /// /// All judgements held by this ScoreProcessor. /// - protected readonly HashSet Judgements = new HashSet(); + protected readonly List Judgements = new List(); public override bool HasFailed => Health.Value == Health.MinValue; @@ -139,9 +139,13 @@ namespace osu.Game.Modes.Scoring /// The judgement to add. protected void AddJudgement(TJudgement judgement) { - if (Judgements.Add(judgement)) + bool exists = Judgements.Contains(judgement); + + if (!exists) { + Judgements.Add(judgement); OnNewJudgement(judgement); + judgement.ComboAtHit = Combo.Value; } else From 09b98d71a705b56802a4dc1c7f89eae064905061 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 31 Mar 2017 13:33:19 +0900 Subject: [PATCH 7/7] Add back Capacity. --- osu.Game/Modes/Scoring/ScoreProcessor.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Modes/Scoring/ScoreProcessor.cs b/osu.Game/Modes/Scoring/ScoreProcessor.cs index 4c42f2a384..a64b4d4013 100644 --- a/osu.Game/Modes/Scoring/ScoreProcessor.cs +++ b/osu.Game/Modes/Scoring/ScoreProcessor.cs @@ -120,6 +120,8 @@ namespace osu.Game.Modes.Scoring protected ScoreProcessor(HitRenderer hitRenderer) { + Judgements.Capacity = hitRenderer.Beatmap.HitObjects.Count; + hitRenderer.OnJudgement += AddJudgement; ComputeTargets(hitRenderer.Beatmap);