From 1366b53a7150c56165a534dacea2eae9933e0a3b Mon Sep 17 00:00:00 2001 From: MaxOhn Date: Tue, 9 Oct 2018 13:16:27 +0200 Subject: [PATCH 01/48] Added traceable mod + HideButApproachCircle function for DrawableHitCircle --- osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 32 +++++++++++++++++++ .../Objects/Drawables/DrawableHitCircle.cs | 9 ++++++ osu.Game.Rulesets.Osu/OsuRuleset.cs | 1 + 3 files changed, 42 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs new file mode 100644 index 0000000000..43eac55ffd --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using osu.Game.Graphics; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; + +namespace osu.Game.Rulesets.Osu.Mods +{ + internal class OsuModTraceable : Mod, IApplicableToDrawableHitObjects + { + public override string Name => "Traceable"; + public override string ShortenedName => "TC"; + public override FontAwesome Icon => FontAwesome.fa_snapchat_ghost; + public override ModType Type => ModType.Fun; + public override string Description => "Put your faith in the approach circles..."; + public override double ScoreMultiplier => 1; + + public void ApplyToDrawableHitObjects(IEnumerable drawables) + { + foreach (var drawable in drawables) + { + if (drawable is DrawableHitCircle c) + c.HideButApproachCircle(); + if (drawable is DrawableSlider s) + s.HeadCircle.HideButApproachCircle(); + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 4bdddcef11..79cc88e474 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -76,6 +76,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } } + public void HideButApproachCircle() + { + circle.Hide(); + circle.AlwaysPresent = true; + ring.Hide(); + number.Hide(); + glow.Hide(); + } + protected override void CheckForResult(bool userTriggered, double timeOffset) { if (!userTriggered) diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 6736d10dab..0b6aee7881 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -121,6 +121,7 @@ namespace osu.Game.Rulesets.Osu return new Mod[] { new OsuModTransform(), new OsuModWiggle(), + new OsuModTraceable(), }; default: return new Mod[] { }; From 954bcd8c123dcad1112ed94bc07bf3a824adfc9d Mon Sep 17 00:00:00 2001 From: MaxOhn Date: Tue, 9 Oct 2018 18:36:12 +0200 Subject: [PATCH 02/48] Treat non-DrawableHitCircle's similar to OsuModHidden --- osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 61 +++++++++++++++++-- .../Objects/Drawables/DrawableHitCircle.cs | 2 + 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index 43eac55ffd..dfd398e7e4 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -1,11 +1,14 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Collections.Generic; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Rulesets.Osu.Mods { @@ -21,11 +24,61 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableHitObjects(IEnumerable drawables) { foreach (var drawable in drawables) + drawable.ApplyCustomUpdateState += ApplyTraceableState; + } + + /* Similar to ApplyHiddenState, only different if drawable is DrawableHitCircle. + * If we'd use ApplyHiddenState instead but only on non-DrawableHitCircle's, then + * the nested object HeadCircle of DrawableSlider would still use ApplyHiddenState, + * thus treating the DrawableHitCircle with the hidden mod instead of the traceable mod. + */ + protected void ApplyTraceableState(DrawableHitObject drawable, ArmedState state) + { + if (!(drawable is DrawableOsuHitObject d)) + return; + + var h = d.HitObject; + + var fadeOutStartTime = h.StartTime - h.TimePreempt + h.TimeFadeIn; + + // new duration from completed fade in to end (before fading out) + var longFadeDuration = ((h as IHasEndTime)?.EndTime ?? h.StartTime) - fadeOutStartTime; + + switch (drawable) { - if (drawable is DrawableHitCircle c) - c.HideButApproachCircle(); - if (drawable is DrawableSlider s) - s.HeadCircle.HideButApproachCircle(); + case DrawableHitCircle circle: + // we only want to see the approach circle + using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) + circle.HideButApproachCircle(); + + // approach circle fades out quickly at StartTime + using (drawable.BeginAbsoluteSequence(h.StartTime, true)) + circle.ApproachCircle.FadeOut(50); + + break; + case DrawableSlider slider: + using (slider.BeginAbsoluteSequence(fadeOutStartTime, true)) + slider.Body.FadeOut(longFadeDuration, Easing.Out); + + break; + case DrawableSliderTick sliderTick: + // slider ticks fade out over up to one second + var tickFadeOutDuration = Math.Min(sliderTick.HitObject.TimePreempt - DrawableSliderTick.ANIM_DURATION, 1000); + + using (sliderTick.BeginAbsoluteSequence(sliderTick.HitObject.StartTime - tickFadeOutDuration, true)) + sliderTick.FadeOut(tickFadeOutDuration); + + break; + case DrawableSpinner spinner: + // hide elements we don't care about. + spinner.Disc.Hide(); + spinner.Ticks.Hide(); + spinner.Background.Hide(); + + using (spinner.BeginAbsoluteSequence(fadeOutStartTime + longFadeDuration, true)) + spinner.FadeOut(h.TimePreempt); + + break; } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 79cc88e474..1644480aa4 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -81,6 +81,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables circle.Hide(); circle.AlwaysPresent = true; ring.Hide(); + flash.Hide(); + explode.Hide(); number.Hide(); glow.Hide(); } From edb69463fd4318145ff97e2bb3a0219fc8f646dc Mon Sep 17 00:00:00 2001 From: MaxOhn Date: Tue, 9 Oct 2018 18:52:34 +0200 Subject: [PATCH 03/48] Trimming whitespace from comment...... --- osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index dfd398e7e4..a6d8d35125 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Mods } /* Similar to ApplyHiddenState, only different if drawable is DrawableHitCircle. - * If we'd use ApplyHiddenState instead but only on non-DrawableHitCircle's, then + * If we'd use ApplyHiddenState instead but only on non-DrawableHitCircle's, then * the nested object HeadCircle of DrawableSlider would still use ApplyHiddenState, * thus treating the DrawableHitCircle with the hidden mod instead of the traceable mod. */ From 5496b8bc58fae51b4dc242bb5eb0051a7d2039a1 Mon Sep 17 00:00:00 2001 From: MaxOhn Date: Mon, 1 Jul 2019 20:11:50 +0200 Subject: [PATCH 04/48] Rewrote traceable mod to inherit from hidden --- osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs | 3 + osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs | 2 + osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 90 ++++++++----------- .../Objects/Drawables/DrawableHitCircle.cs | 23 ++--- osu.Game/Overlays/Mods/ModSection.cs | 4 +- 5 files changed, 48 insertions(+), 74 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs index 8072dc09c1..9b1f43b209 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Bindables; @@ -28,6 +29,8 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1; + public override Type[] IncompatibleMods => new[] { typeof(OsuModTraceable) }; + private Bindable increaseFirstObjectVisibility = new Bindable(); public void ReadFromConfig(OsuConfigManager config) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs index ddf708d0f1..5887cb2865 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs @@ -17,6 +17,8 @@ namespace osu.Game.Rulesets.Osu.Mods { public override string Description => @"Play with no approach circles and fading circles/sliders."; public override double ScoreMultiplier => 1.06; + public override Type[] IncompatibleMods => new[] { typeof(OsuModTraceable) }; + private const double fade_in_duration_multiplier = 0.4; private const double fade_out_duration_multiplier = 0.3; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index a6d8d35125..858b7e15c8 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -2,83 +2,63 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Linq; using System.Collections.Generic; -using osu.Game.Graphics; +using osu.Framework.Graphics.Sprites; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osu.Framework.Graphics; -using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Rulesets.Osu.Mods { - internal class OsuModTraceable : Mod, IApplicableToDrawableHitObjects + internal class OsuModTraceable : OsuModHidden, IReadFromConfig, IApplicableToDrawableHitObjects { public override string Name => "Traceable"; - public override string ShortenedName => "TC"; - public override FontAwesome Icon => FontAwesome.fa_snapchat_ghost; + public override string Acronym => "TC"; + public override IconUsage Icon => FontAwesome.Brands.SnapchatGhost; public override ModType Type => ModType.Fun; public override string Description => "Put your faith in the approach circles..."; public override double ScoreMultiplier => 1; + public override Type[] IncompatibleMods => new[] { typeof(OsuModHidden), typeof(OsuModGrow) }; - public void ApplyToDrawableHitObjects(IEnumerable drawables) + public override void ApplyToDrawableHitObjects(IEnumerable drawables) { - foreach (var drawable in drawables) - drawable.ApplyCustomUpdateState += ApplyTraceableState; + foreach (var drawable in drawables.Skip(IncreaseFirstObjectVisibility.Value ? 1 : 0)) + { + switch (drawable) + { + case DrawableHitCircle _: + drawable.ApplyCustomUpdateState += ApplyTraceableState; + break; + case DrawableSlider slider: + slider.ApplyCustomUpdateState += ApplyHiddenState; + slider.HeadCircle.ApplyCustomUpdateState += ApplyTraceableState; + break; + default: + drawable.ApplyCustomUpdateState += ApplyHiddenState; + break; + } + } } - /* Similar to ApplyHiddenState, only different if drawable is DrawableHitCircle. - * If we'd use ApplyHiddenState instead but only on non-DrawableHitCircle's, then - * the nested object HeadCircle of DrawableSlider would still use ApplyHiddenState, - * thus treating the DrawableHitCircle with the hidden mod instead of the traceable mod. - */ protected void ApplyTraceableState(DrawableHitObject drawable, ArmedState state) { - if (!(drawable is DrawableOsuHitObject d)) + if (!(drawable is DrawableHitCircle circle)) return; - var h = d.HitObject; + var h = circle.HitObject; - var fadeOutStartTime = h.StartTime - h.TimePreempt + h.TimeFadeIn; - - // new duration from completed fade in to end (before fading out) - var longFadeDuration = ((h as IHasEndTime)?.EndTime ?? h.StartTime) - fadeOutStartTime; - - switch (drawable) + // we only want to see the approach circle + using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) { - case DrawableHitCircle circle: - // we only want to see the approach circle - using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) - circle.HideButApproachCircle(); - - // approach circle fades out quickly at StartTime - using (drawable.BeginAbsoluteSequence(h.StartTime, true)) - circle.ApproachCircle.FadeOut(50); - - break; - case DrawableSlider slider: - using (slider.BeginAbsoluteSequence(fadeOutStartTime, true)) - slider.Body.FadeOut(longFadeDuration, Easing.Out); - - break; - case DrawableSliderTick sliderTick: - // slider ticks fade out over up to one second - var tickFadeOutDuration = Math.Min(sliderTick.HitObject.TimePreempt - DrawableSliderTick.ANIM_DURATION, 1000); - - using (sliderTick.BeginAbsoluteSequence(sliderTick.HitObject.StartTime - tickFadeOutDuration, true)) - sliderTick.FadeOut(tickFadeOutDuration); - - break; - case DrawableSpinner spinner: - // hide elements we don't care about. - spinner.Disc.Hide(); - spinner.Ticks.Hide(); - spinner.Background.Hide(); - - using (spinner.BeginAbsoluteSequence(fadeOutStartTime + longFadeDuration, true)) - spinner.FadeOut(h.TimePreempt); - - break; + circle.circle.Hide(); // CirclePiece + circle.circle.AlwaysPresent = true; + circle.ring.Hide(); + circle.flash.Hide(); + circle.explode.Hide(); + circle.number.Hide(); + circle.glow.Hide(); + circle.ApproachCircle.Show(); } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 67c8371340..31c86474cd 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -17,12 +17,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public class DrawableHitCircle : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach { public ApproachCircle ApproachCircle; - private readonly CirclePiece circle; - private readonly RingPiece ring; - private readonly FlashPiece flash; - private readonly ExplodePiece explode; - private readonly NumberPiece number; - private readonly GlowPiece glow; + public readonly CirclePiece circle; + public readonly RingPiece ring; + public readonly FlashPiece flash; + public readonly ExplodePiece explode; + public readonly NumberPiece number; + public readonly GlowPiece glow; private readonly IBindable positionBindable = new Bindable(); private readonly IBindable stackHeightBindable = new Bindable(); @@ -113,17 +113,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } } - public void HideButApproachCircle() - { - circle.Hide(); - circle.AlwaysPresent = true; - ring.Hide(); - flash.Hide(); - explode.Hide(); - number.Hide(); - glow.Hide(); - } - protected override void CheckForResult(bool userTriggered, double timeOffset) { if (!userTriggered) diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index dedd397fa5..0eca1bcbec 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -112,7 +112,7 @@ namespace osu.Game.Overlays.Mods if (selected == null) continue; foreach (var type in modTypes) - if (type.IsInstanceOfType(selected)) + if (type.IsInstanceOfType(selected) && !selected.GetType().IsSubclassOf(type)) { if (immediate) button.Deselect(); @@ -130,7 +130,7 @@ namespace osu.Game.Overlays.Mods { foreach (var button in buttons) { - int i = Array.FindIndex(button.Mods, m => modTypes.Any(t => t.IsInstanceOfType(m))); + int i = Array.FindIndex(button.Mods, m => modTypes.Any(t => t.IsInstanceOfType(m) && !m.GetType().IsSubclassOf(t))); if (i >= 0) button.SelectAt(i); From d753f446e4fb995ea8ad403c851e22ff9bf46d13 Mon Sep 17 00:00:00 2001 From: MaxOhn Date: Mon, 1 Jul 2019 20:20:25 +0200 Subject: [PATCH 05/48] Updated license header --- osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index 858b7e15c8..fe1b20c0cc 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -1,5 +1,5 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. using System; using System.Linq; From 4145173ac905e0b3eef36e77ae542695dc68712c Mon Sep 17 00:00:00 2001 From: MaxOhn Date: Tue, 2 Jul 2019 04:04:07 +0200 Subject: [PATCH 06/48] Combined hidden with traceable as multi mod --- osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs | 1 - osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 22 +++++---- .../Objects/Drawables/DrawableHitCircle.cs | 48 +++++++++---------- osu.Game.Rulesets.Osu/OsuRuleset.cs | 4 +- .../TestSceneModSelectOverlay.cs | 5 +- osu.Game/Overlays/Mods/ModSection.cs | 6 ++- 6 files changed, 44 insertions(+), 42 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs index 5887cb2865..2723be9df8 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs @@ -17,7 +17,6 @@ namespace osu.Game.Rulesets.Osu.Mods { public override string Description => @"Play with no approach circles and fading circles/sliders."; public override double ScoreMultiplier => 1.06; - public override Type[] IncompatibleMods => new[] { typeof(OsuModTraceable) }; private const double fade_in_duration_multiplier = 0.4; private const double fade_out_duration_multiplier = 0.3; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index fe1b20c0cc..64a331213f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -11,15 +11,15 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Mods { - internal class OsuModTraceable : OsuModHidden, IReadFromConfig, IApplicableToDrawableHitObjects + internal class OsuModTraceable : OsuModHidden { public override string Name => "Traceable"; public override string Acronym => "TC"; public override IconUsage Icon => FontAwesome.Brands.SnapchatGhost; - public override ModType Type => ModType.Fun; + public override ModType Type => ModType.DifficultyIncrease; public override string Description => "Put your faith in the approach circles..."; public override double ScoreMultiplier => 1; - public override Type[] IncompatibleMods => new[] { typeof(OsuModHidden), typeof(OsuModGrow) }; + public override Type[] IncompatibleMods => new[] { typeof(OsuModGrow) }; public override void ApplyToDrawableHitObjects(IEnumerable drawables) { @@ -30,10 +30,12 @@ namespace osu.Game.Rulesets.Osu.Mods case DrawableHitCircle _: drawable.ApplyCustomUpdateState += ApplyTraceableState; break; + case DrawableSlider slider: slider.ApplyCustomUpdateState += ApplyHiddenState; slider.HeadCircle.ApplyCustomUpdateState += ApplyTraceableState; break; + default: drawable.ApplyCustomUpdateState += ApplyHiddenState; break; @@ -51,13 +53,13 @@ namespace osu.Game.Rulesets.Osu.Mods // we only want to see the approach circle using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) { - circle.circle.Hide(); // CirclePiece - circle.circle.AlwaysPresent = true; - circle.ring.Hide(); - circle.flash.Hide(); - circle.explode.Hide(); - circle.number.Hide(); - circle.glow.Hide(); + circle.Circle.Hide(); // CirclePiece + circle.Circle.AlwaysPresent = true; + circle.Ring.Hide(); + circle.Flash.Hide(); + circle.Explode.Hide(); + circle.Number.Hide(); + circle.Glow.Hide(); circle.ApproachCircle.Show(); } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 31c86474cd..e8a2f94c14 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -17,18 +17,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public class DrawableHitCircle : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach { public ApproachCircle ApproachCircle; - public readonly CirclePiece circle; - public readonly RingPiece ring; - public readonly FlashPiece flash; - public readonly ExplodePiece explode; - public readonly NumberPiece number; - public readonly GlowPiece glow; + public readonly CirclePiece Circle; + public readonly RingPiece Ring; + public readonly FlashPiece Flash; + public readonly ExplodePiece Explode; + public readonly NumberPiece Number; + public readonly GlowPiece Glow; private readonly IBindable positionBindable = new Bindable(); private readonly IBindable stackHeightBindable = new Bindable(); private readonly IBindable scaleBindable = new Bindable(); - public OsuAction? HitAction => circle.HitAction; + public OsuAction? HitAction => Circle.HitAction; private readonly Container explodeContainer; @@ -55,8 +55,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Anchor = Anchor.Centre, Children = new Drawable[] { - glow = new GlowPiece(), - circle = new CirclePiece + Glow = new GlowPiece(), + Circle = new CirclePiece { Hit = () => { @@ -67,13 +67,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables return true; }, }, - number = new NumberPiece + Number = new NumberPiece { Text = (HitObject.IndexInCurrentCombo + 1).ToString(), }, - ring = new RingPiece(), - flash = new FlashPiece(), - explode = new ExplodePiece(), + Ring = new RingPiece(), + Flash = new FlashPiece(), + Explode = new ExplodePiece(), ApproachCircle = new ApproachCircle { Alpha = 0, @@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables }; //may not be so correct - Size = circle.DrawSize; + Size = Circle.DrawSize; } [BackgroundDependencyLoader] @@ -106,9 +106,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables set { base.AccentColour = value; - explode.Colour = AccentColour; - glow.Colour = AccentColour; - circle.Colour = AccentColour; + Explode.Colour = AccentColour; + Glow.Colour = AccentColour; + Circle.Colour = AccentColour; ApproachCircle.Colour = AccentColour; } } @@ -145,7 +145,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void UpdateCurrentState(ArmedState state) { - glow.FadeOut(400); + Glow.FadeOut(400); switch (state) { @@ -154,7 +154,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Expire(true); - circle.HitAction = null; + Circle.HitAction = null; // override lifetime end as FadeIn may have been changed externally, causing out expiration to be too early. LifetimeEnd = HitObject.StartTime + HitObject.HitWindows.HalfWindowFor(HitResult.Miss); @@ -170,18 +170,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables ApproachCircle.FadeOut(50); const double flash_in = 40; - flash.FadeTo(0.8f, flash_in) + Flash.FadeTo(0.8f, flash_in) .Then() .FadeOut(100); - explode.FadeIn(flash_in); + Explode.FadeIn(flash_in); using (BeginDelayedSequence(flash_in, true)) { //after the flash, we can hide some elements that were behind it - ring.FadeOut(); - circle.FadeOut(); - number.FadeOut(); + Ring.FadeOut(); + Circle.FadeOut(); + Number.FadeOut(); this.FadeOut(800); explodeContainer.ScaleTo(1.5f, 400, Easing.OutQuad); diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 169d54d64a..9c48169a24 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Osu new OsuModHardRock(), new MultiMod(new OsuModSuddenDeath(), new OsuModPerfect()), new MultiMod(new OsuModDoubleTime(), new OsuModNightcore()), - new OsuModHidden(), + new MultiMod(new OsuModHidden(), new OsuModTraceable()), new MultiMod(new OsuModFlashlight(), new OsuModBlinds()), }; @@ -136,8 +136,6 @@ namespace osu.Game.Rulesets.Osu new OsuModWiggle(), new OsuModGrow(), new MultiMod(new ModWindUp(), new ModWindDown()), - - new OsuModTraceable(), }; default: diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 80408ab43b..9074b64eb8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -85,7 +85,7 @@ namespace osu.Game.Tests.Visual.UserInterface var assistMods = instance.GetModsFor(ModType.Automation); var noFailMod = easierMods.FirstOrDefault(m => m is OsuModNoFail); - var hiddenMod = harderMods.FirstOrDefault(m => m is OsuModHidden); + var hiddenMod = harderMods.OfType().FirstOrDefault(m => m.Mods.Any(a => a is OsuModHidden)); var doubleTimeMod = harderMods.OfType().FirstOrDefault(m => m.Mods.Any(a => a is OsuModDoubleTime)); @@ -96,10 +96,11 @@ namespace osu.Game.Tests.Visual.UserInterface testSingleMod(noFailMod); testMultiMod(doubleTimeMod); + testMultiMod(hiddenMod); testIncompatibleMods(easy, hardRock); testDeselectAll(easierMods.Where(m => !(m is MultiMod))); testMultiplierTextColour(noFailMod, modSelect.LowMultiplierColour); - testMultiplierTextColour(hiddenMod, modSelect.HighMultiplierColour); + testMultiplierTextColour(hardRock, modSelect.HighMultiplierColour); testUnimplementedMod(autoPilotMod); } diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index 0eca1bcbec..5c2ab8e18c 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -112,13 +112,15 @@ namespace osu.Game.Overlays.Mods if (selected == null) continue; foreach (var type in modTypes) - if (type.IsInstanceOfType(selected) && !selected.GetType().IsSubclassOf(type)) + { + if (type.IsInstanceOfType(selected)) { if (immediate) button.Deselect(); else Scheduler.AddDelayed(button.Deselect, delay += 50); } + } } } @@ -130,7 +132,7 @@ namespace osu.Game.Overlays.Mods { foreach (var button in buttons) { - int i = Array.FindIndex(button.Mods, m => modTypes.Any(t => t.IsInstanceOfType(m) && !m.GetType().IsSubclassOf(t))); + int i = Array.FindIndex(button.Mods, m => modTypes.Any(t => t.IsInstanceOfType(m))); if (i >= 0) button.SelectAt(i); From 664257fbbe31f7b1617fc55527e59a088dc5c259 Mon Sep 17 00:00:00 2001 From: MaxOhn Date: Wed, 3 Jul 2019 18:42:02 +0200 Subject: [PATCH 07/48] Sliders no longer modified by HD but have transparent body now --- osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs | 1 - osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 60 ++++++++++--------- osu.Game/Overlays/Mods/ModSection.cs | 2 - 3 files changed, 31 insertions(+), 32 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs index 2723be9df8..ddf708d0f1 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs @@ -17,7 +17,6 @@ namespace osu.Game.Rulesets.Osu.Mods { public override string Description => @"Play with no approach circles and fading circles/sliders."; public override double ScoreMultiplier => 1.06; - private const double fade_in_duration_multiplier = 0.4; private const double fade_out_duration_multiplier = 0.3; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index 64a331213f..8ccff6b258 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; +using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Mods { @@ -24,43 +25,44 @@ namespace osu.Game.Rulesets.Osu.Mods public override void ApplyToDrawableHitObjects(IEnumerable drawables) { foreach (var drawable in drawables.Skip(IncreaseFirstObjectVisibility.Value ? 1 : 0)) - { - switch (drawable) - { - case DrawableHitCircle _: - drawable.ApplyCustomUpdateState += ApplyTraceableState; - break; - - case DrawableSlider slider: - slider.ApplyCustomUpdateState += ApplyHiddenState; - slider.HeadCircle.ApplyCustomUpdateState += ApplyTraceableState; - break; - - default: - drawable.ApplyCustomUpdateState += ApplyHiddenState; - break; - } - } + drawable.ApplyCustomUpdateState += ApplyTraceableState; } protected void ApplyTraceableState(DrawableHitObject drawable, ArmedState state) { - if (!(drawable is DrawableHitCircle circle)) + if (!(drawable is DrawableOsuHitObject d)) return; - var h = circle.HitObject; + var h = d.HitObject; - // we only want to see the approach circle - using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) + switch (drawable) { - circle.Circle.Hide(); // CirclePiece - circle.Circle.AlwaysPresent = true; - circle.Ring.Hide(); - circle.Flash.Hide(); - circle.Explode.Hide(); - circle.Number.Hide(); - circle.Glow.Hide(); - circle.ApproachCircle.Show(); + case DrawableHitCircle circle: + // we only want to see the approach circle + using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) + { + circle.Circle.Hide(); // CirclePiece + circle.Circle.AlwaysPresent = true; + circle.Ring.Hide(); + circle.Flash.Hide(); + circle.Explode.Hide(); + circle.Number.Hide(); + circle.Glow.Hide(); + circle.ApproachCircle.Show(); + } + + break; + + case DrawableSlider slider: + ApplyTraceableState(slider.HeadCircle, state); + slider.Body.AccentColour = Color4.Transparent; + + break; + + default: + ApplyHiddenState(drawable, state); + + break; } } } diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index 5c2ab8e18c..dedd397fa5 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -112,7 +112,6 @@ namespace osu.Game.Overlays.Mods if (selected == null) continue; foreach (var type in modTypes) - { if (type.IsInstanceOfType(selected)) { if (immediate) @@ -120,7 +119,6 @@ namespace osu.Game.Overlays.Mods else Scheduler.AddDelayed(button.Deselect, delay += 50); } - } } } From 5b4640d3ead5a89f31cb30b95c2234e79beb03c4 Mon Sep 17 00:00:00 2001 From: MaxOhn Date: Wed, 3 Jul 2019 21:40:14 +0200 Subject: [PATCH 08/48] Traceable no longer inherits from OsuModHidden and is no longer multi mod --- osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs | 1 + osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 24 +++++++++++++------ .../Mods/OsuModeObjectScaleTween.cs | 2 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 3 ++- .../TestSceneModSelectOverlay.cs | 5 ++-- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs index ddf708d0f1..74f9398f18 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs @@ -17,6 +17,7 @@ namespace osu.Game.Rulesets.Osu.Mods { public override string Description => @"Play with no approach circles and fading circles/sliders."; public override double ScoreMultiplier => 1.06; + public override Type[] IncompatibleMods => new[] { typeof(OsuModTraceable) }; private const double fade_in_duration_multiplier = 0.4; private const double fade_out_duration_multiplier = 0.3; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index c5b5a064a6..1d68793c50 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -3,8 +3,10 @@ using System; using System.Linq; +using osu.Framework.Bindables; using System.Collections.Generic; using osu.Framework.Graphics.Sprites; +using osu.Game.Configuration; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; @@ -12,19 +14,25 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Mods { - internal class OsuModTraceable : OsuModHidden + internal class OsuModTraceable : Mod, IReadFromConfig, IApplicableToDrawableHitObjects { public override string Name => "Traceable"; public override string Acronym => "TC"; public override IconUsage Icon => FontAwesome.Brands.SnapchatGhost; - public override ModType Type => ModType.DifficultyIncrease; + public override ModType Type => ModType.Fun; public override string Description => "Put your faith in the approach circles..."; public override double ScoreMultiplier => 1; - public override Type[] IncompatibleMods => new[] { typeof(OsuModeObjectScaleTween) }; + public override Type[] IncompatibleMods => new[] { typeof(OsuModHidden), typeof(OsuModeObjectScaleTween) }; + private Bindable increaseFirstObjectVisibility = new Bindable(); - public override void ApplyToDrawableHitObjects(IEnumerable drawables) + public void ReadFromConfig(OsuConfigManager config) { - foreach (var drawable in drawables.Skip(IncreaseFirstObjectVisibility.Value ? 1 : 0)) + increaseFirstObjectVisibility = config.GetBindable(OsuSetting.IncreaseFirstObjectVisibility); + } + + public void ApplyToDrawableHitObjects(IEnumerable drawables) + { + foreach (var drawable in drawables.Skip(increaseFirstObjectVisibility.Value ? 1 : 0)) drawable.ApplyCustomUpdateState += ApplyTraceableState; } @@ -59,8 +67,10 @@ namespace osu.Game.Rulesets.Osu.Mods break; - default: - ApplyHiddenState(drawable, state); + case DrawableSpinner spinner: + spinner.Disc.Hide(); + //spinner.Ticks.Hide(); // do they contribute to the theme? debatable + spinner.Background.Hide(); break; } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs b/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs index de277100b5..db61c15846 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1; - public override Type[] IncompatibleMods => new[] { typeof(OsuModeObjectScaleTween) }; + public override Type[] IncompatibleMods => new[] { typeof(OsuModTraceable) }; protected virtual float StartScale => 1; diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 949b473ca6..c0e2809b38 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Osu new OsuModHardRock(), new MultiMod(new OsuModSuddenDeath(), new OsuModPerfect()), new MultiMod(new OsuModDoubleTime(), new OsuModNightcore()), - new MultiMod(new OsuModHidden(), new OsuModTraceable()), + new OsuModHidden(), new MultiMod(new OsuModFlashlight(), new OsuModBlinds()), }; @@ -136,6 +136,7 @@ namespace osu.Game.Rulesets.Osu new OsuModWiggle(), new MultiMod(new OsuModGrow(), new OsuModDeflate()), new MultiMod(new ModWindUp(), new ModWindDown()), + new OsuModTraceable(), }; default: diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 9074b64eb8..80408ab43b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -85,7 +85,7 @@ namespace osu.Game.Tests.Visual.UserInterface var assistMods = instance.GetModsFor(ModType.Automation); var noFailMod = easierMods.FirstOrDefault(m => m is OsuModNoFail); - var hiddenMod = harderMods.OfType().FirstOrDefault(m => m.Mods.Any(a => a is OsuModHidden)); + var hiddenMod = harderMods.FirstOrDefault(m => m is OsuModHidden); var doubleTimeMod = harderMods.OfType().FirstOrDefault(m => m.Mods.Any(a => a is OsuModDoubleTime)); @@ -96,11 +96,10 @@ namespace osu.Game.Tests.Visual.UserInterface testSingleMod(noFailMod); testMultiMod(doubleTimeMod); - testMultiMod(hiddenMod); testIncompatibleMods(easy, hardRock); testDeselectAll(easierMods.Where(m => !(m is MultiMod))); testMultiplierTextColour(noFailMod, modSelect.LowMultiplierColour); - testMultiplierTextColour(hardRock, modSelect.HighMultiplierColour); + testMultiplierTextColour(hiddenMod, modSelect.HighMultiplierColour); testUnimplementedMod(autoPilotMod); } From 581ffb7fb09d50fc0b64bb422841f830c61d1ac7 Mon Sep 17 00:00:00 2001 From: MaxOhn Date: Mon, 8 Jul 2019 13:52:15 +0200 Subject: [PATCH 09/48] Adjusted slider border colour --- osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index 1d68793c50..4918ea60b2 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -64,14 +64,13 @@ namespace osu.Game.Rulesets.Osu.Mods case DrawableSlider slider: ApplyTraceableState(slider.HeadCircle, state); slider.Body.AccentColour = Color4.Transparent; - + slider.Body.BorderColour = slider.HeadCircle.AccentColour; break; case DrawableSpinner spinner: spinner.Disc.Hide(); //spinner.Ticks.Hide(); // do they contribute to the theme? debatable spinner.Background.Hide(); - break; } } From 9951011e6c5d469f149ee9b0d08405f0afb6a250 Mon Sep 17 00:00:00 2001 From: miterosan Date: Sun, 8 Sep 2019 16:27:25 +0200 Subject: [PATCH 10/48] Remove not needed androidnativelibrary itemgroup --- osu.Android.props | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Android.props b/osu.Android.props index adc340a734..51bfdca064 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -49,7 +49,6 @@ osu.licenseheader - From f9c969788a758f913001047dca99aff00a853de8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Sep 2019 13:56:23 +0900 Subject: [PATCH 11/48] Fix keys not reaching full brightness as soon as they should --- osu.Game/Screens/Play/KeyCounter.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs index 88a62ac8d4..ad5fcfcf24 100644 --- a/osu.Game/Screens/Play/KeyCounter.cs +++ b/osu.Game/Screens/Play/KeyCounter.cs @@ -130,15 +130,17 @@ namespace osu.Game.Screens.Play private void updateGlowSprite(bool show) { + double remainingFadeTime = FadeTime * (1 - glowSprite.Alpha); + if (show) { - glowSprite.FadeIn(FadeTime); - textLayer.FadeColour(KeyDownTextColor, FadeTime); + glowSprite.FadeIn(remainingFadeTime); + textLayer.FadeColour(KeyDownTextColor, remainingFadeTime); } else { - glowSprite.FadeOut(FadeTime); - textLayer.FadeColour(KeyUpTextColor, FadeTime); + glowSprite.FadeOut(remainingFadeTime); + textLayer.FadeColour(KeyUpTextColor, remainingFadeTime); } } From 158737e001e46bdfd4f8ed85a48ab53ba81f70a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Sep 2019 14:27:29 +0900 Subject: [PATCH 12/48] Remove FadeTime customisation Also adjusts fade transitions to feel better, especially in fast forward scenarios. --- .../Visual/Gameplay/TestSceneKeyCounter.cs | 1 - osu.Game/Screens/Play/HUDOverlay.cs | 1 - osu.Game/Screens/Play/KeyCounter.cs | 14 +++++------ osu.Game/Screens/Play/KeyCounterDisplay.cs | 25 ++----------------- 4 files changed, 9 insertions(+), 32 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs index 18088a9a5b..4643b82792 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs @@ -44,7 +44,6 @@ namespace osu.Game.Tests.Visual.Gameplay Key key = (Key)((int)Key.A + RNG.Next(26)); kc.Add(new KeyCounterKeyboard(key)); }); - AddSliderStep("Fade time", 0, 200, 50, v => kc.FadeTime = v); Key testKey = ((KeyCounterKeyboard)kc.Children.First()).Key; double time1 = 0; diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index eee7235a6e..0f9edf5606 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -231,7 +231,6 @@ namespace osu.Game.Screens.Play protected virtual KeyCounterDisplay CreateKeyCounter() => new KeyCounterDisplay { - FadeTime = 50, Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, Margin = new MarginPadding(10), diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs index ad5fcfcf24..1930369299 100644 --- a/osu.Game/Screens/Play/KeyCounter.cs +++ b/osu.Game/Screens/Play/KeyCounter.cs @@ -65,7 +65,7 @@ namespace osu.Game.Screens.Play //further: change default values here and in KeyCounterCollection if needed, instead of passing them in every constructor public Color4 KeyDownTextColor { get; set; } = Color4.DarkGray; public Color4 KeyUpTextColor { get; set; } = Color4.White; - public int FadeTime { get; set; } + public double FadeTime { get; set; } protected KeyCounter(string name) { @@ -130,17 +130,17 @@ namespace osu.Game.Screens.Play private void updateGlowSprite(bool show) { - double remainingFadeTime = FadeTime * (1 - glowSprite.Alpha); - if (show) { - glowSprite.FadeIn(remainingFadeTime); - textLayer.FadeColour(KeyDownTextColor, remainingFadeTime); + double remainingFadeTime = FadeTime * (1 - glowSprite.Alpha); + glowSprite.FadeIn(remainingFadeTime, Easing.OutQuint); + textLayer.FadeColour(KeyDownTextColor, remainingFadeTime, Easing.OutQuint); } else { - glowSprite.FadeOut(remainingFadeTime); - textLayer.FadeColour(KeyUpTextColor, remainingFadeTime); + double remainingFadeTime = 8 * FadeTime * glowSprite.Alpha; + glowSprite.FadeOut(remainingFadeTime, Easing.OutQuint); + textLayer.FadeColour(KeyUpTextColor, remainingFadeTime, Easing.OutQuint); } } diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs index d5967f5899..6b8fa5c75b 100644 --- a/osu.Game/Screens/Play/KeyCounterDisplay.cs +++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs @@ -17,6 +17,7 @@ namespace osu.Game.Screens.Play public class KeyCounterDisplay : FillFlowContainer { private const int duration = 100; + private const double key_fade_time = 80; public readonly Bindable Visible = new Bindable(true); private readonly Bindable configVisibility = new Bindable(); @@ -33,17 +34,11 @@ namespace osu.Game.Screens.Play base.Add(key); key.IsCounting = IsCounting; - key.FadeTime = FadeTime; + key.FadeTime = key_fade_time; key.KeyDownTextColor = KeyDownTextColor; key.KeyUpTextColor = KeyUpTextColor; } - public void ResetCount() - { - foreach (var counter in Children) - counter.ResetCount(); - } - [BackgroundDependencyLoader] private void load(OsuConfigManager config) { @@ -68,22 +63,6 @@ namespace osu.Game.Screens.Play } } - private int fadeTime; - - public int FadeTime - { - get => fadeTime; - set - { - if (value != fadeTime) - { - fadeTime = value; - foreach (var child in Children) - child.FadeTime = value; - } - } - } - private Color4 keyDownTextColor = Color4.DarkGray; public Color4 KeyDownTextColor From cb0cf6e2c5e14e37d37716a79cec9b02b89d2aae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Sep 2019 14:27:52 +0900 Subject: [PATCH 13/48] Remove reset functions --- osu.Game/Screens/Play/KeyCounter.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs index 1930369299..ad0858184e 100644 --- a/osu.Game/Screens/Play/KeyCounter.cs +++ b/osu.Game/Screens/Play/KeyCounter.cs @@ -144,12 +144,6 @@ namespace osu.Game.Screens.Play } } - public void ResetCount() - { - CountPresses = 0; - states.Clear(); - } - protected override void Update() { base.Update(); From 0cdf125c1e8f64fc5397fc1701e42cb21d1adaf2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Sep 2019 15:41:53 +0900 Subject: [PATCH 14/48] Handle key counter rewinding in a better way Use ElapsedFrameTime rather than storing state data --- .../Visual/Gameplay/TestSceneKeyCounter.cs | 40 ++------------- osu.Game/Rulesets/UI/RulesetInputManager.cs | 4 +- osu.Game/Screens/Play/KeyCounter.cs | 49 ++++++------------- osu.Game/Screens/Play/KeyCounterAction.cs | 22 ++++++--- osu.Game/Screens/Play/KeyCounterDisplay.cs | 5 -- osu.Game/Screens/Play/KeyCounterKeyboard.cs | 7 ++- osu.Game/Screens/Play/KeyCounterMouse.cs | 7 ++- 7 files changed, 50 insertions(+), 84 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs index 4643b82792..6783a36ac3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs @@ -7,7 +7,6 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.MathUtils; -using osu.Framework.Timing; using osu.Game.Screens.Play; using osuTK.Input; @@ -25,14 +24,15 @@ namespace osu.Game.Tests.Visual.Gameplay public TestSceneKeyCounter() { - KeyCounterKeyboard rewindTestKeyCounterKeyboard; + KeyCounterKeyboard testCounter; + KeyCounterDisplay kc = new KeyCounterDisplay { Origin = Anchor.Centre, Anchor = Anchor.Centre, Children = new KeyCounter[] { - rewindTestKeyCounterKeyboard = new KeyCounterKeyboard(Key.X), + testCounter = new KeyCounterKeyboard(Key.X), new KeyCounterKeyboard(Key.X), new KeyCounterMouse(MouseButton.Left), new KeyCounterMouse(MouseButton.Right), @@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.Gameplay InputManager.ReleaseKey(testKey); }); - AddAssert($"Check {testKey} counter after keypress", () => rewindTestKeyCounterKeyboard.CountPresses == 1); + AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 1); AddStep($"Press {testKey} key", () => { @@ -63,39 +63,9 @@ namespace osu.Game.Tests.Visual.Gameplay time1 = Clock.CurrentTime; }); - AddAssert($"Check {testKey} counter after keypress", () => rewindTestKeyCounterKeyboard.CountPresses == 2); - - IFrameBasedClock oldClock = null; - - AddStep($"Rewind {testKey} counter once", () => - { - oldClock = rewindTestKeyCounterKeyboard.Clock; - rewindTestKeyCounterKeyboard.Clock = new FramedOffsetClock(new FixedClock(time1 - 10)); - }); - - AddAssert($"Check {testKey} counter after rewind", () => rewindTestKeyCounterKeyboard.CountPresses == 1); - - AddStep($"Rewind {testKey} counter to zero", () => rewindTestKeyCounterKeyboard.Clock = new FramedOffsetClock(new FixedClock(0))); - - AddAssert($"Check {testKey} counter after rewind", () => rewindTestKeyCounterKeyboard.CountPresses == 0); - - AddStep("Restore clock", () => rewindTestKeyCounterKeyboard.Clock = oldClock); + AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 2); Add(kc); } - - private class FixedClock : IClock - { - private readonly double time; - - public FixedClock(double time) - { - this.time = time; - } - - public double CurrentTime => time; - public double Rate => 1; - public bool IsRunning => false; - } } } diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index e25c3bd0e7..98e27240d3 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -137,9 +137,9 @@ namespace osu.Game.Rulesets.UI { } - public bool OnPressed(T action) => Target.Children.OfType>().Any(c => c.OnPressed(action)); + public bool OnPressed(T action) => Target.Children.OfType>().Any(c => c.OnPressed(action, Clock.ElapsedFrameTime > 0)); - public bool OnReleased(T action) => Target.Children.OfType>().Any(c => c.OnReleased(action)); + public bool OnReleased(T action) => Target.Children.OfType>().Any(c => c.OnReleased(action, Clock.ElapsedFrameTime > 0)); } #endregion diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs index ad0858184e..1daf89d8f9 100644 --- a/osu.Game/Screens/Play/KeyCounter.cs +++ b/osu.Game/Screens/Play/KeyCounter.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -22,9 +20,6 @@ namespace osu.Game.Screens.Play private Container textLayer; private SpriteText countSpriteText; - private readonly List states = new List(); - private KeyCounterState currentState; - public bool IsCounting { get; set; } = true; private int countPresses; @@ -52,16 +47,26 @@ namespace osu.Game.Screens.Play { isLit = value; updateGlowSprite(value); - - if (value && IsCounting) - { - CountPresses++; - saveState(); - } } } } + public void Increment() + { + if (!IsCounting) + return; + + CountPresses++; + } + + public void Decrement() + { + if (!IsCounting) + return; + + CountPresses--; + } + //further: change default values here and in KeyCounterCollection if needed, instead of passing them in every constructor public Color4 KeyDownTextColor { get; set; } = Color4.DarkGray; public Color4 KeyUpTextColor { get; set; } = Color4.White; @@ -143,27 +148,5 @@ namespace osu.Game.Screens.Play textLayer.FadeColour(KeyUpTextColor, remainingFadeTime, Easing.OutQuint); } } - - protected override void Update() - { - base.Update(); - - if (currentState?.Time > Clock.CurrentTime) - restoreStateTo(Clock.CurrentTime); - } - - private void saveState() - { - if (currentState == null || currentState.Time < Clock.CurrentTime) - states.Add(currentState = new KeyCounterState(Clock.CurrentTime, CountPresses)); - } - - private void restoreStateTo(double time) - { - states.RemoveAll(state => state.Time > time); - - currentState = states.LastOrDefault(); - CountPresses = currentState?.Count ?? 0; - } } } diff --git a/osu.Game/Screens/Play/KeyCounterAction.cs b/osu.Game/Screens/Play/KeyCounterAction.cs index 8deac653ad..f60ad7aa5a 100644 --- a/osu.Game/Screens/Play/KeyCounterAction.cs +++ b/osu.Game/Screens/Play/KeyCounterAction.cs @@ -1,11 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Input.Bindings; - namespace osu.Game.Screens.Play { - public class KeyCounterAction : KeyCounter, IKeyBindingHandler + public class KeyCounterAction : KeyCounter where T : struct { public T Action { get; } @@ -16,15 +14,25 @@ namespace osu.Game.Screens.Play Action = action; } - public bool OnPressed(T action) + public bool OnPressed(T action, bool forwards) { - if (action.Equals(Action)) IsLit = true; + if (!action.Equals(Action)) + return false; + + IsLit = true; + if (forwards) + Increment(); return false; } - public bool OnReleased(T action) + public bool OnReleased(T action, bool forwards) { - if (action.Equals(Action)) IsLit = false; + if (!action.Equals(Action)) + return false; + + IsLit = false; + if (!forwards) + Decrement(); return false; } } diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs index 6b8fa5c75b..1edb95ca46 100644 --- a/osu.Game/Screens/Play/KeyCounterDisplay.cs +++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs @@ -102,11 +102,6 @@ namespace osu.Game.Screens.Play private Receptor receptor; - public Receptor GetReceptor() - { - return receptor ?? (receptor = new Receptor(this)); - } - public void SetReceptor(Receptor receptor) { if (this.receptor != null) diff --git a/osu.Game/Screens/Play/KeyCounterKeyboard.cs b/osu.Game/Screens/Play/KeyCounterKeyboard.cs index d9b6dca79d..29188b6b59 100644 --- a/osu.Game/Screens/Play/KeyCounterKeyboard.cs +++ b/osu.Game/Screens/Play/KeyCounterKeyboard.cs @@ -18,7 +18,12 @@ namespace osu.Game.Screens.Play protected override bool OnKeyDown(KeyDownEvent e) { - if (e.Key == Key) IsLit = true; + if (e.Key == Key) + { + IsLit = true; + Increment(); + } + return base.OnKeyDown(e); } diff --git a/osu.Game/Screens/Play/KeyCounterMouse.cs b/osu.Game/Screens/Play/KeyCounterMouse.cs index 95fa58e5c0..828441de6e 100644 --- a/osu.Game/Screens/Play/KeyCounterMouse.cs +++ b/osu.Game/Screens/Play/KeyCounterMouse.cs @@ -36,7 +36,12 @@ namespace osu.Game.Screens.Play protected override bool OnMouseDown(MouseDownEvent e) { - if (e.Button == Button) IsLit = true; + if (e.Button == Button) + { + IsLit = true; + Increment(); + } + return base.OnMouseDown(e); } From 831d04f339402020b0467bd38a7b940ab8031638 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Sep 2019 15:48:07 +0900 Subject: [PATCH 15/48] Don't use gameplay clock in KeyCounter --- osu.Game/Screens/Play/KeyCounter.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs index 1daf89d8f9..f4109a63d0 100644 --- a/osu.Game/Screens/Play/KeyCounter.cs +++ b/osu.Game/Screens/Play/KeyCounter.cs @@ -78,11 +78,8 @@ namespace osu.Game.Screens.Play } [BackgroundDependencyLoader(true)] - private void load(TextureStore textures, GameplayClock clock) + private void load(TextureStore textures) { - if (clock != null) - Clock = clock; - Children = new Drawable[] { buttonSprite = new Sprite From 09a0c9f4d2fa8224651ff91d05881fe31f118ac1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Sep 2019 18:10:50 +0900 Subject: [PATCH 16/48] Add key counter rewind tests --- osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs | 9 ++++++++- .../Visual/Gameplay/TestSceneGameplayRewinding.cs | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs index 452ac859de..e2b620ea98 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs @@ -21,7 +21,12 @@ namespace osu.Game.Tests.Visual.Gameplay protected override void AddCheckSteps() { AddUntilStep("score above zero", () => ((ScoreAccessiblePlayer)Player).ScoreProcessor.TotalScore.Value > 0); - AddUntilStep("key counter counted keys", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0)); + AddUntilStep("key counter counted keys", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 5)); + AddStep("rewind", () => + { + ((ScoreAccessiblePlayer)Player).GameplayClockContainer.Seek(0); + }); + AddUntilStep("key counter counted no", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0)); } private class ScoreAccessiblePlayer : TestPlayer @@ -29,6 +34,8 @@ namespace osu.Game.Tests.Visual.Gameplay public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; public new HUDOverlay HUDOverlay => base.HUDOverlay; + public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer; + public ScoreAccessiblePlayer() : base(false, false) { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs index 237fee1594..ffc025a942 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs @@ -14,6 +14,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using osuTK; @@ -47,9 +48,11 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for track to start running", () => track.IsRunning); addSeekStep(3000); AddAssert("all judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged)); + AddUntilStep("key counter counted keys", () => player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses >= 7)); AddStep("clear results", () => player.AppliedResults.Clear()); addSeekStep(0); AddAssert("none judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => !h.Judged)); + AddUntilStep("key counters reset", () => player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0)); AddAssert("no results triggered", () => player.AppliedResults.Count == 0); } @@ -90,6 +93,10 @@ namespace osu.Game.Tests.Visual.Gameplay { public readonly List AppliedResults = new List(); + public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; + + public new HUDOverlay HUDOverlay => base.HUDOverlay; + public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer; public new DrawableRuleset DrawableRuleset => base.DrawableRuleset; From 68feedbd159b677879e77260b7f2b1f40e789185 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Sep 2019 18:46:42 +0900 Subject: [PATCH 17/48] Fix unreported CI issue --- osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs index 6783a36ac3..ad747e88e1 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs @@ -46,7 +46,6 @@ namespace osu.Game.Tests.Visual.Gameplay }); Key testKey = ((KeyCounterKeyboard)kc.Children.First()).Key; - double time1 = 0; AddStep($"Press {testKey} key", () => { @@ -60,7 +59,6 @@ namespace osu.Game.Tests.Visual.Gameplay { InputManager.PressKey(testKey); InputManager.ReleaseKey(testKey); - time1 = Clock.CurrentTime; }); AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 2); From 77947e83097164eb73adc4b380fd2b80fcf643e4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Sep 2019 22:33:27 +0900 Subject: [PATCH 18/48] Fix rewind tests failing --- .../Replays/CatchAutoGenerator.cs | 1 + .../Replays/ManiaAutoGenerator.cs | 1 + .../Visual/Gameplay/TestSceneAutoplay.cs | 19 ++++++++++++++----- osu.Game/Screens/Play/GameplayClock.cs | 2 ++ osu.Game/Tests/Visual/OsuTestScene.cs | 4 ++-- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs index 4ea1f22006..7f972a25ae 100644 --- a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs +++ b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs @@ -39,6 +39,7 @@ namespace osu.Game.Rulesets.Catch.Replays // Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled addFrame(-100000, lastPosition); + addFrame(0, lastPosition); void moveToNext(CatchHitObject h) { diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index 7b8bbc2095..5d333e2047 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -49,6 +49,7 @@ namespace osu.Game.Rulesets.Mania.Replays { // Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled Replay.Frames.Add(new ManiaReplayFrame(-100000, 0)); + Replay.Frames.Add(new ManiaReplayFrame(0, 0)); var pointGroups = generateActionPoints().GroupBy(a => a.Time).OrderBy(g => g.First().Time); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs index e2b620ea98..883aa9fc36 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Linq; +using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play; @@ -12,6 +13,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Description("Player instantiated with an autoplay mod.")] public class TestSceneAutoplay : AllPlayersTestScene { + private ClockBackedTestWorkingBeatmap.TrackVirtualManual track; + protected override Player CreatePlayer(Ruleset ruleset) { Mods.Value = Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray(); @@ -22,11 +25,17 @@ namespace osu.Game.Tests.Visual.Gameplay { AddUntilStep("score above zero", () => ((ScoreAccessiblePlayer)Player).ScoreProcessor.TotalScore.Value > 0); AddUntilStep("key counter counted keys", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 5)); - AddStep("rewind", () => - { - ((ScoreAccessiblePlayer)Player).GameplayClockContainer.Seek(0); - }); - AddUntilStep("key counter counted no", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0)); + AddStep("rewind", () => track.Seek(-10000)); + AddUntilStep("key counter reset", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0)); + } + + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) + { + var working = base.CreateWorkingBeatmap(beatmap); + + track = (ClockBackedTestWorkingBeatmap.TrackVirtualManual)working.Track; + + return working; } private class ScoreAccessiblePlayer : TestPlayer diff --git a/osu.Game/Screens/Play/GameplayClock.cs b/osu.Game/Screens/Play/GameplayClock.cs index b1948d02d5..379c4c89ed 100644 --- a/osu.Game/Screens/Play/GameplayClock.cs +++ b/osu.Game/Screens/Play/GameplayClock.cs @@ -42,5 +42,7 @@ namespace osu.Game.Screens.Play public double FramesPerSecond => underlyingClock.FramesPerSecond; public FrameTimeInfo TimeInfo => underlyingClock.TimeInfo; + + public IClock Source => underlyingClock; } } diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 2b8baab57c..32a32cfa43 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -239,7 +239,7 @@ namespace osu.Game.Tests.Visual public override bool Seek(double seek) { - offset = MathHelper.Clamp(seek, 0, Length); + offset = Math.Min(seek, Length); lastReferenceTime = null; return offset == seek; From 057c4aa795657654822ce73c086352e75a9677f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Sep 2019 22:42:20 +0900 Subject: [PATCH 19/48] Remove unused using statement --- osu.Game/Tests/Visual/OsuTestScene.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 32a32cfa43..2bc9273f69 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -20,7 +20,6 @@ using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Tests.Beatmaps; -using osuTK; namespace osu.Game.Tests.Visual { From 3ab352ffe51b0a37fef9af64569b91c9bbc0d2b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Sep 2019 23:08:37 +0900 Subject: [PATCH 20/48] Randomise beatmap playback order on startup Closes #6135. --- osu.Game/Overlays/Music/PlaylistList.cs | 18 ++++++++++-------- osu.Game/Overlays/MusicController.cs | 21 +++++++++++---------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 539601c359..6ad0aa23ec 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; @@ -44,6 +45,8 @@ namespace osu.Game.Overlays.Music private class ItemsScrollContainer : OsuScrollContainer { + private BindableList beatmaps; + public Action Selected; public Action OrderChanged; @@ -73,20 +76,19 @@ namespace osu.Game.Overlays.Music } [BackgroundDependencyLoader] - private void load(BeatmapManager beatmaps, IBindable beatmap) + private void load(MusicController musicController, IBindable beatmap) { - beatmaps.GetAllUsableBeatmapSets().ForEach(addBeatmapSet); - beatmaps.ItemAdded += addBeatmapSet; - beatmaps.ItemRemoved += removeBeatmapSet; + beatmaps = musicController.BeatmapSets.GetBoundCopy(); + + beatmaps.ItemsAdded += i => i.ForEach(addBeatmapSet); + beatmaps.ItemsRemoved += i => i.ForEach(removeBeatmapSet); + beatmaps.ForEach(addBeatmapSet); beatmapBacking.BindTo(beatmap); beatmapBacking.ValueChanged += _ => updateSelectedSet(); } - private void addBeatmapSet(BeatmapSetInfo obj) => Schedule(() => - { - items.Insert(items.Count - 1, new PlaylistItem(obj) { OnSelect = set => Selected?.Invoke(set) }); - }); + private void addBeatmapSet(BeatmapSetInfo obj) => Schedule(() => { items.Insert(items.Count - 1, new PlaylistItem(obj) { OnSelect = set => Selected?.Invoke(set) }); }); private void removeBeatmapSet(BeatmapSetInfo obj) => Schedule(() => { diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 6ad147735b..92246dfc62 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Input.Bindings; +using osu.Framework.MathUtils; using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Input.Bindings; @@ -24,7 +25,7 @@ namespace osu.Game.Overlays [Resolved] private BeatmapManager beatmaps { get; set; } - private List beatmapSets; + public readonly BindableList BeatmapSets = new BindableList(); public bool IsUserPaused { get; private set; } @@ -46,7 +47,7 @@ namespace osu.Game.Overlays [BackgroundDependencyLoader] private void load() { - beatmapSets = beatmaps.GetAllUsableBeatmapSets(); + BeatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets().OrderBy(_ => RNG.Next())); beatmaps.ItemAdded += handleBeatmapAdded; beatmaps.ItemRemoved += handleBeatmapRemoved; } @@ -65,8 +66,8 @@ namespace osu.Game.Overlays /// The new position. public void ChangeBeatmapSetPosition(BeatmapSetInfo beatmapSetInfo, int index) { - beatmapSets.Remove(beatmapSetInfo); - beatmapSets.Insert(index, beatmapSetInfo); + BeatmapSets.Remove(beatmapSetInfo); + BeatmapSets.Insert(index, beatmapSetInfo); } /// @@ -75,10 +76,10 @@ namespace osu.Game.Overlays public bool IsPlaying => beatmap.Value.Track.IsRunning; private void handleBeatmapAdded(BeatmapSetInfo set) => - Schedule(() => beatmapSets.Add(set)); + Schedule(() => BeatmapSets.Add(set)); private void handleBeatmapRemoved(BeatmapSetInfo set) => - Schedule(() => beatmapSets.RemoveAll(s => s.ID == set.ID)); + Schedule(() => BeatmapSets.RemoveAll(s => s.ID == set.ID)); private ScheduledDelegate seekDelegate; @@ -140,7 +141,7 @@ namespace osu.Game.Overlays { queuedDirection = TrackChangeDirection.Prev; - var playable = beatmapSets.TakeWhile(i => i.ID != current.BeatmapSetInfo.ID).LastOrDefault() ?? beatmapSets.LastOrDefault(); + var playable = BeatmapSets.TakeWhile(i => i.ID != current.BeatmapSetInfo.ID).LastOrDefault() ?? BeatmapSets.LastOrDefault(); if (playable != null) { @@ -165,7 +166,7 @@ namespace osu.Game.Overlays if (!instant) queuedDirection = TrackChangeDirection.Next; - var playable = beatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).Skip(1).FirstOrDefault() ?? beatmapSets.FirstOrDefault(); + var playable = BeatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).Skip(1).FirstOrDefault() ?? BeatmapSets.FirstOrDefault(); if (playable != null) { @@ -200,8 +201,8 @@ namespace osu.Game.Overlays else { //figure out the best direction based on order in playlist. - var last = beatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo?.ID).Count(); - var next = beatmap.NewValue == null ? -1 : beatmapSets.TakeWhile(b => b.ID != beatmap.NewValue.BeatmapSetInfo?.ID).Count(); + var last = BeatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo?.ID).Count(); + var next = beatmap.NewValue == null ? -1 : BeatmapSets.TakeWhile(b => b.ID != beatmap.NewValue.BeatmapSetInfo?.ID).Count(); direction = last > next ? TrackChangeDirection.Prev : TrackChangeDirection.Next; } From b5b29a21e783b93d21ea955d473fce33d59c8d47 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Sep 2019 02:15:18 +0900 Subject: [PATCH 21/48] Move menu cursor rotation to more appropriate settings section --- .../Overlays/Settings/Sections/Graphics/DetailSettings.cs | 5 ----- .../{MainMenuSettings.cs => UserInterfaceSettings.cs} | 7 ++++++- osu.Game/Overlays/Settings/Sections/GraphicsSection.cs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) rename osu.Game/Overlays/Settings/Sections/Graphics/{MainMenuSettings.cs => UserInterfaceSettings.cs} (71%) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs index 56e56f6ca8..9be34c3073 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs @@ -26,11 +26,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics LabelText = "Video", Bindable = config.GetBindable(OsuSetting.ShowVideoBackground) }, - new SettingsCheckbox - { - LabelText = "Rotate cursor when dragging", - Bindable = config.GetBindable(OsuSetting.CursorRotation) - }, new SettingsEnumDropdown { LabelText = "Screenshot format", diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/MainMenuSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs similarity index 71% rename from osu.Game/Overlays/Settings/Sections/Graphics/MainMenuSettings.cs rename to osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs index 92f64d0e14..dd822fedb6 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/MainMenuSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/UserInterfaceSettings.cs @@ -6,7 +6,7 @@ using osu.Game.Configuration; namespace osu.Game.Overlays.Settings.Sections.Graphics { - public class MainMenuSettings : SettingsSubsection + public class UserInterfaceSettings : SettingsSubsection { protected override string Header => "User Interface"; @@ -15,6 +15,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics { Children = new[] { + new SettingsCheckbox + { + LabelText = "Rotate cursor when dragging", + Bindable = config.GetBindable(OsuSetting.CursorRotation) + }, new SettingsCheckbox { LabelText = "Parallax", diff --git a/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs b/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs index 3d6086d3ea..89caa3dc8f 100644 --- a/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Settings.Sections new RendererSettings(), new LayoutSettings(), new DetailSettings(), - new MainMenuSettings(), + new UserInterfaceSettings(), }; } } From adc2dfa6c6ffecf27ae299d0cecd1e2844d380f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Sep 2019 03:00:17 +0900 Subject: [PATCH 22/48] Fix HitCircleLongCombo test stacking off-screen --- osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs index 399cf22599..95c2810e94 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs @@ -29,7 +29,8 @@ namespace osu.Game.Rulesets.Osu.Tests }; for (int i = 0; i < 512; i++) - beatmap.HitObjects.Add(new HitCircle { Position = new Vector2(256, 192), StartTime = i * 100 }); + if (i % 32 < 20) + beatmap.HitObjects.Add(new HitCircle { Position = new Vector2(256, 192), StartTime = i * 100 }); return beatmap; } From 7e791f7cd78e2fed4e67f91a739e8a6411da891a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Sep 2019 13:14:33 +0900 Subject: [PATCH 23/48] Expose as IBindableList --- osu.Game/Overlays/MusicController.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 92246dfc62..db94b0278f 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -25,7 +25,9 @@ namespace osu.Game.Overlays [Resolved] private BeatmapManager beatmaps { get; set; } - public readonly BindableList BeatmapSets = new BindableList(); + public IBindableList BeatmapSets => beatmapSets; + + private readonly BindableList beatmapSets = new BindableList(); public bool IsUserPaused { get; private set; } @@ -47,7 +49,7 @@ namespace osu.Game.Overlays [BackgroundDependencyLoader] private void load() { - BeatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets().OrderBy(_ => RNG.Next())); + beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets().OrderBy(_ => RNG.Next())); beatmaps.ItemAdded += handleBeatmapAdded; beatmaps.ItemRemoved += handleBeatmapRemoved; } @@ -66,8 +68,8 @@ namespace osu.Game.Overlays /// The new position. public void ChangeBeatmapSetPosition(BeatmapSetInfo beatmapSetInfo, int index) { - BeatmapSets.Remove(beatmapSetInfo); - BeatmapSets.Insert(index, beatmapSetInfo); + beatmapSets.Remove(beatmapSetInfo); + beatmapSets.Insert(index, beatmapSetInfo); } /// @@ -76,10 +78,10 @@ namespace osu.Game.Overlays public bool IsPlaying => beatmap.Value.Track.IsRunning; private void handleBeatmapAdded(BeatmapSetInfo set) => - Schedule(() => BeatmapSets.Add(set)); + Schedule(() => beatmapSets.Add(set)); private void handleBeatmapRemoved(BeatmapSetInfo set) => - Schedule(() => BeatmapSets.RemoveAll(s => s.ID == set.ID)); + Schedule(() => beatmapSets.RemoveAll(s => s.ID == set.ID)); private ScheduledDelegate seekDelegate; From 91bdece9af42fe2848d9fef7b56432cdaaee279c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Sep 2019 13:15:39 +0900 Subject: [PATCH 24/48] Localise OrderChanged handling and fix callbacks The dragged item's position now only updates after the drag finishes. Local handling changes were required to ignore the bindable remove/add events that are fired as a result. --- osu.Game/Overlays/Music/PlaylistList.cs | 42 +++++++++++++++++----- osu.Game/Overlays/Music/PlaylistOverlay.cs | 8 ----- osu.Game/Overlays/NowPlayingOverlay.cs | 1 - 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 6ad0aa23ec..636945edd2 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -19,7 +19,6 @@ namespace osu.Game.Overlays.Music public class PlaylistList : CompositeDrawable { public Action Selected; - public Action OrderChanged; private readonly ItemsScrollContainer items; @@ -29,7 +28,6 @@ namespace osu.Game.Overlays.Music { RelativeSizeAxes = Axes.Both, Selected = set => Selected?.Invoke(set), - OrderChanged = (s, i) => OrderChanged?.Invoke(s, i) }; } @@ -45,16 +43,17 @@ namespace osu.Game.Overlays.Music private class ItemsScrollContainer : OsuScrollContainer { - private BindableList beatmaps; + private IBindableList beatmaps; public Action Selected; - public Action OrderChanged; private readonly SearchContainer search; private readonly FillFlowContainer items; private readonly IBindable beatmapBacking = new Bindable(); + private MusicController musicController; + public ItemsScrollContainer() { Children = new Drawable[] @@ -78,6 +77,8 @@ namespace osu.Game.Overlays.Music [BackgroundDependencyLoader] private void load(MusicController musicController, IBindable beatmap) { + this.musicController = musicController; + beatmaps = musicController.BeatmapSets.GetBoundCopy(); beatmaps.ItemsAdded += i => i.ForEach(addBeatmapSet); @@ -88,10 +89,21 @@ namespace osu.Game.Overlays.Music beatmapBacking.ValueChanged += _ => updateSelectedSet(); } - private void addBeatmapSet(BeatmapSetInfo obj) => Schedule(() => { items.Insert(items.Count - 1, new PlaylistItem(obj) { OnSelect = set => Selected?.Invoke(set) }); }); + private void addBeatmapSet(BeatmapSetInfo obj) => Schedule(() => + { + if (obj == draggedItem?.BeatmapSetInfo) + { + draggedItem = null; + return; + } + + items.Insert(items.Count - 1, new PlaylistItem(obj) { OnSelect = set => Selected?.Invoke(set) }); + }); private void removeBeatmapSet(BeatmapSetInfo obj) => Schedule(() => { + if (obj == draggedItem?.BeatmapSetInfo) return; + var itemToRemove = items.FirstOrDefault(i => i.BeatmapSetInfo.ID == obj.ID); if (itemToRemove != null) items.Remove(itemToRemove); @@ -114,6 +126,8 @@ namespace osu.Game.Overlays.Music private Vector2 nativeDragPosition; private PlaylistItem draggedItem; + private int? dragDestination; + protected override bool OnDragStart(DragStartEvent e) { nativeDragPosition = e.ScreenSpaceMousePosition; @@ -133,10 +147,20 @@ namespace osu.Game.Overlays.Music protected override bool OnDragEnd(DragEndEvent e) { nativeDragPosition = e.ScreenSpaceMousePosition; - var handled = draggedItem != null || base.OnDragEnd(e); - draggedItem = null; - return handled; + if (draggedItem != null) + { + if (dragDestination != null) + { + // draggedItem is nulled when the BindableList's add event is received so we can quietly ignore the callbacks. + musicController.ChangeBeatmapSetPosition(draggedItem.BeatmapSetInfo, dragDestination.Value); + dragDestination = null; + } + + return true; + } + + return base.OnDragEnd(e); } protected override void Update() @@ -212,7 +236,7 @@ namespace osu.Game.Overlays.Music } items.SetLayoutPosition(draggedItem, dstIndex); - OrderChanged?.Invoke(draggedItem.BeatmapSetInfo, dstIndex); + dragDestination = dstIndex; } private class ItemSearchContainer : FillFlowContainer, IHasFilterableChildren diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index ec3d708645..ae81a6c117 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -22,12 +21,6 @@ namespace osu.Game.Overlays.Music private const float transition_duration = 600; private const float playlist_height = 510; - /// - /// Invoked when the order of an item in the list has changed. - /// The second parameter indicates the new index of the item. - /// - public Action OrderChanged; - private readonly Bindable beatmap = new Bindable(); private BeatmapManager beatmaps; @@ -65,7 +58,6 @@ namespace osu.Game.Overlays.Music RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Top = 95, Bottom = 10, Right = 10 }, Selected = itemSelected, - OrderChanged = (s, i) => OrderChanged?.Invoke(s, i) }, filter = new FilterControl { diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index cf42c8005a..6b79f2af07 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -81,7 +81,6 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.X, Y = player_height + 10, - OrderChanged = musicController.ChangeBeatmapSetPosition }, playerContainer = new Container { From 2db1e236a7180174ffa78318e29d92c0e9b6842f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Sep 2019 14:08:09 +0900 Subject: [PATCH 25/48] Fix frame count dependent tests regressing --- .../TestSceneAutoGeneration.cs | 101 ++++++++++-------- 1 file changed, 54 insertions(+), 47 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs index f260357df5..8206e33c7c 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs @@ -16,6 +16,11 @@ namespace osu.Game.Rulesets.Mania.Tests [HeadlessTest] public class TestSceneAutoGeneration : OsuTestScene { + /// + /// The number of frames which are generated at the start of a replay regardless of hitobject content. + /// + private const int frame_offset = 2; + [Test] public void TestSingleNote() { @@ -28,11 +33,11 @@ namespace osu.Game.Rulesets.Mania.Tests var generated = new ManiaAutoGenerator(beatmap).Generate(); - Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames"); - Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time"); - Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time"); - Assert.IsTrue(checkContains(generated.Frames[1], ManiaAction.Special1), "Special1 has not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[2], ManiaAction.Special1), "Special1 has not been released"); + Assert.IsTrue(generated.Frames.Count == frame_offset + 2, "Replay must have 3 frames"); + Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time"); + Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect release time"); + Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Special1), "Special1 has not been pressed"); + Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Special1), "Special1 has not been released"); } [Test] @@ -49,11 +54,11 @@ namespace osu.Game.Rulesets.Mania.Tests var generated = new ManiaAutoGenerator(beatmap).Generate(); - Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames"); - Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time"); - Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time"); - Assert.IsTrue(checkContains(generated.Frames[1], ManiaAction.Special1), "Special1 has not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[2], ManiaAction.Special1), "Special1 has not been released"); + Assert.IsTrue(generated.Frames.Count == frame_offset + 2, "Replay must have 3 frames"); + Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time"); + Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect release time"); + Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Special1), "Special1 has not been pressed"); + Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Special1), "Special1 has not been released"); } [Test] @@ -69,11 +74,11 @@ namespace osu.Game.Rulesets.Mania.Tests var generated = new ManiaAutoGenerator(beatmap).Generate(); - Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames"); - Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time"); - Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time"); - Assert.IsTrue(checkContains(generated.Frames[1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[2], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been released"); + Assert.IsTrue(generated.Frames.Count == frame_offset + 2, "Replay must have 3 frames"); + Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time"); + Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect release time"); + Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed"); + Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been released"); } [Test] @@ -91,11 +96,13 @@ namespace osu.Game.Rulesets.Mania.Tests var generated = new ManiaAutoGenerator(beatmap).Generate(); - Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames"); - Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time"); - Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time"); - Assert.IsTrue(checkContains(generated.Frames[1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[2], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been released"); + Assert.IsTrue(generated.Frames.Count == frame_offset + 2, "Replay must have 3 frames"); + + Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time"); + Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect release time"); + + Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed"); + Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been released"); } [Test] @@ -112,15 +119,15 @@ namespace osu.Game.Rulesets.Mania.Tests var generated = new ManiaAutoGenerator(beatmap).Generate(); - Assert.IsTrue(generated.Frames.Count == 5, "Replay must have 5 frames"); - Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect first note hit time"); - Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect first note release time"); - Assert.AreEqual(2000, generated.Frames[3].Time, "Incorrect second note hit time"); - Assert.AreEqual(2000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[4].Time, "Incorrect second note release time"); - Assert.IsTrue(checkContains(generated.Frames[1], ManiaAction.Key1), "Key1 has not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[2], ManiaAction.Key1), "Key1 has not been released"); - Assert.IsTrue(checkContains(generated.Frames[3], ManiaAction.Key2), "Key2 has not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[4], ManiaAction.Key2), "Key2 has not been released"); + Assert.IsTrue(generated.Frames.Count == frame_offset + 4, "Replay must have 4 generated frames"); + Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect first note hit time"); + Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect first note release time"); + Assert.AreEqual(2000, generated.Frames[frame_offset + 2].Time, "Incorrect second note hit time"); + Assert.AreEqual(2000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 3].Time, "Incorrect second note release time"); + Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed"); + Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1), "Key1 has not been released"); + Assert.IsTrue(checkContains(generated.Frames[frame_offset + 2], ManiaAction.Key2), "Key2 has not been pressed"); + Assert.IsFalse(checkContains(generated.Frames[frame_offset + 3], ManiaAction.Key2), "Key2 has not been released"); } [Test] @@ -139,16 +146,16 @@ namespace osu.Game.Rulesets.Mania.Tests var generated = new ManiaAutoGenerator(beatmap).Generate(); - Assert.IsTrue(generated.Frames.Count == 5, "Replay must have 5 frames"); - Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect first note hit time"); - Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[3].Time, "Incorrect first note release time"); - Assert.AreEqual(2000, generated.Frames[2].Time, "Incorrect second note hit time"); - Assert.AreEqual(4000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[4].Time, "Incorrect second note release time"); - Assert.IsTrue(checkContains(generated.Frames[1], ManiaAction.Key1), "Key1 has not been pressed"); - Assert.IsTrue(checkContains(generated.Frames[2], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[3], ManiaAction.Key1), "Key1 has not been released"); - Assert.IsTrue(checkContains(generated.Frames[3], ManiaAction.Key2), "Key2 has been released"); - Assert.IsFalse(checkContains(generated.Frames[4], ManiaAction.Key2), "Key2 has not been released"); + Assert.IsTrue(generated.Frames.Count == frame_offset + 4, "Replay must have 4 generated frames"); + Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect first note hit time"); + Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 2].Time, "Incorrect first note release time"); + Assert.AreEqual(2000, generated.Frames[frame_offset + 1].Time, "Incorrect second note hit time"); + Assert.AreEqual(4000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 3].Time, "Incorrect second note release time"); + Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed"); + Assert.IsTrue(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed"); + Assert.IsFalse(checkContains(generated.Frames[frame_offset + 2], ManiaAction.Key1), "Key1 has not been released"); + Assert.IsTrue(checkContains(generated.Frames[frame_offset + 2], ManiaAction.Key2), "Key2 has been released"); + Assert.IsFalse(checkContains(generated.Frames[frame_offset + 3], ManiaAction.Key2), "Key2 has not been released"); } [Test] @@ -166,14 +173,14 @@ namespace osu.Game.Rulesets.Mania.Tests var generated = new ManiaAutoGenerator(beatmap).Generate(); - Assert.IsTrue(generated.Frames.Count == 4, "Replay must have 4 frames"); - Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect first note hit time"); - Assert.AreEqual(3000, generated.Frames[2].Time, "Incorrect second note press time + first note release time"); - Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[3].Time, "Incorrect second note release time"); - Assert.IsTrue(checkContains(generated.Frames[1], ManiaAction.Key1), "Key1 has not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[2], ManiaAction.Key1), "Key1 has not been released"); - Assert.IsTrue(checkContains(generated.Frames[2], ManiaAction.Key2), "Key2 has not been pressed"); - Assert.IsFalse(checkContains(generated.Frames[3], ManiaAction.Key2), "Key2 has not been released"); + Assert.IsTrue(generated.Frames.Count == frame_offset + 3, "Replay must have 3 generated frames"); + Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect first note hit time"); + Assert.AreEqual(3000, generated.Frames[frame_offset + 1].Time, "Incorrect second note press time + first note release time"); + Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 2].Time, "Incorrect second note release time"); + Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed"); + Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1), "Key1 has not been released"); + Assert.IsTrue(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key2), "Key2 has not been pressed"); + Assert.IsFalse(checkContains(generated.Frames[frame_offset + 2], ManiaAction.Key2), "Key2 has not been released"); } private bool checkContains(ReplayFrame frame, params ManiaAction[] actions) => actions.All(action => ((ManiaReplayFrame)frame).Actions.Contains(action)); From 2046f64b22b31c753390da30bc71d33b59381c96 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Sep 2019 16:07:02 +0900 Subject: [PATCH 26/48] Revert clamping logic --- osu.Game/Tests/Visual/OsuTestScene.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 2bc9273f69..8e98d51962 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -20,6 +20,7 @@ using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Tests.Beatmaps; +using osuTK; namespace osu.Game.Tests.Visual { @@ -238,7 +239,7 @@ namespace osu.Game.Tests.Visual public override bool Seek(double seek) { - offset = Math.Min(seek, Length); + offset = MathHelper.Clamp(seek, 0, Length); lastReferenceTime = null; return offset == seek; From 381daffe527afef49687cbd1aed9ba026f718ef2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Sep 2019 16:07:29 +0900 Subject: [PATCH 27/48] Generate better temporary frames to support framed handling flaws --- osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs | 8 ++++---- osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs | 2 +- osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs | 8 ++++---- osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs | 3 ++- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs index 7f972a25ae..6c8515eb90 100644 --- a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs +++ b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs @@ -37,10 +37,6 @@ namespace osu.Game.Rulesets.Catch.Replays float lastPosition = 0.5f; double lastTime = 0; - // Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled - addFrame(-100000, lastPosition); - addFrame(0, lastPosition); - void moveToNext(CatchHitObject h) { float positionChange = Math.Abs(lastPosition - h.X); @@ -128,6 +124,10 @@ namespace osu.Game.Rulesets.Catch.Replays private void addFrame(double time, float? position = null, bool dashing = false) { + // todo: can be removed once FramedReplayInputHandler correctly handles rewinding before first frame. + if (Replay.Frames.Count == 0) + Replay.Frames.Add(new CatchReplayFrame(time - 1, position, false, null)); + var last = currentFrame; currentFrame = new CatchReplayFrame(time, position, dashing, last); Replay.Frames.Add(currentFrame); diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs index 8206e33c7c..a5248c7712 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.Tests /// /// The number of frames which are generated at the start of a replay regardless of hitobject content. /// - private const int frame_offset = 2; + private const int frame_offset = 1; [Test] public void TestSingleNote() diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index 5d333e2047..2b336ca16d 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -47,10 +47,6 @@ namespace osu.Game.Rulesets.Mania.Replays public override Replay Generate() { - // Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled - Replay.Frames.Add(new ManiaReplayFrame(-100000, 0)); - Replay.Frames.Add(new ManiaReplayFrame(0, 0)); - var pointGroups = generateActionPoints().GroupBy(a => a.Time).OrderBy(g => g.First().Time); var actions = new List(); @@ -71,6 +67,10 @@ namespace osu.Game.Rulesets.Mania.Replays } } + // todo: can be removed once FramedReplayInputHandler correctly handles rewinding before first frame. + if (Replay.Frames.Count == 0) + Replay.Frames.Add(new ManiaReplayFrame(group.First().Time - 1)); + Replay.Frames.Add(new ManiaReplayFrame(group.First().Time, actions.ToArray())); } diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs index 70ba5cd938..72c7eb60e0 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs @@ -21,7 +21,8 @@ namespace osu.Game.Rulesets.Mania.Replays public ManiaReplayFrame(double time, params ManiaAction[] actions) : base(time) { - Actions.AddRange(actions); + if (actions.Length > 0) + Actions.AddRange(actions); } public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap, ReplayFrame lastFrame = null) From e17cd9e964e5eaeded62b3b2a4584a813bec5470 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Sep 2019 16:14:31 +0900 Subject: [PATCH 28/48] Reduce length of tests --- osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs index 883aa9fc36..f94071a7a9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs @@ -24,7 +24,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override void AddCheckSteps() { AddUntilStep("score above zero", () => ((ScoreAccessiblePlayer)Player).ScoreProcessor.TotalScore.Value > 0); - AddUntilStep("key counter counted keys", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 5)); + AddUntilStep("key counter counted keys", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 2)); AddStep("rewind", () => track.Seek(-10000)); AddUntilStep("key counter reset", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0)); } From 61b396f235bedbd8306a26f84cbf5472df9f92d8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Sep 2019 17:09:43 +0900 Subject: [PATCH 29/48] Remove redundant length check --- osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs index 72c7eb60e0..70ba5cd938 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs @@ -21,8 +21,7 @@ namespace osu.Game.Rulesets.Mania.Replays public ManiaReplayFrame(double time, params ManiaAction[] actions) : base(time) { - if (actions.Length > 0) - Actions.AddRange(actions); + Actions.AddRange(actions); } public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap, ReplayFrame lastFrame = null) From cfdac956c2b28acd95829b6cac682d803e9fea67 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Sep 2019 20:04:49 +0900 Subject: [PATCH 30/48] Fix issues with colour and skin application --- osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 23 +++++++++++-------- .../Objects/Drawables/DrawableHitCircle.cs | 8 +++---- .../Objects/Drawables/DrawableSlider.cs | 4 ++-- .../Objects/Drawables/DrawableHitObject.cs | 15 +++++++++++- 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index 7c75bd608e..10a6334479 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -5,12 +5,12 @@ using System; using System.Linq; using osu.Framework.Bindables; using System.Collections.Generic; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; -using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Mods { @@ -22,7 +22,8 @@ namespace osu.Game.Rulesets.Osu.Mods public override ModType Type => ModType.Fun; public override string Description => "Put your faith in the approach circles..."; public override double ScoreMultiplier => 1; - public override Type[] IncompatibleMods => new[] { typeof(OsuModHidden), typeof(OsuModeObjectScaleTween) }; + + public override Type[] IncompatibleMods => new[] { typeof(OsuModHidden), typeof(OsuModSpinIn) }; private Bindable increaseFirstObjectVisibility = new Bindable(); public void ReadFromConfig(OsuConfigManager config) @@ -38,26 +39,28 @@ namespace osu.Game.Rulesets.Osu.Mods protected void ApplyTraceableState(DrawableHitObject drawable, ArmedState state) { - if (!(drawable is DrawableOsuHitObject d)) + if (!(drawable is DrawableOsuHitObject drawableOsu)) return; - var h = d.HitObject; + var h = drawableOsu.HitObject; switch (drawable) { case DrawableHitCircle circle: // we only want to see the approach circle using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true)) - { - circle.ApproachCircle.Show(); - } + circle.CirclePiece.Hide(); break; case DrawableSlider slider: - ApplyTraceableState(slider.HeadCircle, state); - slider.Body.AccentColour = Color4.Transparent; - slider.Body.BorderColour = slider.HeadCircle.AccentColour.Value; + slider.AccentColour.BindValueChanged(_ => + { + //will trigger on skin change. + slider.Body.AccentColour = slider.AccentColour.Value.Opacity(0); + slider.Body.BorderColour = slider.AccentColour.Value; + }, true); + break; case DrawableSpinner spinner: diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 83646c561d..c90f230f93 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { public class DrawableHitCircle : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach { - public ApproachCircle ApproachCircle; + public ApproachCircle ApproachCircle { get; } private readonly IBindable positionBindable = new Bindable(); private readonly IBindable stackHeightBindable = new Bindable(); @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private readonly HitArea hitArea; - private readonly SkinnableDrawable mainContent; + public SkinnableDrawable CirclePiece { get; } public DrawableHitCircle(HitCircle h) : base(h) @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables return true; }, }, - mainContent = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.HitCircle), _ => new MainCirclePiece(HitObject.IndexInCurrentCombo)), + CirclePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.HitCircle), _ => new MainCirclePiece(HitObject.IndexInCurrentCombo)), ApproachCircle = new ApproachCircle { Alpha = 0, @@ -133,7 +133,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { base.UpdateInitialTransforms(); - mainContent.FadeInFromZero(HitObject.TimeFadeIn); + CirclePiece.FadeInFromZero(HitObject.TimeFadeIn); ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt)); ApproachCircle.ScaleTo(1f, HitObject.TimePreempt); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 08b43b0345..643a0f7336 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -163,9 +163,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private float sliderPathRadius; - protected override void SkinChanged(ISkinSource skin, bool allowFallback) + protected override void ApplySkin(ISkinSource skin, bool allowFallback) { - base.SkinChanged(skin, allowFallback); + base.ApplySkin(skin, allowFallback); Body.BorderSize = skin.GetConfig(OsuSkinConfiguration.SliderBorderSize)?.Value ?? SliderBody.DEFAULT_BORDER_SIZE; sliderPathRadius = skin.GetConfig(OsuSkinConfiguration.SliderPathRadius)?.Value ?? OsuHitObject.OBJECT_RADIUS; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 00b57f7249..9a7f1e8522 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -240,7 +240,7 @@ namespace osu.Game.Rulesets.Objects.Drawables #endregion - protected override void SkinChanged(ISkinSource skin, bool allowFallback) + protected sealed override void SkinChanged(ISkinSource skin, bool allowFallback) { base.SkinChanged(skin, allowFallback); @@ -250,6 +250,19 @@ namespace osu.Game.Rulesets.Objects.Drawables AccentColour.Value = comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White; } + + ApplySkin(skin, allowFallback); + + updateState(State.Value, true); + } + + /// + /// Called when a change is made to the skin. + /// + /// The new skin. + /// Whether fallback to default skin should be allowed if the custom skin is missing this resource. + protected virtual void ApplySkin(ISkinSource skin, bool allowFallback) + { } /// From aa1a6256431f0e6ac5a6cd793d3d57112e346faf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Sep 2019 20:07:44 +0900 Subject: [PATCH 31/48] Add back incompatibility marker --- osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 3 +-- osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index 10a6334479..7e20feba02 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Description => "Put your faith in the approach circles..."; public override double ScoreMultiplier => 1; - public override Type[] IncompatibleMods => new[] { typeof(OsuModHidden), typeof(OsuModSpinIn) }; + public override Type[] IncompatibleMods => new[] { typeof(OsuModHidden), typeof(OsuModSpinIn), typeof(OsuModeObjectScaleTween) }; private Bindable increaseFirstObjectVisibility = new Bindable(); public void ReadFromConfig(OsuConfigManager config) @@ -65,7 +65,6 @@ namespace osu.Game.Rulesets.Osu.Mods case DrawableSpinner spinner: spinner.Disc.Hide(); - //spinner.Ticks.Hide(); // do they contribute to the theme? debatable spinner.Background.Hide(); break; } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs b/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs index e926ade41b..923278f484 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Mods private Bindable increaseFirstObjectVisibility = new Bindable(); - public override Type[] IncompatibleMods => new[] { typeof(OsuModSpinIn) }; + public override Type[] IncompatibleMods => new[] { typeof(OsuModSpinIn), typeof(OsuModTraceable) }; public void ReadFromConfig(OsuConfigManager config) { From 5901a915e7850fb064cde851cbb5d5a4d8af193b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Sep 2019 20:19:57 +0900 Subject: [PATCH 32/48] Always update drawable hitobject state on skin change --- .../Objects/Drawables/DrawableSlider.cs | 4 ++-- .../Objects/Drawables/DrawableHitObject.cs | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 08b43b0345..643a0f7336 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -163,9 +163,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private float sliderPathRadius; - protected override void SkinChanged(ISkinSource skin, bool allowFallback) + protected override void ApplySkin(ISkinSource skin, bool allowFallback) { - base.SkinChanged(skin, allowFallback); + base.ApplySkin(skin, allowFallback); Body.BorderSize = skin.GetConfig(OsuSkinConfiguration.SliderBorderSize)?.Value ?? SliderBody.DEFAULT_BORDER_SIZE; sliderPathRadius = skin.GetConfig(OsuSkinConfiguration.SliderPathRadius)?.Value ?? OsuHitObject.OBJECT_RADIUS; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 00b57f7249..9a7f1e8522 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -240,7 +240,7 @@ namespace osu.Game.Rulesets.Objects.Drawables #endregion - protected override void SkinChanged(ISkinSource skin, bool allowFallback) + protected sealed override void SkinChanged(ISkinSource skin, bool allowFallback) { base.SkinChanged(skin, allowFallback); @@ -250,6 +250,19 @@ namespace osu.Game.Rulesets.Objects.Drawables AccentColour.Value = comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White; } + + ApplySkin(skin, allowFallback); + + updateState(State.Value, true); + } + + /// + /// Called when a change is made to the skin. + /// + /// The new skin. + /// Whether fallback to default skin should be allowed if the custom skin is missing this resource. + protected virtual void ApplySkin(ISkinSource skin, bool allowFallback) + { } /// From 646a64792a8a7be0f00b202b545cd4421d6ffce1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2019 14:36:31 +0000 Subject: [PATCH 33/48] Bump ppy.osu.Framework.Android from 2019.911.0 to 2019.918.0 Bumps [ppy.osu.Framework.Android](https://github.com/ppy/osu-framework) from 2019.911.0 to 2019.918.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.911.0...2019.918.0) Signed-off-by: dependabot-preview[bot] --- osu.Android.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Android.props b/osu.Android.props index 4167d07698..85e8cb9ceb 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -63,6 +63,6 @@ - + From 1d7377df65c29f90712bb9a97630acd05b9bab3a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2019 14:51:01 +0000 Subject: [PATCH 34/48] Bump ppy.osu.Framework from 2019.911.0 to 2019.918.0 Bumps [ppy.osu.Framework](https://github.com/ppy/osu-framework) from 2019.911.0 to 2019.918.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.911.0...2019.918.0) Signed-off-by: dependabot-preview[bot] --- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 5703293caf..a733a0e7f9 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -26,7 +26,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 683dccf3ae..f70853d70b 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -118,7 +118,7 @@ - + From 5dc5181c9014f8f75ab32b6b17d16de5092e3e2c Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2019 15:27:39 +0000 Subject: [PATCH 35/48] Bump ppy.osu.Framework.iOS from 2019.911.0 to 2019.918.0 Bumps [ppy.osu.Framework.iOS](https://github.com/ppy/osu-framework) from 2019.911.0 to 2019.918.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2019.911.0...2019.918.0) Signed-off-by: dependabot-preview[bot] --- osu.iOS.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.iOS.props b/osu.iOS.props index f70853d70b..4bfa1ebcd0 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -119,7 +119,7 @@ - + From ecd721e8c5be287068bc1f51d2f85b4a44c225b3 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 18 Sep 2019 22:49:28 +0300 Subject: [PATCH 36/48] Add bypass fail property to Player --- osu.Game/Screens/Play/Player.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 309f4837e5..fbaab61b42 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -86,6 +86,11 @@ namespace osu.Game.Screens.Play [Cached(Type = typeof(IBindable>))] protected new readonly Bindable> Mods = new Bindable>(Array.Empty()); + /// + /// Whether to block the player from failing. + /// + protected virtual bool BypassFail => false; + private readonly bool allowPause; private readonly bool showResults; @@ -360,7 +365,7 @@ namespace osu.Game.Screens.Play private bool onFail() { - if (Mods.Value.OfType().Any(m => !m.AllowFail)) + if (Mods.Value.OfType().Any(m => !m.AllowFail) || BypassFail) return false; HasFailed = true; From 775b90e06643da66c6ebc72218e2163bbf15c8de Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 18 Sep 2019 22:49:48 +0300 Subject: [PATCH 37/48] Bypass fail on replays --- osu.Game/Screens/Play/ReplayPlayer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index a9c0ee3a15..da9f558c16 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -9,6 +9,9 @@ namespace osu.Game.Screens.Play { private readonly Score score; + // Block replays from failing. (see https://github.com/ppy/osu/issues/6108) + protected override bool BypassFail => true; + public ReplayPlayer(Score score, bool allowPause = true, bool showResults = true) : base(allowPause, showResults) { From 871adb16e0ba068e305ca79e342623bfff2b6e34 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 18 Sep 2019 22:51:03 +0300 Subject: [PATCH 38/48] Add asserts for fail bypassing --- osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs index 3fbce9d43c..d89304cf44 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs @@ -26,12 +26,14 @@ namespace osu.Game.Tests.Visual.Gameplay { AddUntilStep("score above zero", () => ((ScoreAccessibleReplayPlayer)Player).ScoreProcessor.TotalScore.Value > 0); AddUntilStep("key counter counted keys", () => ((ScoreAccessibleReplayPlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0)); + AddAssert("cannot fail", () => ((ScoreAccessibleReplayPlayer)Player).BypassFail); } private class ScoreAccessibleReplayPlayer : ReplayPlayer { public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; public new HUDOverlay HUDOverlay => base.HUDOverlay; + public new bool BypassFail => base.BypassFail; protected override bool PauseOnFocusLost => false; From ea6318ed73c22607c2aace18d7fa9cc7a659ebd1 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 18 Sep 2019 23:17:24 +0300 Subject: [PATCH 39/48] Fix failing test --- .../Visual/Gameplay/TestSceneFailJudgement.cs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs index d57ec44f39..e6d302a5ca 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs @@ -17,9 +17,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override Player CreatePlayer(Ruleset ruleset) { Mods.Value = Array.Empty(); - - var beatmap = Beatmap.Value.GetPlayableBeatmap(ruleset.RulesetInfo, Array.Empty()); - return new FailPlayer(ruleset.GetAutoplayMod().CreateReplayScore(beatmap)); + return new FailPlayer(); } protected override void AddCheckSteps() @@ -29,16 +27,12 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("total judgements == 1", () => ((FailPlayer)Player).ScoreProcessor.JudgedHits == 1); } - private class FailPlayer : ReplayPlayer + private class FailPlayer : TestPlayer { - public new DrawableRuleset DrawableRuleset => base.DrawableRuleset; - public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; - protected override bool PauseOnFocusLost => false; - - public FailPlayer(Score score) - : base(score, false, false) + public FailPlayer() + : base(false, false) { } From 3efcf0493c45c95b5a648bbcce99ab4af831ac7d Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 18 Sep 2019 23:28:48 +0300 Subject: [PATCH 40/48] Remove redundant using directive --- osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs index e6d302a5ca..cca6301b02 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs @@ -6,8 +6,6 @@ using System.Linq; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.UI; -using osu.Game.Scoring; using osu.Game.Screens.Play; namespace osu.Game.Tests.Visual.Gameplay From 3fa1b53b2ae3d670bc7f1f2a6f8b55cb57659b93 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Sep 2019 12:39:15 +0900 Subject: [PATCH 41/48] Add back combo colours for osu!classic --- osu.Game/Skinning/DefaultLegacySkin.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Skinning/DefaultLegacySkin.cs b/osu.Game/Skinning/DefaultLegacySkin.cs index 98f158c725..4b6eea6b6e 100644 --- a/osu.Game/Skinning/DefaultLegacySkin.cs +++ b/osu.Game/Skinning/DefaultLegacySkin.cs @@ -13,6 +13,13 @@ namespace osu.Game.Skinning : base(Info, storage, audioManager, string.Empty) { Configuration.CustomColours["SliderBall"] = new Color4(2, 170, 255, 255); + Configuration.ComboColours.AddRange(new[] + { + new Color4(255, 192, 0, 255), + new Color4(0, 202, 0, 255), + new Color4(18, 124, 255, 255), + new Color4(242, 24, 57, 255), + }); } public static SkinInfo Info { get; } = new SkinInfo From 0644443979bde65a602504c34eeecbbfcff332f9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Sep 2019 13:51:50 +0900 Subject: [PATCH 42/48] Use resolved attribute for music controller --- osu.Game/Overlays/Music/PlaylistList.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 636945edd2..cd9c91f3af 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -43,8 +43,6 @@ namespace osu.Game.Overlays.Music private class ItemsScrollContainer : OsuScrollContainer { - private IBindableList beatmaps; - public Action Selected; private readonly SearchContainer search; @@ -52,7 +50,10 @@ namespace osu.Game.Overlays.Music private readonly IBindable beatmapBacking = new Bindable(); - private MusicController musicController; + private IBindableList beatmaps; + + [Resolved] + private MusicController musicController { get; set; } public ItemsScrollContainer() { @@ -75,12 +76,9 @@ namespace osu.Game.Overlays.Music } [BackgroundDependencyLoader] - private void load(MusicController musicController, IBindable beatmap) + private void load(IBindable beatmap) { - this.musicController = musicController; - beatmaps = musicController.BeatmapSets.GetBoundCopy(); - beatmaps.ItemsAdded += i => i.ForEach(addBeatmapSet); beatmaps.ItemsRemoved += i => i.ForEach(removeBeatmapSet); beatmaps.ForEach(addBeatmapSet); From 4b97327b37ad910b93bb3a835a19201369dc6730 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Sep 2019 13:53:52 +0900 Subject: [PATCH 43/48] Cleanup draggedItem usages and make them more safe --- osu.Game/Overlays/Music/PlaylistList.cs | 50 ++++++++++++------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index cd9c91f3af..5b528c5ab2 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -87,25 +87,24 @@ namespace osu.Game.Overlays.Music beatmapBacking.ValueChanged += _ => updateSelectedSet(); } - private void addBeatmapSet(BeatmapSetInfo obj) => Schedule(() => - { - if (obj == draggedItem?.BeatmapSetInfo) - { - draggedItem = null; - return; - } - - items.Insert(items.Count - 1, new PlaylistItem(obj) { OnSelect = set => Selected?.Invoke(set) }); - }); - - private void removeBeatmapSet(BeatmapSetInfo obj) => Schedule(() => + private void addBeatmapSet(BeatmapSetInfo obj) { if (obj == draggedItem?.BeatmapSetInfo) return; - var itemToRemove = items.FirstOrDefault(i => i.BeatmapSetInfo.ID == obj.ID); - if (itemToRemove != null) - items.Remove(itemToRemove); - }); + Schedule(() => items.Insert(items.Count - 1, new PlaylistItem(obj) { OnSelect = set => Selected?.Invoke(set) })); + } + + private void removeBeatmapSet(BeatmapSetInfo obj) + { + if (obj == draggedItem?.BeatmapSetInfo) return; + + Schedule(() => + { + var itemToRemove = items.FirstOrDefault(i => i.BeatmapSetInfo.ID == obj.ID); + if (itemToRemove != null) + items.Remove(itemToRemove); + }); + } private void updateSelectedSet() { @@ -146,19 +145,16 @@ namespace osu.Game.Overlays.Music { nativeDragPosition = e.ScreenSpaceMousePosition; - if (draggedItem != null) - { - if (dragDestination != null) - { - // draggedItem is nulled when the BindableList's add event is received so we can quietly ignore the callbacks. - musicController.ChangeBeatmapSetPosition(draggedItem.BeatmapSetInfo, dragDestination.Value); - dragDestination = null; - } + if (draggedItem == null) + return base.OnDragEnd(e); - return true; - } + if (dragDestination != null) + musicController.ChangeBeatmapSetPosition(draggedItem.BeatmapSetInfo, dragDestination.Value); - return base.OnDragEnd(e); + draggedItem = null; + dragDestination = null; + + return true; } protected override void Update() From 9de0bcae1eef5ff0beaa2fb70f26d66a62cb725e Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 19 Sep 2019 07:58:54 +0300 Subject: [PATCH 44/48] Check for blocking fail mods by default --- osu.Game/Screens/Play/Player.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index fbaab61b42..e8134253f5 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -87,9 +87,11 @@ namespace osu.Game.Screens.Play protected new readonly Bindable> Mods = new Bindable>(Array.Empty()); /// - /// Whether to block the player from failing. + /// Whether failing should be allowed. + /// + /// By default, this checks whether any selected mod disallows failing. /// - protected virtual bool BypassFail => false; + protected virtual bool AllowFail => !Mods.Value.OfType().Any(m => !m.AllowFail); private readonly bool allowPause; private readonly bool showResults; @@ -365,7 +367,7 @@ namespace osu.Game.Screens.Play private bool onFail() { - if (Mods.Value.OfType().Any(m => !m.AllowFail) || BypassFail) + if (!AllowFail) return false; HasFailed = true; From e793854735a812acb0d4e01ddbff87c5d20922d3 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 19 Sep 2019 08:00:41 +0300 Subject: [PATCH 45/48] Invert BypassFail usage --- osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs | 4 ++-- osu.Game/Screens/Play/ReplayPlayer.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs index d89304cf44..36335bc54a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs @@ -26,14 +26,14 @@ namespace osu.Game.Tests.Visual.Gameplay { AddUntilStep("score above zero", () => ((ScoreAccessibleReplayPlayer)Player).ScoreProcessor.TotalScore.Value > 0); AddUntilStep("key counter counted keys", () => ((ScoreAccessibleReplayPlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0)); - AddAssert("cannot fail", () => ((ScoreAccessibleReplayPlayer)Player).BypassFail); + AddAssert("cannot fail", () => !((ScoreAccessibleReplayPlayer)Player).AllowFail); } private class ScoreAccessibleReplayPlayer : ReplayPlayer { public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; public new HUDOverlay HUDOverlay => base.HUDOverlay; - public new bool BypassFail => base.BypassFail; + public new bool AllowFail => base.AllowFail; protected override bool PauseOnFocusLost => false; diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index da9f558c16..b040549efc 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -9,8 +9,8 @@ namespace osu.Game.Screens.Play { private readonly Score score; - // Block replays from failing. (see https://github.com/ppy/osu/issues/6108) - protected override bool BypassFail => true; + // Disallow replays from failing. (see https://github.com/ppy/osu/issues/6108) + protected override bool AllowFail => false; public ReplayPlayer(Score score, bool allowPause = true, bool showResults = true) : base(allowPause, showResults) From 762adb783ae359a5d3f1d5bebeabd1ec3ef79be8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Sep 2019 14:15:06 +0900 Subject: [PATCH 46/48] Fix duplicate invocation of updateState on load complete --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 9a7f1e8522..b94de0df89 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -253,7 +253,8 @@ namespace osu.Game.Rulesets.Objects.Drawables ApplySkin(skin, allowFallback); - updateState(State.Value, true); + if (IsLoaded) + updateState(State.Value, true); } /// From da4d83063e73c4cda5a705fa0500f4153388a029 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 19 Sep 2019 08:31:11 +0300 Subject: [PATCH 47/48] Simplify LINQ expression --- osu.Game/Screens/Play/Player.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e8134253f5..30d6cfbf68 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -89,9 +89,9 @@ namespace osu.Game.Screens.Play /// /// Whether failing should be allowed. /// - /// By default, this checks whether any selected mod disallows failing. + /// By default, this checks whether all selected mods allow failing. /// - protected virtual bool AllowFail => !Mods.Value.OfType().Any(m => !m.AllowFail); + protected virtual bool AllowFail => Mods.Value.OfType().All(m => m.AllowFail); private readonly bool allowPause; private readonly bool showResults; From c76e27549a6db11e251376d5d15c2a3d710545b9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Sep 2019 14:56:52 +0900 Subject: [PATCH 48/48] Remove spacing --- osu.Game/Screens/Play/Player.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 30d6cfbf68..4b234ab296 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -88,7 +88,6 @@ namespace osu.Game.Screens.Play /// /// Whether failing should be allowed. - /// /// By default, this checks whether all selected mods allow failing. /// protected virtual bool AllowFail => Mods.Value.OfType().All(m => m.AllowFail);