From e5e454ddcda5dda65221723e75116cd56dcc08e8 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 7 Mar 2019 16:17:12 +0900 Subject: [PATCH 01/64] Don't perform lookup of beatmap stats unless an online id is present --- osu.Game/Screens/Select/BeatmapDetails.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 604d7a132b..d9334d65ac 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -175,7 +175,7 @@ namespace osu.Game.Screens.Select private void updateStatistics() { - if (Beatmap == null) + if (Beatmap?.OnlineBeatmapID == null) { clearStats(); return; From 054db480897a6fbea1a41f6ec90c5a7c9f3435c9 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 7 Mar 2019 16:59:43 +0900 Subject: [PATCH 02/64] Move online id null check to only bypass metrics lookup --- osu.Game/Screens/Select/BeatmapDetails.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index d9334d65ac..07db073edb 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -175,7 +175,7 @@ namespace osu.Game.Screens.Select private void updateStatistics() { - if (Beatmap?.OnlineBeatmapID == null) + if (Beatmap == null) { clearStats(); return; @@ -188,7 +188,7 @@ namespace osu.Game.Screens.Select tags.Text = Beatmap.Metadata.Tags; var requestedBeatmap = Beatmap; - if (requestedBeatmap.Metrics == null) + if (requestedBeatmap.Metrics == null && requestedBeatmap.OnlineBeatmapID != null) { var lookup = new GetBeatmapDetailsRequest(requestedBeatmap); lookup.Success += res => From 800007c3782b11ebce37a0ac695e763345b9a84e Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 8 Mar 2019 18:17:50 +0900 Subject: [PATCH 03/64] Set DummyWorkingBeatmap difficulties to 0 for better fallback display --- osu.Game/Beatmaps/DummyWorkingBeatmap.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs index 0aa1697bf8..f9df025be8 100644 --- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs @@ -26,7 +26,12 @@ namespace osu.Game.Beatmaps Title = "no beatmaps available!" }, BeatmapSet = new BeatmapSetInfo(), - BaseDifficulty = new BeatmapDifficulty(), + BaseDifficulty = new BeatmapDifficulty + { + DrainRate = 0, + CircleSize = 0, + OverallDifficulty = 0, + }, Ruleset = new DummyRulesetInfo() }) { From 192c257aac669402ac70bd34f341badaac07ad36 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 8 Mar 2019 18:32:39 +0900 Subject: [PATCH 04/64] Add test steps for BeatmapDetailArea --- .../Visual/TestCaseBeatmapDetailArea.cs | 133 +++++++++++++++++- 1 file changed, 132 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs b/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs index c23075a127..ff39ad5c0d 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs @@ -1,8 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; +using osu.Game.Beatmaps; using osu.Game.Screens.Select; using osuTK; @@ -14,12 +16,141 @@ namespace osu.Game.Tests.Visual { public TestCaseBeatmapDetailArea() { - Add(new BeatmapDetailArea + BeatmapDetailArea detailsArea; + Add(detailsArea = new BeatmapDetailArea { Anchor = Anchor.Centre, Origin = Anchor.Centre, Size = new Vector2(550f, 450f), }); + + AddStep("all metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap + { + BeatmapInfo = + { + Version = "All Metrics", + Metadata = new BeatmapMetadata + { + Source = "osu!lazer", + Tags = "this beatmap has all the metrics", + }, + BaseDifficulty = new BeatmapDifficulty + { + CircleSize = 7, + DrainRate = 1, + OverallDifficulty = 5.7f, + ApproachRate = 3.5f, + }, + StarDifficulty = 5.3f, + Metrics = new BeatmapMetrics + { + Ratings = Enumerable.Range(0, 11), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + }, + } + } + ); + + AddStep("all except source", () => detailsArea.Beatmap = new DummyWorkingBeatmap + { + BeatmapInfo = + { + Version = "All Metrics", + Metadata = new BeatmapMetadata + { + Tags = "this beatmap has all the metrics", + }, + BaseDifficulty = new BeatmapDifficulty + { + CircleSize = 7, + DrainRate = 1, + OverallDifficulty = 5.7f, + ApproachRate = 3.5f, + }, + StarDifficulty = 5.3f, + Metrics = new BeatmapMetrics + { + Ratings = Enumerable.Range(0, 11), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + }, + } + }); + + AddStep("ratings", () => detailsArea.Beatmap = new DummyWorkingBeatmap + { + BeatmapInfo = + { + Version = "Only Ratings", + Metadata = new BeatmapMetadata + { + Source = "osu!lazer", + Tags = "this beatmap has ratings metrics but not retries or fails", + }, + BaseDifficulty = new BeatmapDifficulty + { + CircleSize = 6, + DrainRate = 9, + OverallDifficulty = 6, + ApproachRate = 6, + }, + StarDifficulty = 4.8f, + Metrics = new BeatmapMetrics + { + Ratings = Enumerable.Range(0, 11), + }, + } + }); + + AddStep("fails+retries", () => detailsArea.Beatmap = new DummyWorkingBeatmap + { + BeatmapInfo = + { + Version = "Only Retries and Fails", + Metadata = new BeatmapMetadata + { + Source = "osu!lazer", + Tags = "this beatmap has retries and fails but no ratings", + }, + BaseDifficulty = new BeatmapDifficulty + { + CircleSize = 3.7f, + DrainRate = 6, + OverallDifficulty = 6, + ApproachRate = 7, + }, + StarDifficulty = 2.91f, + Metrics = new BeatmapMetrics + { + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + }, + } + }); + + AddStep("null metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap + { + BeatmapInfo = + { + Version = "No Metrics", + Metadata = new BeatmapMetadata + { + Source = "osu!lazer", + Tags = "this beatmap has no metrics", + }, + BaseDifficulty = new BeatmapDifficulty + { + CircleSize = 5, + DrainRate = 5, + OverallDifficulty = 5.5f, + ApproachRate = 6.5f, + }, + StarDifficulty = 1.97f, + } + }); + + AddStep("null beatmap", () => detailsArea.Beatmap = null); } } } From 8e5816805c11c67a3546952bfbef51a1dcdddfa0 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 8 Mar 2019 18:44:35 +0900 Subject: [PATCH 05/64] Fix showing outdated data for non-online beatmaps --- osu.Game/Screens/Select/BeatmapDetails.cs | 70 +++++++---------------- 1 file changed, 21 insertions(+), 49 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 07db073edb..6057ba382b 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -175,21 +175,21 @@ namespace osu.Game.Screens.Select private void updateStatistics() { + advanced.Beatmap = Beatmap; + description.Text = Beatmap?.Version; + source.Text = Beatmap?.Metadata?.Source; + tags.Text = Beatmap?.Metadata?.Tags; + if (Beatmap == null) { - clearStats(); + ratingsContainer.FadeOut(transition_duration); + failRetryContainer.FadeOut(transition_duration); return; } - ratingsContainer.FadeIn(transition_duration); - advanced.Beatmap = Beatmap; - description.Text = Beatmap.Version; - source.Text = Beatmap.Metadata.Source; - tags.Text = Beatmap.Metadata.Tags; - - var requestedBeatmap = Beatmap; - if (requestedBeatmap.Metrics == null && requestedBeatmap.OnlineBeatmapID != null) + if (Beatmap.Metrics == null && Beatmap.OnlineBeatmapID != null) { + var requestedBeatmap = Beatmap; var lookup = new GetBeatmapDetailsRequest(requestedBeatmap); lookup.Success += res => { @@ -198,39 +198,35 @@ namespace osu.Game.Screens.Select return; requestedBeatmap.Metrics = res; - Schedule(() => displayMetrics(res)); + Schedule(() => updateMetrics(res)); }; - lookup.Failure += e => Schedule(() => displayMetrics(null)); - + lookup.Failure += e => Schedule(() => updateMetrics(null)); api.Queue(lookup); loading.Show(); } - - displayMetrics(requestedBeatmap.Metrics, false); + else + { + updateMetrics(Beatmap.Metrics); + } } - private void displayMetrics(BeatmapMetrics metrics, bool failOnMissing = true) + private void updateMetrics(BeatmapMetrics metrics) { var hasRatings = metrics?.Ratings?.Any() ?? false; var hasRetriesFails = (metrics?.Retries?.Any() ?? false) && (metrics.Fails?.Any() ?? false); - if (failOnMissing) loading.Hide(); - if (hasRatings) { ratings.Metrics = metrics; - ratings.FadeIn(transition_duration); + ratingsContainer.FadeIn(transition_duration); } - else if (failOnMissing) + else { ratings.Metrics = new BeatmapMetrics { Ratings = new int[10], }; - } - else - { - ratings.FadeTo(0.25f, transition_duration); + ratingsContainer.FadeTo(0.25f, transition_duration); } if (hasRetriesFails) @@ -238,41 +234,17 @@ namespace osu.Game.Screens.Select failRetryGraph.Metrics = metrics; failRetryContainer.FadeIn(transition_duration); } - else if (failOnMissing) + else { failRetryGraph.Metrics = new BeatmapMetrics { Fails = new int[100], Retries = new int[100], }; + failRetryContainer.FadeOut(transition_duration); } - else - { - failRetryContainer.FadeTo(0.25f, transition_duration); - } - } - - private void clearStats() - { - description.Text = null; - source.Text = null; - tags.Text = null; - - advanced.Beatmap = new BeatmapInfo - { - StarDifficulty = 0, - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 0, - DrainRate = 0, - OverallDifficulty = 0, - ApproachRate = 0, - }, - }; loading.Hide(); - ratingsContainer.FadeOut(transition_duration); - failRetryContainer.FadeOut(transition_duration); } private class DetailBox : Container From 7311ccabfbb18f9d53b5a695381022b3e05151e1 Mon Sep 17 00:00:00 2001 From: Joehu Date: Fri, 8 Mar 2019 20:27:50 -0800 Subject: [PATCH 06/64] Fix direct panel stats being misaligned by one pixel --- osu.Game/Overlays/Direct/DirectGridPanel.cs | 5 +---- osu.Game/Overlays/Direct/DirectListPanel.cs | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 1413f0f885..b35dbde639 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -185,10 +185,7 @@ namespace osu.Game.Overlays.Direct Margin = new MarginPadding { Top = vertical_padding, Right = vertical_padding }, Children = new[] { - new Statistic(FontAwesome.fa_play_circle, SetInfo.OnlineInfo?.PlayCount ?? 0) - { - Margin = new MarginPadding { Right = 1 }, - }, + new Statistic(FontAwesome.fa_play_circle, SetInfo.OnlineInfo?.PlayCount ?? 0), new Statistic(FontAwesome.fa_heart, SetInfo.OnlineInfo?.FavouriteCount ?? 0), }, }, diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index 01393ad98b..d857a0f042 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -160,10 +160,7 @@ namespace osu.Game.Overlays.Direct Direction = FillDirection.Vertical, Children = new Drawable[] { - new Statistic(FontAwesome.fa_play_circle, SetInfo.OnlineInfo?.PlayCount ?? 0) - { - Margin = new MarginPadding { Right = 1 }, - }, + new Statistic(FontAwesome.fa_play_circle, SetInfo.OnlineInfo?.PlayCount ?? 0), new Statistic(FontAwesome.fa_heart, SetInfo.OnlineInfo?.FavouriteCount ?? 0), new FillFlowContainer { From 13b3036ec6c6d21b5b2278010ac184efe09f4e8f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Mar 2019 02:45:45 +0900 Subject: [PATCH 07/64] Fix "wind" mods adjusting rate twice This is a hotfix for incorrect framework behaviour. Closes #4442 --- osu.Game/Screens/Play/GameplayClockContainer.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 594df63420..0a6453beeb 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -141,11 +141,10 @@ namespace osu.Game.Screens.Play { if (sourceClock == null) return; - sourceClock.Rate = 1; + sourceClock.Rate = UserPlaybackRate.Value; + foreach (var mod in beatmap.Mods.Value.OfType()) mod.ApplyToClock(sourceClock); - - sourceClock.Rate *= UserPlaybackRate.Value; } } } From cdeaa80fea548a2be72ef7675976e73d0fed9f65 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Mar 2019 11:35:25 +0900 Subject: [PATCH 08/64] Call ResetSpeedAdjustments before adjusting clock --- osu.Game/Screens/Play/GameplayClockContainer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 0a6453beeb..207627140d 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -141,6 +141,7 @@ namespace osu.Game.Screens.Play { if (sourceClock == null) return; + sourceClock.ResetSpeedAdjustments(); sourceClock.Rate = UserPlaybackRate.Value; foreach (var mod in beatmap.Mods.Value.OfType()) From c1a356161f08749b75bd3338206557f296bf1b6e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Mar 2019 18:14:01 +0900 Subject: [PATCH 09/64] Allow use rate adjust to fallback to clock rate adjust --- osu.Game/Screens/Play/GameplayClockContainer.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 207627140d..3c2cec1d94 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -142,7 +143,11 @@ namespace osu.Game.Screens.Play if (sourceClock == null) return; sourceClock.ResetSpeedAdjustments(); - sourceClock.Rate = UserPlaybackRate.Value; + + if (sourceClock is IHasTempoAdjust tempo) + tempo.TempoAdjust = UserPlaybackRate.Value; + else + sourceClock.Rate = UserPlaybackRate.Value; foreach (var mod in beatmap.Mods.Value.OfType()) mod.ApplyToClock(sourceClock); From 6832e384a9a63c050b5e66d8b702aa12633ef1e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Mar 2019 18:14:41 +0900 Subject: [PATCH 10/64] Simplify DT/HT/NC/DC --- osu.Game/Rulesets/Mods/ModDaycore.cs | 2 +- osu.Game/Rulesets/Mods/ModDoubleTime.cs | 12 +++++------- osu.Game/Rulesets/Mods/ModHalfTime.cs | 12 +++++------- osu.Game/Rulesets/Mods/ModNightcore.cs | 2 +- osu.Game/Rulesets/Mods/ModTimeAdjust.cs | 24 ++++++++++++++++++++++++ 5 files changed, 36 insertions(+), 16 deletions(-) create mode 100644 osu.Game/Rulesets/Mods/ModTimeAdjust.cs diff --git a/osu.Game/Rulesets/Mods/ModDaycore.cs b/osu.Game/Rulesets/Mods/ModDaycore.cs index 2eea6a237c..dded688e80 100644 --- a/osu.Game/Rulesets/Mods/ModDaycore.cs +++ b/osu.Game/Rulesets/Mods/ModDaycore.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Mods public override void ApplyToClock(IAdjustableClock clock) { if (clock is IHasPitchAdjust pitchAdjust) - pitchAdjust.PitchAdjust = 0.75; + pitchAdjust.PitchAdjust *= RateAdjust; else base.ApplyToClock(clock); } diff --git a/osu.Game/Rulesets/Mods/ModDoubleTime.cs b/osu.Game/Rulesets/Mods/ModDoubleTime.cs index e59654c60d..9ea9eb76bc 100644 --- a/osu.Game/Rulesets/Mods/ModDoubleTime.cs +++ b/osu.Game/Rulesets/Mods/ModDoubleTime.cs @@ -2,12 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Timing; +using System.Linq; using osu.Game.Graphics; namespace osu.Game.Rulesets.Mods { - public abstract class ModDoubleTime : Mod, IApplicableToClock + public abstract class ModDoubleTime : ModTimeAdjust, IApplicableToClock { public override string Name => "Double Time"; public override string Acronym => "DT"; @@ -15,11 +15,9 @@ namespace osu.Game.Rulesets.Mods public override ModType Type => ModType.DifficultyIncrease; public override string Description => "Zoooooooooom..."; public override bool Ranked => true; - public override Type[] IncompatibleMods => new[] { typeof(ModHalfTime), typeof(ModTimeRamp) }; - public virtual void ApplyToClock(IAdjustableClock clock) - { - clock.Rate = 1.5; - } + public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModHalfTime)).ToArray(); + + protected override double RateAdjust => 1.5; } } diff --git a/osu.Game/Rulesets/Mods/ModHalfTime.cs b/osu.Game/Rulesets/Mods/ModHalfTime.cs index 07cceb6f49..fe26c96214 100644 --- a/osu.Game/Rulesets/Mods/ModHalfTime.cs +++ b/osu.Game/Rulesets/Mods/ModHalfTime.cs @@ -2,12 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Timing; +using System.Linq; using osu.Game.Graphics; namespace osu.Game.Rulesets.Mods { - public abstract class ModHalfTime : Mod, IApplicableToClock + public abstract class ModHalfTime : ModTimeAdjust, IApplicableToClock { public override string Name => "Half Time"; public override string Acronym => "HT"; @@ -15,11 +15,9 @@ namespace osu.Game.Rulesets.Mods public override ModType Type => ModType.DifficultyReduction; public override string Description => "Less zoom..."; public override bool Ranked => true; - public override Type[] IncompatibleMods => new[] { typeof(ModDoubleTime), typeof(ModTimeRamp) }; - public virtual void ApplyToClock(IAdjustableClock clock) - { - clock.Rate = 0.75; - } + public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModDoubleTime)).ToArray(); + + protected override double RateAdjust => 0.75; } } diff --git a/osu.Game/Rulesets/Mods/ModNightcore.cs b/osu.Game/Rulesets/Mods/ModNightcore.cs index e6bd532f72..a689292ed7 100644 --- a/osu.Game/Rulesets/Mods/ModNightcore.cs +++ b/osu.Game/Rulesets/Mods/ModNightcore.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Mods public override void ApplyToClock(IAdjustableClock clock) { if (clock is IHasPitchAdjust pitchAdjust) - pitchAdjust.PitchAdjust = 1.5; + pitchAdjust.PitchAdjust *= RateAdjust; else base.ApplyToClock(clock); } diff --git a/osu.Game/Rulesets/Mods/ModTimeAdjust.cs b/osu.Game/Rulesets/Mods/ModTimeAdjust.cs new file mode 100644 index 0000000000..513883f552 --- /dev/null +++ b/osu.Game/Rulesets/Mods/ModTimeAdjust.cs @@ -0,0 +1,24 @@ +// 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 osu.Framework.Audio; +using osu.Framework.Timing; + +namespace osu.Game.Rulesets.Mods +{ + public abstract class ModTimeAdjust : Mod + { + public override Type[] IncompatibleMods => new[] { typeof(ModTimeRamp) }; + + protected abstract double RateAdjust { get; } + + public virtual void ApplyToClock(IAdjustableClock clock) + { + if (clock is IHasTempoAdjust tempo) + tempo.TempoAdjust *= RateAdjust; + else + clock.Rate *= RateAdjust; + } + } +} From a10cd2288dc4433196a931ee5a85dd4a6a8e909a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Mar 2019 18:15:18 +0900 Subject: [PATCH 11/64] Improve ModRamp's handling of external rate changes --- osu.Game/Rulesets/Mods/ModTimeRamp.cs | 30 ++++++++++++++++++++------- osu.Game/Rulesets/Mods/ModWindDown.cs | 5 +++++ osu.Game/Rulesets/Mods/ModWindUp.cs | 7 ++++++- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModTimeRamp.cs b/osu.Game/Rulesets/Mods/ModTimeRamp.cs index 4a0ed0f9bb..1573418d95 100644 --- a/osu.Game/Rulesets/Mods/ModTimeRamp.cs +++ b/osu.Game/Rulesets/Mods/ModTimeRamp.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mods { public abstract class ModTimeRamp : Mod { - public override Type[] IncompatibleMods => new[] { typeof(ModDoubleTime), typeof(ModHalfTime) }; + public override Type[] IncompatibleMods => new[] { typeof(ModTimeAdjust) }; protected abstract double FinalRateAdjustment { get; } } @@ -29,20 +29,26 @@ namespace osu.Game.Rulesets.Mods private IAdjustableClock clock; - private IHasPitchAdjust pitchAdjust; - /// /// The point in the beatmap at which the final ramping rate should be reached. /// private const double final_rate_progress = 0.75f; + /// + /// The adjustment applied on entering this mod's application method. + /// + private double baseAdjust; + public virtual void ApplyToClock(IAdjustableClock clock) { this.clock = clock; - pitchAdjust = (IHasPitchAdjust)clock; - // for preview purposes - pitchAdjust.PitchAdjust = 1.0 + FinalRateAdjustment; + // we capture the adjustment applied before entering our application method. + // this will cover external changes, which should re-fire this method. + baseAdjust = (clock as IHasPitchAdjust)?.PitchAdjust ?? clock.Rate; + + // for preview purposes. during gameplay, Update will overwrite this setting. + applyAdjustment(1); } public virtual void ApplyToBeatmap(Beatmap beatmap) @@ -56,9 +62,17 @@ namespace osu.Game.Rulesets.Mods public virtual void Update(Playfield playfield) { var absRate = Math.Abs(FinalRateAdjustment); - var adjustment = MathHelper.Clamp(absRate * ((clock.CurrentTime - beginRampTime) / finalRateTime), 0, absRate); + applyAdjustment(MathHelper.Clamp(absRate * ((clock.CurrentTime - beginRampTime) / finalRateTime), 0, absRate)); + } - pitchAdjust.PitchAdjust = 1 + Math.Sign(FinalRateAdjustment) * adjustment; + private void applyAdjustment(double adjustment) + { + var localAdjust = 1 + Math.Sign(FinalRateAdjustment) * adjustment; + + if (clock is IHasPitchAdjust tempo) + tempo.PitchAdjust = baseAdjust * localAdjust; + else + clock.Rate *= baseAdjust * localAdjust; } } } diff --git a/osu.Game/Rulesets/Mods/ModWindDown.cs b/osu.Game/Rulesets/Mods/ModWindDown.cs index 646c5c64e4..174070eb85 100644 --- a/osu.Game/Rulesets/Mods/ModWindDown.cs +++ b/osu.Game/Rulesets/Mods/ModWindDown.cs @@ -1,6 +1,8 @@ // 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.Game.Graphics; using osu.Game.Rulesets.Objects; @@ -14,6 +16,9 @@ namespace osu.Game.Rulesets.Mods public override string Description => "Sloooow doooown..."; public override FontAwesome Icon => FontAwesome.fa_chevron_circle_down; public override double ScoreMultiplier => 1.0; + protected override double FinalRateAdjustment => -0.25; + + public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModWindUp)).ToArray(); } } diff --git a/osu.Game/Rulesets/Mods/ModWindUp.cs b/osu.Game/Rulesets/Mods/ModWindUp.cs index 9050b5591a..bf9af8a51d 100644 --- a/osu.Game/Rulesets/Mods/ModWindUp.cs +++ b/osu.Game/Rulesets/Mods/ModWindUp.cs @@ -1,6 +1,8 @@ // 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.Game.Graphics; using osu.Game.Rulesets.Objects; @@ -14,6 +16,9 @@ namespace osu.Game.Rulesets.Mods public override string Description => "Can you keep up?"; public override FontAwesome Icon => FontAwesome.fa_chevron_circle_up; public override double ScoreMultiplier => 1.0; + protected override double FinalRateAdjustment => 0.5; + + public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModWindDown)).ToArray(); } -} \ No newline at end of file +} From 12f334035fb1b52d3328671ef270f8a591f2b760 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 12 Mar 2019 19:23:24 +0900 Subject: [PATCH 12/64] Create properties for use in DrawableManiaJudgement --- .../UI/DrawableManiaJudgement.cs | 22 +++++++--------- .../Rulesets/Judgements/DrawableJudgement.cs | 26 +++++++++++++------ 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs index 5874bac7f6..3073b1dd19 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs @@ -22,22 +22,20 @@ namespace osu.Game.Rulesets.Mania.UI JudgementText.Font = JudgementText.Font.With(size: 25); } + protected override double FadeInDuration => 50; + + protected override float InitialHitScale => 0.8f; + + protected override double HitFadeOutDuration => 200; + + protected override float HitScaleDuration => 250; + protected override void LoadComplete() { - base.LoadComplete(); - - this.FadeInFromZero(50, Easing.OutQuint); - if (Result.IsHit) - { - JudgementBody.ScaleTo(0.8f); - JudgementBody.ScaleTo(1, 250, Easing.OutElastic); + JudgementBody.Delay(FadeInDuration).ScaleTo(0.75f, HitScaleDuration); - JudgementBody.Delay(50).ScaleTo(0.75f, 250); - this.Delay(50).FadeOut(200); - } - - Expire(); + base.LoadComplete(); } } } diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 0d6e11c649..e25676700d 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -32,6 +32,14 @@ namespace osu.Game.Rulesets.Judgements protected Container JudgementBody; protected SpriteText JudgementText; + protected virtual double FadeInDuration => 100; + + protected virtual float InitialHitScale => 0.9f; + + protected virtual float HitScaleDuration => 500; + + protected virtual double HitFadeOutDuration => 400; + /// /// Creates a drawable which visualises a . /// @@ -65,11 +73,13 @@ namespace osu.Game.Rulesets.Judgements }; } + private const double MISS_ANIMATION_DURATION = 800; + protected override void LoadComplete() { base.LoadComplete(); - this.FadeInFromZero(100, Easing.OutQuint); + this.FadeInFromZero(FadeInDuration, Easing.OutQuint); switch (Result.Type) { @@ -77,18 +87,18 @@ namespace osu.Game.Rulesets.Judgements break; case HitResult.Miss: JudgementBody.ScaleTo(1.6f); - JudgementBody.ScaleTo(1, 100, Easing.In); + JudgementBody.ScaleTo(1, FadeInDuration, Easing.In); - JudgementBody.MoveToOffset(new Vector2(0, 100), 800, Easing.InQuint); - JudgementBody.RotateTo(40, 800, Easing.InQuint); + JudgementBody.MoveToOffset(new Vector2(0, 100), MISS_ANIMATION_DURATION, Easing.InQuint); + JudgementBody.RotateTo(40, MISS_ANIMATION_DURATION, Easing.InQuint); - this.Delay(600).FadeOut(200); + this.Delay(500).FadeOut(200); break; default: - JudgementBody.ScaleTo(0.9f); - JudgementBody.ScaleTo(1, 500, Easing.OutElastic); + JudgementBody.ScaleTo(InitialHitScale); + JudgementBody.ScaleTo(1, HitScaleDuration, Easing.OutElastic); - this.Delay(100).FadeOut(400); + this.Delay(FadeInDuration).FadeOut(HitFadeOutDuration); break; } From 9850122245670545d1dde1dd5df132423fb07f2e Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 12 Mar 2019 19:24:46 +0900 Subject: [PATCH 13/64] Fix incorrect delay --- osu.Game/Rulesets/Judgements/DrawableJudgement.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index e25676700d..308a2b00f9 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Judgements JudgementBody.MoveToOffset(new Vector2(0, 100), MISS_ANIMATION_DURATION, Easing.InQuint); JudgementBody.RotateTo(40, MISS_ANIMATION_DURATION, Easing.InQuint); - this.Delay(500).FadeOut(200); + this.Delay(600).FadeOut(200); break; default: JudgementBody.ScaleTo(InitialHitScale); From 3b3b1e51ee43953bf713768ac89cca5e3b6e2d31 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 12 Mar 2019 19:41:33 +0900 Subject: [PATCH 14/64] Move hit animation logic into virtual method --- .../UI/DrawableManiaJudgement.cs | 15 ++++------- .../Rulesets/Judgements/DrawableJudgement.cs | 27 ++++++++++--------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs index 3073b1dd19..8797f014df 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs @@ -24,18 +24,13 @@ namespace osu.Game.Rulesets.Mania.UI protected override double FadeInDuration => 50; - protected override float InitialHitScale => 0.8f; - - protected override double HitFadeOutDuration => 200; - - protected override float HitScaleDuration => 250; - - protected override void LoadComplete() + protected override void ApplyHitAnimations() { - if (Result.IsHit) - JudgementBody.Delay(FadeInDuration).ScaleTo(0.75f, HitScaleDuration); + JudgementBody.ScaleTo(0.8f); + JudgementBody.ScaleTo(1, 250, Easing.OutElastic); - base.LoadComplete(); + JudgementBody.Delay(FadeInDuration).ScaleTo(0.75f, 250); + this.Delay(FadeInDuration).FadeOut(200); } } } diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 308a2b00f9..16e7fd4a15 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -32,14 +32,12 @@ namespace osu.Game.Rulesets.Judgements protected Container JudgementBody; protected SpriteText JudgementText; + /// + /// The amount of time for this judgement to initially fade in. + /// + /// Override this to change fade in times of mode-specific judgements protected virtual double FadeInDuration => 100; - protected virtual float InitialHitScale => 0.9f; - - protected virtual float HitScaleDuration => 500; - - protected virtual double HitFadeOutDuration => 400; - /// /// Creates a drawable which visualises a . /// @@ -73,7 +71,13 @@ namespace osu.Game.Rulesets.Judgements }; } - private const double MISS_ANIMATION_DURATION = 800; + protected virtual void ApplyHitAnimations() + { + JudgementBody.ScaleTo(0.9f); + JudgementBody.ScaleTo(1, 500, Easing.OutElastic); + + this.Delay(FadeInDuration).FadeOut(400); + } protected override void LoadComplete() { @@ -89,16 +93,13 @@ namespace osu.Game.Rulesets.Judgements JudgementBody.ScaleTo(1.6f); JudgementBody.ScaleTo(1, FadeInDuration, Easing.In); - JudgementBody.MoveToOffset(new Vector2(0, 100), MISS_ANIMATION_DURATION, Easing.InQuint); - JudgementBody.RotateTo(40, MISS_ANIMATION_DURATION, Easing.InQuint); + JudgementBody.MoveToOffset(new Vector2(0, 100), 800, Easing.InQuint); + JudgementBody.RotateTo(40, 800, Easing.InQuint); this.Delay(600).FadeOut(200); break; default: - JudgementBody.ScaleTo(InitialHitScale); - JudgementBody.ScaleTo(1, HitScaleDuration, Easing.OutElastic); - - this.Delay(FadeInDuration).FadeOut(HitFadeOutDuration); + ApplyHitAnimations(); break; } From 7eb253b6872acc10ad646f1e3d184cef0b51bbf5 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 12 Mar 2019 19:44:53 +0900 Subject: [PATCH 15/64] Fix incorrect scale duration --- osu.Game/Rulesets/Judgements/DrawableJudgement.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 16e7fd4a15..b273faec8f 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -91,7 +91,7 @@ namespace osu.Game.Rulesets.Judgements break; case HitResult.Miss: JudgementBody.ScaleTo(1.6f); - JudgementBody.ScaleTo(1, FadeInDuration, Easing.In); + JudgementBody.ScaleTo(1, 100, Easing.In); JudgementBody.MoveToOffset(new Vector2(0, 100), 800, Easing.InQuint); JudgementBody.RotateTo(40, 800, Easing.InQuint); From 527b77b07de94ac2477923b5f27bab29ea7e899a Mon Sep 17 00:00:00 2001 From: David Zhao Date: Tue, 12 Mar 2019 19:52:44 +0900 Subject: [PATCH 16/64] Make all inheritors of drawablejudgement use new method --- .../Objects/Drawables/DrawableOsuJudgement.cs | 9 +++------ osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs | 8 +++----- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs index 2512e74da7..938a2293ba 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs @@ -5,7 +5,6 @@ using osu.Framework.Graphics; using osuTK; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -16,12 +15,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { } - protected override void LoadComplete() + protected override void ApplyHitAnimations() { - if (Result.Type != HitResult.Miss) - JudgementText?.TransformSpacingTo(new Vector2(14, 0), 1800, Easing.OutQuint); - - base.LoadComplete(); + JudgementText?.TransformSpacingTo(new Vector2(14, 0), 1800, Easing.OutQuint); + base.ApplyHitAnimations(); } } } diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs index 90841f11f5..943adaed4b 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs @@ -39,12 +39,10 @@ namespace osu.Game.Rulesets.Taiko.UI } } - protected override void LoadComplete() + protected override void ApplyHitAnimations() { - if (Result.IsHit) - this.MoveToY(-100, 500); - - base.LoadComplete(); + this.MoveToY(-100, 500); + base.ApplyHitAnimations(); } } } From cc09ecbfcf27d2d220b8828f527bb1994444c341 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Mar 2019 20:31:15 +0900 Subject: [PATCH 17/64] Increase validation performed on .osu files to avoid hard crashes --- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 4 +- osu.Game/Beatmaps/Formats/LegacyParser.cs | 45 +++++++++++++++++++ .../Objects/Legacy/ConvertHitObjectParser.cs | 35 ++++++++------- 3 files changed, 66 insertions(+), 18 deletions(-) create mode 100644 osu.Game/Beatmaps/Formats/LegacyParser.cs diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 4f19fbd323..5988b05084 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -280,8 +280,8 @@ namespace osu.Game.Beatmaps.Formats { string[] split = line.Split(','); - double time = getOffsetTime(double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo)); - double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo); + double time = getOffsetTime(Parsing.ParseDouble(split[0].Trim())); + double beatLength = Parsing.ParseDouble(split[1].Trim()); double speedMultiplier = beatLength < 0 ? 100.0 / -beatLength : 1; TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple; diff --git a/osu.Game/Beatmaps/Formats/LegacyParser.cs b/osu.Game/Beatmaps/Formats/LegacyParser.cs new file mode 100644 index 0000000000..777a85dc93 --- /dev/null +++ b/osu.Game/Beatmaps/Formats/LegacyParser.cs @@ -0,0 +1,45 @@ +// 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.Globalization; + +namespace osu.Game.Beatmaps.Formats +{ + /// + /// Helper methods to parse from string to number and perform very basic validation. + /// + public static class Parsing + { + public const int MAX_COORDINATE_VALUE = 65536; + + public const double MAX_PARSE_VALUE = int.MaxValue; + + public static double ParseFloat(string input, float parseLimit = (float)MAX_PARSE_VALUE) + { + var output = float.Parse(input, CultureInfo.InvariantCulture); + if (output < -parseLimit) throw new FormatException("Value is too low"); + if (output > parseLimit) throw new FormatException("Value is too high"); + + return output; + } + + public static double ParseDouble(string input, double parseLimit = MAX_PARSE_VALUE) + { + var output = double.Parse(input, CultureInfo.InvariantCulture); + if (output < -parseLimit) throw new FormatException("Value is too low"); + if (output > parseLimit) throw new FormatException("Value is too high"); + + return output; + } + + public static int ParseInt(string input, int parseLimit = (int)MAX_PARSE_VALUE) + { + var output = int.Parse(input, CultureInfo.InvariantCulture); + if (output < -parseLimit) throw new FormatException("Value is too low"); + if (output > parseLimit) throw new FormatException("Value is too high"); + + return output; + } + } +} diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index e397139843..4d36b45989 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -5,7 +5,6 @@ using osuTK; using osu.Game.Rulesets.Objects.Types; using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using osu.Game.Beatmaps.Formats; using osu.Game.Audio; @@ -46,9 +45,11 @@ namespace osu.Game.Rulesets.Objects.Legacy { string[] split = text.Split(','); - Vector2 pos = new Vector2((int)Convert.ToSingle(split[0], CultureInfo.InvariantCulture), (int)Convert.ToSingle(split[1], CultureInfo.InvariantCulture)); + Vector2 pos = new Vector2((int)Parsing.ParseFloat(split[0], Parsing.MAX_COORDINATE_VALUE), (int)Parsing.ParseFloat(split[1], Parsing.MAX_COORDINATE_VALUE)); - ConvertHitObjectType type = (ConvertHitObjectType)int.Parse(split[3]); + double startTime = Parsing.ParseDouble(split[2]) + Offset; + + ConvertHitObjectType type = (ConvertHitObjectType)Parsing.ParseInt(split[3]); int comboOffset = (int)(type & ConvertHitObjectType.ComboOffset) >> 4; type &= ~ConvertHitObjectType.ComboOffset; @@ -56,7 +57,7 @@ namespace osu.Game.Rulesets.Objects.Legacy bool combo = type.HasFlag(ConvertHitObjectType.NewCombo); type &= ~ConvertHitObjectType.NewCombo; - var soundType = (LegacySoundType)int.Parse(split[4]); + var soundType = (LegacySoundType)Parsing.ParseInt(split[4]); var bankInfo = new SampleBankInfo(); HitObject result = null; @@ -107,7 +108,7 @@ namespace osu.Game.Rulesets.Objects.Legacy } string[] temp = t.Split(':'); - points[pointIndex++] = new Vector2((int)Convert.ToDouble(temp[0], CultureInfo.InvariantCulture), (int)Convert.ToDouble(temp[1], CultureInfo.InvariantCulture)) - pos; + points[pointIndex++] = new Vector2((int)Parsing.ParseDouble(temp[0], Parsing.MAX_COORDINATE_VALUE), (int)Parsing.ParseDouble(temp[1], Parsing.MAX_COORDINATE_VALUE)) - pos; } // osu-stable special-cased colinear perfect curves to a CurveType.Linear @@ -116,7 +117,7 @@ namespace osu.Game.Rulesets.Objects.Legacy if (points.Length == 3 && pathType == PathType.PerfectCurve && isLinear(points)) pathType = PathType.Linear; - int repeatCount = Convert.ToInt32(split[6], CultureInfo.InvariantCulture); + int repeatCount = Parsing.ParseInt(split[6]); if (repeatCount > 9000) throw new ArgumentOutOfRangeException(nameof(repeatCount), @"Repeat count is way too high"); @@ -125,7 +126,7 @@ namespace osu.Game.Rulesets.Objects.Legacy repeatCount = Math.Max(0, repeatCount - 1); if (split.Length > 7) - length = Convert.ToDouble(split[7], CultureInfo.InvariantCulture); + length = Math.Max(0, Parsing.ParseDouble(split[7])); if (split.Length > 10) readCustomSampleBanks(split[10], bankInfo); @@ -184,7 +185,9 @@ namespace osu.Game.Rulesets.Objects.Legacy } else if (type.HasFlag(ConvertHitObjectType.Spinner)) { - result = CreateSpinner(new Vector2(512, 384) / 2, combo, comboOffset, Convert.ToDouble(split[5], CultureInfo.InvariantCulture) + Offset); + double endTime = Math.Max(startTime, Parsing.ParseDouble(split[5]) + Offset); + + result = CreateSpinner(new Vector2(512, 384) / 2, combo, comboOffset, endTime); if (split.Length > 6) readCustomSampleBanks(split[6], bankInfo); @@ -193,12 +196,12 @@ namespace osu.Game.Rulesets.Objects.Legacy { // Note: Hold is generated by BMS converts - double endTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture); + double endTime = Math.Max(0, Parsing.ParseDouble(split[2])); if (split.Length > 5 && !string.IsNullOrEmpty(split[5])) { string[] ss = split[5].Split(':'); - endTime = Convert.ToDouble(ss[0], CultureInfo.InvariantCulture); + endTime = Parsing.ParseDouble(ss[0]); readCustomSampleBanks(string.Join(":", ss.Skip(1)), bankInfo); } @@ -211,7 +214,7 @@ namespace osu.Game.Rulesets.Objects.Legacy return null; } - result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture) + Offset; + result.StartTime = startTime; if (result.Samples.Count == 0) result.Samples = convertSoundType(soundType, bankInfo); @@ -222,7 +225,7 @@ namespace osu.Game.Rulesets.Objects.Legacy } catch (FormatException) { - throw new FormatException("One or more hit objects were malformed."); + return null; } } @@ -233,8 +236,8 @@ namespace osu.Game.Rulesets.Objects.Legacy string[] split = str.Split(':'); - var bank = (LegacyBeatmapDecoder.LegacySampleBank)int.Parse(split[0]); - var addbank = (LegacyBeatmapDecoder.LegacySampleBank)int.Parse(split[1]); + var bank = (LegacyBeatmapDecoder.LegacySampleBank)Parsing.ParseInt(split[0]); + var addbank = (LegacyBeatmapDecoder.LegacySampleBank)Parsing.ParseInt(split[1]); string stringBank = bank.ToString().ToLowerInvariant(); if (stringBank == @"none") @@ -247,10 +250,10 @@ namespace osu.Game.Rulesets.Objects.Legacy bankInfo.Add = string.IsNullOrEmpty(stringAddBank) ? stringBank : stringAddBank; if (split.Length > 2) - bankInfo.CustomSampleBank = int.Parse(split[2]); + bankInfo.CustomSampleBank = Parsing.ParseInt(split[2]); if (split.Length > 3) - bankInfo.Volume = int.Parse(split[3]); + bankInfo.Volume = Parsing.ParseInt(split[3]); bankInfo.Filename = split.Length > 4 ? split[4] : null; } From 73d9aef5bdf70ee6c359a4909bb70cb29d2302ac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Mar 2019 20:38:04 +0900 Subject: [PATCH 18/64] Fix filename --- osu.Game/Beatmaps/Formats/{LegacyParser.cs => Parsing.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename osu.Game/Beatmaps/Formats/{LegacyParser.cs => Parsing.cs} (100%) diff --git a/osu.Game/Beatmaps/Formats/LegacyParser.cs b/osu.Game/Beatmaps/Formats/Parsing.cs similarity index 100% rename from osu.Game/Beatmaps/Formats/LegacyParser.cs rename to osu.Game/Beatmaps/Formats/Parsing.cs From 93b774104afab8644d8736d97549d391b2932f78 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Mar 2019 11:30:33 +0900 Subject: [PATCH 19/64] Fix NaN handling --- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 5 ++++- osu.Game/Beatmaps/Formats/Parsing.cs | 21 ++++++++++++------- .../Objects/Legacy/ConvertHitObjectParser.cs | 6 +++++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 5988b05084..84bd953068 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -348,7 +348,10 @@ namespace osu.Game.Beatmaps.Formats CustomSampleBank = customSampleBank }); } - catch (FormatException e) + catch (FormatException) + { + } + catch (OverflowException) { } } diff --git a/osu.Game/Beatmaps/Formats/Parsing.cs b/osu.Game/Beatmaps/Formats/Parsing.cs index 777a85dc93..c3efb8c760 100644 --- a/osu.Game/Beatmaps/Formats/Parsing.cs +++ b/osu.Game/Beatmaps/Formats/Parsing.cs @@ -15,11 +15,14 @@ namespace osu.Game.Beatmaps.Formats public const double MAX_PARSE_VALUE = int.MaxValue; - public static double ParseFloat(string input, float parseLimit = (float)MAX_PARSE_VALUE) + public static float ParseFloat(string input, float parseLimit = (float)MAX_PARSE_VALUE) { var output = float.Parse(input, CultureInfo.InvariantCulture); - if (output < -parseLimit) throw new FormatException("Value is too low"); - if (output > parseLimit) throw new FormatException("Value is too high"); + + if (output < -parseLimit) throw new OverflowException("Value is too low"); + if (output > parseLimit) throw new OverflowException("Value is too high"); + + if (float.IsNaN(output)) throw new FormatException("Not a number"); return output; } @@ -27,8 +30,11 @@ namespace osu.Game.Beatmaps.Formats public static double ParseDouble(string input, double parseLimit = MAX_PARSE_VALUE) { var output = double.Parse(input, CultureInfo.InvariantCulture); - if (output < -parseLimit) throw new FormatException("Value is too low"); - if (output > parseLimit) throw new FormatException("Value is too high"); + + if (output < -parseLimit) throw new OverflowException("Value is too low"); + if (output > parseLimit) throw new OverflowException("Value is too high"); + + if (double.IsNaN(output)) throw new FormatException("Not a number"); return output; } @@ -36,8 +42,9 @@ namespace osu.Game.Beatmaps.Formats public static int ParseInt(string input, int parseLimit = (int)MAX_PARSE_VALUE) { var output = int.Parse(input, CultureInfo.InvariantCulture); - if (output < -parseLimit) throw new FormatException("Value is too low"); - if (output > parseLimit) throw new FormatException("Value is too high"); + + if (output < -parseLimit) throw new OverflowException("Value is too low"); + if (output > parseLimit) throw new OverflowException("Value is too high"); return output; } diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 4d36b45989..d738b1028e 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -225,8 +225,12 @@ namespace osu.Game.Rulesets.Objects.Legacy } catch (FormatException) { - return null; } + catch (OverflowException) + { + } + + return null; } private void readCustomSampleBanks(string str, SampleBankInfo bankInfo) From 0241148385c3687e28c717bdc13b772e787e2223 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Mar 2019 11:30:38 +0900 Subject: [PATCH 20/64] Add extensive tests --- .../Beatmaps/Formats/ParsingTest.cs | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 osu.Game.Tests/Beatmaps/Formats/ParsingTest.cs diff --git a/osu.Game.Tests/Beatmaps/Formats/ParsingTest.cs b/osu.Game.Tests/Beatmaps/Formats/ParsingTest.cs new file mode 100644 index 0000000000..b3863bcf44 --- /dev/null +++ b/osu.Game.Tests/Beatmaps/Formats/ParsingTest.cs @@ -0,0 +1,72 @@ +// 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.Globalization; +using NUnit.Framework; +using osu.Game.Beatmaps.Formats; + +namespace osu.Game.Tests.Beatmaps.Formats +{ + [TestFixture] + public class ParsingTest + { + [Test] + public void TestNaNHandling() => allThrow("NaN"); + + [Test] + public void TestBadStringHandling() => allThrow("Random string 123"); + + [TestCase(Parsing.MAX_PARSE_VALUE)] + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(-Parsing.MAX_PARSE_VALUE)] + [TestCase(10, 10)] + [TestCase(-10, 10)] + public void TestValidRanges(double input, double limit = Parsing.MAX_PARSE_VALUE) + { + Assert.AreEqual(Parsing.ParseInt((input).ToString(CultureInfo.InvariantCulture), (int)limit), (int)input); + Assert.AreEqual(Parsing.ParseFloat((input).ToString(CultureInfo.InvariantCulture), (float)limit), (float)input); + Assert.AreEqual(Parsing.ParseDouble((input).ToString(CultureInfo.InvariantCulture), limit), input); + } + + [TestCase(double.PositiveInfinity)] + [TestCase(double.NegativeInfinity)] + [TestCase(999999999999)] + [TestCase(Parsing.MAX_PARSE_VALUE * 1.1)] + [TestCase(-Parsing.MAX_PARSE_VALUE * 1.1)] + [TestCase(11, 10)] + [TestCase(-11, 10)] + public void TestOutOfRangeHandling(double input, double limit = Parsing.MAX_PARSE_VALUE) + => allThrow(input.ToString(CultureInfo.InvariantCulture), limit); + + private void allThrow(string input, double limit = Parsing.MAX_PARSE_VALUE) + where T : Exception + { + Assert.Throws(getIntParseException(input) ?? typeof(T), () => Parsing.ParseInt(input, (int)limit)); + Assert.Throws(() => Parsing.ParseFloat(input, (float)limit)); + Assert.Throws(() => Parsing.ParseDouble(input, limit)); + } + + /// + /// may not be able to parse some inputs. + /// In this case we expect to receive the raw parsing exception. + /// + /// The input attempting to be parsed. + /// The type of exception thrown by . Null if no exception is thrown. + private Type getIntParseException(string input) + { + try + { + var _ = int.Parse(input); + } + catch (Exception e) + { + return e.GetType(); + } + + return null; + } + } +} From a35d9ccc091c215e92087273eaf1ae498cc529c1 Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Wed, 13 Mar 2019 12:35:05 +0900 Subject: [PATCH 21/64] Apply clamping suggestion Co-Authored-By: peppy --- osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index d738b1028e..791de05bf7 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -257,7 +257,7 @@ namespace osu.Game.Rulesets.Objects.Legacy bankInfo.CustomSampleBank = Parsing.ParseInt(split[2]); if (split.Length > 3) - bankInfo.Volume = Parsing.ParseInt(split[3]); + bankInfo.Volume = Math.Max(0, Parsing.ParseInt(split[3])); bankInfo.Filename = split.Length > 4 ? split[4] : null; } From f0114d776db14f2c71e89eedefc710e9956921e6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Mar 2019 12:56:47 +0900 Subject: [PATCH 22/64] Use interface to access API Allows for better testability. --- .../Visual/TestCaseMatchLeaderboard.cs | 2 +- ...stCaseUpdateableBeatmapBackgroundSprite.cs | 2 +- osu.Game.Tests/Visual/TestCaseUserProfile.cs | 4 +- osu.Game/Beatmaps/BeatmapManager.cs | 4 +- osu.Game/Online/API/APIAccess.cs | 2 +- osu.Game/Online/API/APIRequest.cs | 11 +++-- osu.Game/Online/API/DummyAPIAccess.cs | 32 +++++++++++++-- osu.Game/Online/API/IAPIProvider.cs | 40 +++++++++++++++++++ osu.Game/Online/API/IOnlineComponent.cs | 2 +- osu.Game/Online/Leaderboards/Leaderboard.cs | 6 +-- osu.Game/OsuGameBase.cs | 1 - .../Overlays/AccountCreation/ScreenEntry.cs | 4 +- .../Overlays/AccountCreation/ScreenWarning.cs | 4 +- osu.Game/Overlays/AccountCreationOverlay.cs | 4 +- .../BeatmapSet/Buttons/DownloadButton.cs | 2 +- .../BeatmapSet/Scores/ScoresContainer.cs | 4 +- osu.Game/Overlays/BeatmapSetOverlay.cs | 4 +- osu.Game/Overlays/DirectOverlay.cs | 4 +- .../Profile/Sections/PaginatedContainer.cs | 4 +- .../Sections/Recent/DrawableRecentActivity.cs | 4 +- .../Sections/General/LoginSettings.cs | 8 ++-- osu.Game/Overlays/SocialOverlay.cs | 6 +-- .../Overlays/Toolbar/ToolbarUserButton.cs | 4 +- osu.Game/Overlays/UserProfileOverlay.cs | 4 +- osu.Game/Screens/Menu/ButtonSystem.cs | 2 +- osu.Game/Screens/Menu/Disclaimer.cs | 4 +- .../Multi/Lounge/Components/RoomInspector.cs | 2 +- osu.Game/Screens/Multi/Multiplayer.cs | 4 +- .../Screens/Multi/Play/TimeshiftPlayer.cs | 2 +- osu.Game/Screens/Multi/RoomManager.cs | 2 +- osu.Game/Screens/Play/Player.cs | 4 +- osu.Game/Screens/Select/BeatmapDetails.cs | 4 +- .../Select/Leaderboards/BeatmapLeaderboard.cs | 2 +- 33 files changed, 127 insertions(+), 61 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseMatchLeaderboard.cs b/osu.Game.Tests/Visual/TestCaseMatchLeaderboard.cs index 42a886a5a3..484a212a38 100644 --- a/osu.Game.Tests/Visual/TestCaseMatchLeaderboard.cs +++ b/osu.Game.Tests/Visual/TestCaseMatchLeaderboard.cs @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual } [Resolved] - private APIAccess api { get; set; } + private IAPIProvider api { get; set; } [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs b/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs index 506121efd7..ac90c264c4 100644 --- a/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs +++ b/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs @@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual private BeatmapManager beatmaps { get; set; } [BackgroundDependencyLoader] - private void load(OsuGameBase osu, APIAccess api, RulesetStore rulesets) + private void load(OsuGameBase osu, IAPIProvider api, RulesetStore rulesets) { Bindable beatmapBindable = new Bindable(); diff --git a/osu.Game.Tests/Visual/TestCaseUserProfile.cs b/osu.Game.Tests/Visual/TestCaseUserProfile.cs index 726134294e..46ee74b69f 100644 --- a/osu.Game.Tests/Visual/TestCaseUserProfile.cs +++ b/osu.Game.Tests/Visual/TestCaseUserProfile.cs @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual public class TestCaseUserProfile : OsuTestCase { private readonly TestUserProfileOverlay profile; - private APIAccess api; + private IAPIProvider api; public override IReadOnlyList RequiredTypes => new[] { @@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual } [BackgroundDependencyLoader] - private void load(APIAccess api) + private void load(IAPIProvider api) { this.api = api; } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 711aa0b79b..0ef8098a76 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -64,7 +64,7 @@ namespace osu.Game.Beatmaps private readonly BeatmapStore beatmaps; - private readonly APIAccess api; + private readonly IAPIProvider api; private readonly AudioManager audioManager; @@ -72,7 +72,7 @@ namespace osu.Game.Beatmaps private readonly List currentDownloads = new List(); - public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, APIAccess api, AudioManager audioManager, GameHost host = null, + public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, AudioManager audioManager, GameHost host = null, WorkingBeatmap defaultBeatmap = null) : base(storage, contextFactory, new BeatmapStore(contextFactory), host) { diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 5593abf348..3d861e44bf 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -22,7 +22,7 @@ namespace osu.Game.Online.API private readonly OsuConfigManager config; private readonly OAuth authentication; - public string Endpoint = @"https://osu.ppy.sh"; + public string Endpoint => @"https://osu.ppy.sh"; private const string client_id = @"5"; private const string client_secret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"; diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index 2781a5709b..96f3b85272 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -61,9 +61,12 @@ namespace osu.Game.Online.API private Action pendingFailure; - public void Perform(APIAccess api) + public void Perform(IAPIProvider api) { - API = api; + if (!(api is APIAccess apiAccess)) + throw new NotSupportedException($"A {nameof(APIAccess)} is required to perform requests."); + + API = apiAccess; if (checkAndScheduleFailure()) return; @@ -71,7 +74,7 @@ namespace osu.Game.Online.API WebRequest = CreateWebRequest(); WebRequest.Failed += Fail; WebRequest.AllowRetryOnTimeout = false; - WebRequest.AddHeader("Authorization", $"Bearer {api.AccessToken}"); + WebRequest.AddHeader("Authorization", $"Bearer {API.AccessToken}"); if (checkAndScheduleFailure()) return; @@ -85,7 +88,7 @@ namespace osu.Game.Online.API if (checkAndScheduleFailure()) return; - api.Schedule(delegate { Success?.Invoke(); }); + API.Schedule(delegate { Success?.Invoke(); }); } public void Cancel() => Fail(new OperationCanceledException(@"Request cancelled")); diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index 096ab5d8c8..af2fe51b38 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -11,14 +11,16 @@ namespace osu.Game.Online.API public Bindable LocalUser { get; } = new Bindable(new User { Username = @"Dummy", - Id = 1, + Id = 1001, }); public bool IsLoggedIn => true; - public void Update() - { - } + public string ProvidedUsername => LocalUser.Value.Username; + + public string Endpoint => "https://test.com"; + + public APIState State => LocalUser.Value.Id == 1 ? APIState.Offline : APIState.Online; public virtual void Queue(APIRequest request) { @@ -26,6 +28,28 @@ namespace osu.Game.Online.API public void Register(IOnlineComponent component) { + // todo: add support } + + public void Unregister(IOnlineComponent component) + { + // todo: add support + } + + public void Login(string username, string password) + { + LocalUser.Value = new User + { + Username = @"Dummy", + Id = 1, + }; + } + + public void Logout() + { + LocalUser.Value = new GuestUser(); + } + + public RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, string username, string password) => null; } } diff --git a/osu.Game/Online/API/IAPIProvider.cs b/osu.Game/Online/API/IAPIProvider.cs index e4533ecb3d..7c1f850943 100644 --- a/osu.Game/Online/API/IAPIProvider.cs +++ b/osu.Game/Online/API/IAPIProvider.cs @@ -18,6 +18,19 @@ namespace osu.Game.Online.API /// bool IsLoggedIn { get; } + /// + /// The last username provided by the end-user. + /// May not be authenticated. + /// + string ProvidedUsername { get; } + + /// + /// The URL endpoint for this API. Does not include a trailing slash. + /// + string Endpoint { get; } + + APIState State { get; } + /// /// Queue a new request. /// @@ -29,5 +42,32 @@ namespace osu.Game.Online.API /// /// The component to register. void Register(IOnlineComponent component); + + /// + /// Unregisters a component to receive state changes. + /// + /// The component to unregister. + void Unregister(IOnlineComponent component); + + /// + /// Attempt to login using the provided credentials. This is a non-blocking operation. + /// + /// The user's username. + /// The user's password. + void Login(string username, string password); + + /// + /// Log out the current user. + /// + void Logout(); + + /// + /// Create a new user account. This is a blocking operation. + /// + /// The email to create the account with. + /// The username to create the account with. + /// The password to create the account with. + /// Any errors encoutnered during account creation. + RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, string username, string password); } } diff --git a/osu.Game/Online/API/IOnlineComponent.cs b/osu.Game/Online/API/IOnlineComponent.cs index fb40bfd1e6..da6b784759 100644 --- a/osu.Game/Online/API/IOnlineComponent.cs +++ b/osu.Game/Online/API/IOnlineComponent.cs @@ -5,6 +5,6 @@ namespace osu.Game.Online.API { public interface IOnlineComponent { - void APIStateChanged(APIAccess api, APIState state); + void APIStateChanged(IAPIProvider api, APIState state); } } diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index f5b6e185c7..ac1666f8ed 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -174,12 +174,12 @@ namespace osu.Game.Online.Leaderboards }; } - private APIAccess api; + private IAPIProvider api; private ScheduledDelegate pendingUpdateScores; [BackgroundDependencyLoader(true)] - private void load(APIAccess api) + private void load(IAPIProvider api) { this.api = api; api?.Register(this); @@ -195,7 +195,7 @@ namespace osu.Game.Online.Leaderboards private APIRequest getScoresRequest; - public void APIStateChanged(APIAccess api, APIState state) + public void APIStateChanged(IAPIProvider api, APIState state) { if (state == APIState.Online) UpdateScores(); diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 643a673faf..7d55d19e50 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -152,7 +152,6 @@ namespace osu.Game API = new APIAccess(LocalConfig); - dependencies.Cache(API); dependencies.CacheAs(API); var defaultBeatmap = new DummyWorkingBeatmap(this); diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs index 2fc00edbc1..13d8df098f 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.AccountCreation private OsuTextBox emailTextBox; private OsuPasswordTextBox passwordTextBox; - private APIAccess api; + private IAPIProvider api; private ShakeContainer registerShake; private IEnumerable characterCheckText; @@ -42,7 +42,7 @@ namespace osu.Game.Overlays.AccountCreation private GameHost host; [BackgroundDependencyLoader] - private void load(OsuColour colours, APIAccess api, GameHost host) + private void load(OsuColour colours, IAPIProvider api, GameHost host) { this.api = api; this.host = host; diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs index 4e2cc1ea00..be417f4aac 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs @@ -22,7 +22,7 @@ namespace osu.Game.Overlays.AccountCreation { private OsuTextFlowContainer multiAccountExplanationText; private LinkFlowContainer furtherAssistance; - private APIAccess api; + private IAPIProvider api; private const string help_centre_url = "/help/wiki/Help_Centre#login"; @@ -39,7 +39,7 @@ namespace osu.Game.Overlays.AccountCreation } [BackgroundDependencyLoader(true)] - private void load(OsuColour colours, APIAccess api, OsuGame game, TextureStore textures) + private void load(OsuColour colours, IAPIProvider api, OsuGame game, TextureStore textures) { this.api = api; diff --git a/osu.Game/Overlays/AccountCreationOverlay.cs b/osu.Game/Overlays/AccountCreationOverlay.cs index bc780538d5..e8e44c206e 100644 --- a/osu.Game/Overlays/AccountCreationOverlay.cs +++ b/osu.Game/Overlays/AccountCreationOverlay.cs @@ -30,7 +30,7 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(OsuColour colours, APIAccess api) + private void load(OsuColour colours, IAPIProvider api) { api.Register(this); @@ -96,7 +96,7 @@ namespace osu.Game.Overlays this.FadeOut(100); } - public void APIStateChanged(APIAccess api, APIState state) + public void APIStateChanged(IAPIProvider api, APIState state) { switch (state) { diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/DownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/DownloadButton.cs index edd886f0f2..bbbcff0558 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/DownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/DownloadButton.cs @@ -39,7 +39,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons } [BackgroundDependencyLoader] - private void load(APIAccess api, BeatmapManager beatmaps) + private void load(IAPIProvider api, BeatmapManager beatmaps) { FillFlowContainer textSprites; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 6c65d491af..3dd03fcea6 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -45,7 +45,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } private GetScoresRequest getScoresRequest; - private APIAccess api; + private IAPIProvider api; public BeatmapInfo Beatmap { @@ -129,7 +129,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } [BackgroundDependencyLoader] - private void load(APIAccess api) + private void load(IAPIProvider api) { this.api = api; updateDisplay(); diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 55c21b7fc9..c49268bc16 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -31,7 +31,7 @@ namespace osu.Game.Overlays private readonly Header header; - private APIAccess api; + private IAPIProvider api; private RulesetStore rulesets; private readonly ScrollContainer scroll; @@ -101,7 +101,7 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(APIAccess api, RulesetStore rulesets) + private void load(IAPIProvider api, RulesetStore rulesets) { this.api = api; this.rulesets = rulesets; diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index a3d25a7a1c..34edbbcc8b 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays { private const float panel_padding = 10f; - private APIAccess api; + private IAPIProvider api; private RulesetStore rulesets; private readonly FillFlowContainer resultCountsContainer; @@ -164,7 +164,7 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(OsuColour colours, APIAccess api, RulesetStore rulesets, PreviewTrackManager previewTrackManager) + private void load(OsuColour colours, IAPIProvider api, RulesetStore rulesets, PreviewTrackManager previewTrackManager) { this.api = api; this.rulesets = rulesets; diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index 497d6c3fc4..46c65b9db7 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Profile.Sections protected readonly Bindable User = new Bindable(); - protected APIAccess Api; + protected IAPIProvider Api; protected APIRequest RetrievalRequest; protected RulesetStore Rulesets; @@ -84,7 +84,7 @@ namespace osu.Game.Overlays.Profile.Sections } [BackgroundDependencyLoader] - private void load(APIAccess api, RulesetStore rulesets) + private void load(IAPIProvider api, RulesetStore rulesets) { Api = api; Rulesets = rulesets; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 7e721ac807..8fab29e42c 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent { public class DrawableRecentActivity : DrawableProfileRow { - private APIAccess api; + private IAPIProvider api; private readonly APIRecentActivity activity; @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent } [BackgroundDependencyLoader] - private void load(APIAccess api) + private void load(IAPIProvider api) { this.api = api; diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index 026424e1ff..d6738250f9 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -58,14 +58,14 @@ namespace osu.Game.Overlays.Settings.Sections.General } [BackgroundDependencyLoader(permitNulls: true)] - private void load(OsuColour colours, APIAccess api) + private void load(OsuColour colours, IAPIProvider api) { this.colours = colours; api?.Register(this); } - public void APIStateChanged(APIAccess api, APIState state) + public void APIStateChanged(IAPIProvider api, APIState state) { form = null; @@ -194,7 +194,7 @@ namespace osu.Game.Overlays.Settings.Sections.General { private TextBox username; private TextBox password; - private APIAccess api; + private IAPIProvider api; public Action RequestHide; @@ -205,7 +205,7 @@ namespace osu.Game.Overlays.Settings.Sections.General } [BackgroundDependencyLoader(permitNulls: true)] - private void load(APIAccess api, OsuConfigManager config, AccountCreationOverlay accountCreation) + private void load(IAPIProvider api, OsuConfigManager config, AccountCreationOverlay accountCreation) { this.api = api; Direction = FillDirection.Vertical; diff --git a/osu.Game/Overlays/SocialOverlay.cs b/osu.Game/Overlays/SocialOverlay.cs index 3464058abb..daf3d1c576 100644 --- a/osu.Game/Overlays/SocialOverlay.cs +++ b/osu.Game/Overlays/SocialOverlay.cs @@ -22,7 +22,7 @@ namespace osu.Game.Overlays { public class SocialOverlay : SearchableListOverlay, IOnlineComponent { - private APIAccess api; + private IAPIProvider api; private readonly LoadingAnimation loading; private FillFlowContainer panels; @@ -89,7 +89,7 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(APIAccess api) + private void load(IAPIProvider api) { this.api = api; api.Register(this); @@ -193,7 +193,7 @@ namespace osu.Game.Overlays } } - public void APIStateChanged(APIAccess api, APIState state) + public void APIStateChanged(IAPIProvider api, APIState state) { switch (state) { diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index d47f3a7b16..8d1910fc19 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -43,12 +43,12 @@ namespace osu.Game.Overlays.Toolbar } [BackgroundDependencyLoader] - private void load(APIAccess api) + private void load(IAPIProvider api) { api.Register(this); } - public void APIStateChanged(APIAccess api, APIState state) + public void APIStateChanged(IAPIProvider api, APIState state) { switch (state) { diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 1ff1c2ce91..48ce055975 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -26,7 +26,7 @@ namespace osu.Game.Overlays private ProfileSection lastSection; private ProfileSection[] sections; private GetUserRequest userReq; - private APIAccess api; + private IAPIProvider api; protected ProfileHeader Header; private SectionsContainer sectionsContainer; private ProfileTabControl tabs; @@ -56,7 +56,7 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(APIAccess api) + private void load(IAPIProvider api) { this.api = api; } diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 1f68818669..3df4ef9059 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -97,7 +97,7 @@ namespace osu.Game.Screens.Menu private OsuGame game { get; set; } [Resolved] - private APIAccess api { get; set; } + private IAPIProvider api { get; set; } [Resolved(CanBeNull = true)] private NotificationOverlay notifications { get; set; } diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 89f4f92092..7a80a686b1 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.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; @@ -44,7 +44,7 @@ namespace osu.Game.Screens.Menu } [BackgroundDependencyLoader] - private void load(OsuColour colours, APIAccess api) + private void load(OsuColour colours, IAPIProvider api) { InternalChildren = new Drawable[] { diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs b/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs index fd9c8d7b35..5798fce457 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs @@ -246,7 +246,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components } [Resolved] - private APIAccess api { get; set; } + private IAPIProvider api { get; set; } private GetRoomScoresRequest request; diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index dd01ae4160..f38fc4e3ff 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -54,7 +54,7 @@ namespace osu.Game.Screens.Multi private OsuGameBase game { get; set; } [Resolved] - private APIAccess api { get; set; } + private IAPIProvider api { get; set; } [Resolved(CanBeNull = true)] private OsuLogo logo { get; set; } @@ -163,7 +163,7 @@ namespace osu.Game.Screens.Multi this.Push(new PlayerLoader(player)); } - public void APIStateChanged(APIAccess api, APIState state) + public void APIStateChanged(IAPIProvider api, APIState state) { if (state != APIState.Online) forcefullyExit(); diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs index 6b88403b9e..d5b8f1f0c8 100644 --- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs +++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Multi.Play private readonly PlaylistItem playlistItem; [Resolved] - private APIAccess api { get; set; } + private IAPIProvider api { get; set; } [Resolved] private IBindable ruleset { get; set; } diff --git a/osu.Game/Screens/Multi/RoomManager.cs b/osu.Game/Screens/Multi/RoomManager.cs index c15a8471a1..385cbe20e5 100644 --- a/osu.Game/Screens/Multi/RoomManager.cs +++ b/osu.Game/Screens/Multi/RoomManager.cs @@ -30,7 +30,7 @@ namespace osu.Game.Screens.Multi private Bindable currentFilter { get; set; } [Resolved] - private APIAccess api { get; set; } + private IAPIProvider api { get; set; } [Resolved] private RulesetStore rulesets { get; set; } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index ced0a43679..b11c5e51c9 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -60,7 +60,7 @@ namespace osu.Game.Screens.Play private RulesetInfo ruleset; - private APIAccess api; + private IAPIProvider api; private SampleChannel sampleRestart; @@ -85,7 +85,7 @@ namespace osu.Game.Screens.Play private GameplayClockContainer gameplayClockContainer; [BackgroundDependencyLoader] - private void load(AudioManager audio, APIAccess api, OsuConfigManager config) + private void load(AudioManager audio, IAPIProvider api, OsuConfigManager config) { this.api = api; diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 604d7a132b..751ff164e2 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.Select private readonly FailRetryGraph failRetryGraph; private readonly DimmedLoadingAnimation loading; - private APIAccess api; + private IAPIProvider api; private ScheduledDelegate pendingBeatmapSwitch; @@ -160,7 +160,7 @@ namespace osu.Game.Screens.Select } [BackgroundDependencyLoader] - private void load(APIAccess api) + private void load(IAPIProvider api) { this.api = api; } diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 61370f7ce3..ebb1d78ba0 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -43,7 +43,7 @@ namespace osu.Game.Screens.Select.Leaderboards private IBindable ruleset { get; set; } [Resolved] - private APIAccess api { get; set; } + private IAPIProvider api { get; set; } [BackgroundDependencyLoader] private void load() From b1f18481e0b0c008625841abfa07ab73d658e1a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Mar 2019 12:57:01 +0900 Subject: [PATCH 23/64] Show text to supporters telling them they're cool Also adds better tests for disclaimer screen. --- osu.Game.Tests/Visual/TestCaseDisclaimer.cs | 17 ++++- osu.Game/Screens/Menu/Disclaimer.cs | 85 +++++++++++++++------ 2 files changed, 76 insertions(+), 26 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseDisclaimer.cs b/osu.Game.Tests/Visual/TestCaseDisclaimer.cs index 3ceb3eb4bd..f08a2a54ca 100644 --- a/osu.Game.Tests/Visual/TestCaseDisclaimer.cs +++ b/osu.Game.Tests/Visual/TestCaseDisclaimer.cs @@ -2,16 +2,31 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Game.Online.API; using osu.Game.Screens.Menu; +using osu.Game.Users; namespace osu.Game.Tests.Visual { public class TestCaseDisclaimer : ScreenTestCase { + [Cached(typeof(IAPIProvider))] + private readonly DummyAPIAccess api = new DummyAPIAccess(); + [BackgroundDependencyLoader] private void load() { - LoadScreen(new Disclaimer()); + AddStep("load disclaimer", () => LoadScreen(new Disclaimer())); + + AddStep("toggle support", () => + { + api.LocalUser.Value = new User + { + Username = api.LocalUser.Value.Username, + Id = api.LocalUser.Value.Id, + IsSupporter = !api.LocalUser.Value.IsSupporter, + }; + }); } } } diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 7a80a686b1..af8c127a3c 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -1,12 +1,13 @@ -// 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; -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.Graphics.Sprites; using osu.Framework.Screens; using osu.Game.Graphics; @@ -25,16 +26,17 @@ namespace osu.Game.Screens.Menu private SpriteIcon icon; private Color4 iconColour; private LinkFlowContainer textFlow; + private LinkFlowContainer supportFlow; public override bool HideOverlaysOnEnter => true; public override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled; public override bool CursorVisible => false; - private readonly List supporterDrawables = new List(); private Drawable heart; private const float icon_y = -85; + private const float icon_size = 30; private readonly Bindable currentUser = new Bindable(); @@ -53,19 +55,38 @@ namespace osu.Game.Screens.Menu Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = FontAwesome.fa_warning, - Size = new Vector2(30), + Size = new Vector2(icon_size), Y = icon_y, }, - textFlow = new LinkFlowContainer + new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = new MarginPadding(50), - TextAnchor = Anchor.TopCentre, - Y = -110, + Direction = FillDirection.Vertical, + Y = icon_y + icon_size, Anchor = Anchor.Centre, Origin = Anchor.TopCentre, - Spacing = new Vector2(0, 2), + Children = new Drawable[] + { + textFlow = new LinkFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + TextAnchor = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Spacing = new Vector2(0, 2), + }, + supportFlow = new LinkFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + TextAnchor = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Spacing = new Vector2(0, 2), + }, + } } }; @@ -88,28 +109,42 @@ namespace osu.Game.Screens.Menu textFlow.NewParagraph(); textFlow.NewParagraph(); - supporterDrawables.AddRange(textFlow.AddText("Consider becoming an ", format)); - supporterDrawables.AddRange(textFlow.AddLink("osu!supporter", "https://osu.ppy.sh/home/support", creationParameters: format)); - supporterDrawables.AddRange(textFlow.AddText(" to help support the game", format)); - - supporterDrawables.Add(heart = textFlow.AddIcon(FontAwesome.fa_heart, t => - { - t.Padding = new MarginPadding { Left = 5 }; - t.Font = t.Font.With(size: 12); - t.Colour = colours.Pink; - t.Origin = Anchor.Centre; - }).First()); - iconColour = colours.Yellow; currentUser.BindTo(api.LocalUser); currentUser.BindValueChanged(e => { + supportFlow.Children.ForEach(d => d.FadeOut(500, Easing.OutQuint).Expire()); + if (e.NewValue.IsSupporter) - supporterDrawables.ForEach(d => d.FadeOut(500, Easing.OutQuint).Expire()); + { + supportFlow.AddText("Thank you for supporting osu!", format); + } + else + { + supportFlow.AddText("Consider becoming an ", format); + supportFlow.AddLink("osu!supporter", "https://osu.ppy.sh/home/support", creationParameters: format); + supportFlow.AddText(" to help support the game", format); + } + + heart = supportFlow.AddIcon(FontAwesome.fa_heart, t => + { + t.Padding = new MarginPadding { Left = 5 }; + t.Font = t.Font.With(size: 12); + t.Origin = Anchor.Centre; + t.Colour = colours.Pink; + }).First(); + + if (IsLoaded) + animateHeart(); }, true); } + private void animateHeart() + { + heart.FlashColour(Color4.White, 750, Easing.OutQuint).Loop(); + } + protected override void LoadComplete() { base.LoadComplete(); @@ -128,7 +163,9 @@ namespace osu.Game.Screens.Menu .MoveToY(icon_y, 160, Easing.InCirc) .RotateTo(0, 160, Easing.InCirc); - supporterDrawables.ForEach(d => d.FadeOut().Delay(2000).FadeIn(500)); + supportFlow.FadeOut().Delay(2000).FadeIn(500); + + animateHeart(); this .FadeInFromZero(500) @@ -136,8 +173,6 @@ namespace osu.Game.Screens.Menu .FadeOut(250) .ScaleTo(0.9f, 250, Easing.InQuint) .Finally(d => this.Push(intro)); - - heart.FlashColour(Color4.White, 750, Easing.OutQuint).Loop(); } } } From f8b5cf8c8e51741a2feb4d4b56f44b43183dcca4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Mar 2019 13:46:41 +0900 Subject: [PATCH 24/64] Add extra clamping of endTime to startTime --- osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 791de05bf7..73b3e823fd 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -196,12 +196,12 @@ namespace osu.Game.Rulesets.Objects.Legacy { // Note: Hold is generated by BMS converts - double endTime = Math.Max(0, Parsing.ParseDouble(split[2])); + double endTime = Math.Max(startTime, Parsing.ParseDouble(split[2])); if (split.Length > 5 && !string.IsNullOrEmpty(split[5])) { string[] ss = split[5].Split(':'); - endTime = Parsing.ParseDouble(ss[0]); + endTime = Math.Max(startTime, Parsing.ParseDouble(ss[0])); readCustomSampleBanks(string.Join(":", ss.Skip(1)), bankInfo); } From f4c505709ab2a9403ce88a5254e2104a9a9c823f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Mar 2019 13:56:31 +0900 Subject: [PATCH 25/64] Use parsing methods in more places Limiting scope to beatmap decoding for this pass. Can expand to skin/storyboard in the future. --- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 84bd953068..9b3607029f 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Globalization; using System.IO; using System.Linq; using osu.Framework.IO.File; @@ -25,7 +24,7 @@ namespace osu.Game.Beatmaps.Formats public static void Register() { - AddDecoder(@"osu file format v", m => new LegacyBeatmapDecoder(int.Parse(m.Split('v').Last()))); + AddDecoder(@"osu file format v", m => new LegacyBeatmapDecoder(Parsing.ParseInt(m.Split('v').Last()))); } /// @@ -104,25 +103,25 @@ namespace osu.Game.Beatmaps.Formats metadata.AudioFile = FileSafety.PathStandardise(pair.Value); break; case @"AudioLeadIn": - beatmap.BeatmapInfo.AudioLeadIn = int.Parse(pair.Value); + beatmap.BeatmapInfo.AudioLeadIn = Parsing.ParseInt(pair.Value); break; case @"PreviewTime": - metadata.PreviewTime = getOffsetTime(int.Parse(pair.Value)); + metadata.PreviewTime = getOffsetTime(Parsing.ParseInt(pair.Value)); break; case @"Countdown": - beatmap.BeatmapInfo.Countdown = int.Parse(pair.Value) == 1; + beatmap.BeatmapInfo.Countdown = Parsing.ParseInt(pair.Value) == 1; break; case @"SampleSet": defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), pair.Value); break; case @"SampleVolume": - defaultSampleVolume = int.Parse(pair.Value); + defaultSampleVolume = Parsing.ParseInt(pair.Value); break; case @"StackLeniency": - beatmap.BeatmapInfo.StackLeniency = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + beatmap.BeatmapInfo.StackLeniency = Parsing.ParseFloat(pair.Value); break; case @"Mode": - beatmap.BeatmapInfo.RulesetID = int.Parse(pair.Value); + beatmap.BeatmapInfo.RulesetID = Parsing.ParseInt(pair.Value); switch (beatmap.BeatmapInfo.RulesetID) { @@ -142,13 +141,13 @@ namespace osu.Game.Beatmaps.Formats break; case @"LetterboxInBreaks": - beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(pair.Value) == 1; + beatmap.BeatmapInfo.LetterboxInBreaks = Parsing.ParseInt(pair.Value) == 1; break; case @"SpecialStyle": - beatmap.BeatmapInfo.SpecialStyle = int.Parse(pair.Value) == 1; + beatmap.BeatmapInfo.SpecialStyle = Parsing.ParseInt(pair.Value) == 1; break; case @"WidescreenStoryboard": - beatmap.BeatmapInfo.WidescreenStoryboard = int.Parse(pair.Value) == 1; + beatmap.BeatmapInfo.WidescreenStoryboard = Parsing.ParseInt(pair.Value) == 1; break; } } @@ -163,16 +162,16 @@ namespace osu.Game.Beatmaps.Formats beatmap.BeatmapInfo.StoredBookmarks = pair.Value; break; case @"DistanceSpacing": - beatmap.BeatmapInfo.DistanceSpacing = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + beatmap.BeatmapInfo.DistanceSpacing = Math.Max(0, Parsing.ParseDouble(pair.Value)); break; case @"BeatDivisor": - beatmap.BeatmapInfo.BeatDivisor = int.Parse(pair.Value); + beatmap.BeatmapInfo.BeatDivisor = Parsing.ParseInt(pair.Value); break; case @"GridSize": - beatmap.BeatmapInfo.GridSize = int.Parse(pair.Value); + beatmap.BeatmapInfo.GridSize = Parsing.ParseInt(pair.Value); break; case @"TimelineZoom": - beatmap.BeatmapInfo.TimelineZoom = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + beatmap.BeatmapInfo.TimelineZoom = Math.Max(0, Parsing.ParseDouble(pair.Value)); break; } } @@ -209,10 +208,10 @@ namespace osu.Game.Beatmaps.Formats beatmap.BeatmapInfo.Metadata.Tags = pair.Value; break; case @"BeatmapID": - beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value); + beatmap.BeatmapInfo.OnlineBeatmapID = Parsing.ParseInt(pair.Value); break; case @"BeatmapSetID": - beatmap.BeatmapInfo.BeatmapSet = new BeatmapSetInfo { OnlineBeatmapSetID = int.Parse(pair.Value) }; + beatmap.BeatmapInfo.BeatmapSet = new BeatmapSetInfo { OnlineBeatmapSetID = Parsing.ParseInt(pair.Value) }; break; } } @@ -225,22 +224,22 @@ namespace osu.Game.Beatmaps.Formats switch (pair.Key) { case @"HPDrainRate": - difficulty.DrainRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + difficulty.DrainRate = Parsing.ParseFloat(pair.Value); break; case @"CircleSize": - difficulty.CircleSize = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + difficulty.CircleSize = Parsing.ParseFloat(pair.Value); break; case @"OverallDifficulty": - difficulty.OverallDifficulty = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + difficulty.OverallDifficulty = Parsing.ParseFloat(pair.Value); break; case @"ApproachRate": - difficulty.ApproachRate = float.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + difficulty.ApproachRate = Parsing.ParseFloat(pair.Value); break; case @"SliderMultiplier": - difficulty.SliderMultiplier = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + difficulty.SliderMultiplier = Parsing.ParseDouble(pair.Value); break; case @"SliderTickRate": - difficulty.SliderTickRate = double.Parse(pair.Value, NumberFormatInfo.InvariantInfo); + difficulty.SliderTickRate = Parsing.ParseDouble(pair.Value); break; } } @@ -260,10 +259,12 @@ namespace osu.Game.Beatmaps.Formats beatmap.BeatmapInfo.Metadata.BackgroundFile = FileSafety.PathStandardise(filename); break; case EventType.Break: + double start = getOffsetTime(Parsing.ParseDouble(split[1])); + var breakEvent = new BreakPeriod { - StartTime = getOffsetTime(double.Parse(split[1], NumberFormatInfo.InvariantInfo)), - EndTime = getOffsetTime(double.Parse(split[2], NumberFormatInfo.InvariantInfo)) + StartTime = start, + EndTime = Math.Max(start, getOffsetTime(Parsing.ParseDouble(split[1]))) }; if (!breakEvent.HasEffect) @@ -286,19 +287,19 @@ namespace osu.Game.Beatmaps.Formats TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple; if (split.Length >= 3) - timeSignature = split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)int.Parse(split[2]); + timeSignature = split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)Parsing.ParseInt(split[2]); LegacySampleBank sampleSet = defaultSampleBank; if (split.Length >= 4) - sampleSet = (LegacySampleBank)int.Parse(split[3]); + sampleSet = (LegacySampleBank)Parsing.ParseInt(split[3]); int customSampleBank = 0; if (split.Length >= 5) - customSampleBank = int.Parse(split[4]); + customSampleBank = Parsing.ParseInt(split[4]); int sampleVolume = defaultSampleVolume; if (split.Length >= 6) - sampleVolume = int.Parse(split[5]); + sampleVolume = Parsing.ParseInt(split[5]); bool timingChange = true; if (split.Length >= 7) @@ -308,7 +309,7 @@ namespace osu.Game.Beatmaps.Formats bool omitFirstBarSignature = false; if (split.Length >= 8) { - EffectFlags effectFlags = (EffectFlags)int.Parse(split[7]); + EffectFlags effectFlags = (EffectFlags)Parsing.ParseInt(split[7]); kiaiMode = effectFlags.HasFlag(EffectFlags.Kiai); omitFirstBarSignature = effectFlags.HasFlag(EffectFlags.OmitFirstBarLine); } From 04b88cdd11889d309777a93937066ab943d968c6 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Wed, 13 Mar 2019 14:12:05 +0900 Subject: [PATCH 26/64] Add required types for BeatmapDetailArea test case --- osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs b/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs index ff39ad5c0d..6cc3982f9c 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapDetailArea.cs @@ -1,6 +1,8 @@ // 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 NUnit.Framework; using osu.Framework.Graphics; @@ -14,6 +16,8 @@ namespace osu.Game.Tests.Visual [System.ComponentModel.Description("PlaySongSelect leaderboard/details area")] public class TestCaseBeatmapDetailArea : OsuTestCase { + public override IReadOnlyList RequiredTypes => new[] { typeof(BeatmapDetails) }; + public TestCaseBeatmapDetailArea() { BeatmapDetailArea detailsArea; From e6449db8e374f33779e1d9326e43c5f6270c7603 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Wed, 13 Mar 2019 14:12:36 +0900 Subject: [PATCH 27/64] Null metrics on null beatmap for transition animation --- osu.Game/Screens/Select/BeatmapDetails.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 6057ba382b..46979d0000 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -182,6 +182,7 @@ namespace osu.Game.Screens.Select if (Beatmap == null) { + updateMetrics(null); ratingsContainer.FadeOut(transition_duration); failRetryContainer.FadeOut(transition_duration); return; From 241e336c212ae097511b4bb93f2c62cd82fb691a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Mar 2019 14:22:16 +0900 Subject: [PATCH 28/64] Fix break parsing --- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 9b3607029f..d51bb8d6ca 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -264,7 +264,7 @@ namespace osu.Game.Beatmaps.Formats var breakEvent = new BreakPeriod { StartTime = start, - EndTime = Math.Max(start, getOffsetTime(Parsing.ParseDouble(split[1]))) + EndTime = Math.Max(start, getOffsetTime(Parsing.ParseDouble(split[2]))) }; if (!breakEvent.HasEffect) From 8f00f2290a1ffb9591521affbc076dc9d958d15f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Mar 2019 14:56:41 +0900 Subject: [PATCH 29/64] Log issues --- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 3 +++ osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index d51bb8d6ca..a27126ad9c 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -5,6 +5,7 @@ using System; using System.IO; using System.Linq; using osu.Framework.IO.File; +using osu.Framework.Logging; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Beatmaps.ControlPoints; @@ -351,9 +352,11 @@ namespace osu.Game.Beatmaps.Formats } catch (FormatException) { + Logger.Log("A timing point could not be parsed correctly and will be ignored", LoggingTarget.Runtime, LogLevel.Important); } catch (OverflowException) { + Logger.Log("A timing point could not be parsed correctly and will be ignored", LoggingTarget.Runtime, LogLevel.Important); } } diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 73b3e823fd..8d6bb8bd3f 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -225,9 +225,11 @@ namespace osu.Game.Rulesets.Objects.Legacy } catch (FormatException) { + Logger.Log("A hitobject could not be parsed correctly and will be ignored", LoggingTarget.Runtime, LogLevel.Important); } catch (OverflowException) { + Logger.Log("A hitobject could not be parsed correctly and will be ignored", LoggingTarget.Runtime, LogLevel.Important); } return null; From 3d4a80957fc52198c1225ad64acb8b5ba1fd6d00 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Mar 2019 18:27:54 +0900 Subject: [PATCH 30/64] Improve comment --- osu.Game/Rulesets/Judgements/DrawableJudgement.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index b273faec8f..89db954c36 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -33,9 +33,9 @@ namespace osu.Game.Rulesets.Judgements protected SpriteText JudgementText; /// - /// The amount of time for this judgement to initially fade in. + /// Duration of initial fade in. + /// Default fade out will start immediately after this duration. /// - /// Override this to change fade in times of mode-specific judgements protected virtual double FadeInDuration => 100; /// From 6aa3dc9f554e0d41dd42fc01c4115597574b05b4 Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Wed, 13 Mar 2019 18:56:48 +0900 Subject: [PATCH 31/64] Use non-real domain Co-Authored-By: peppy --- osu.Game/Online/API/DummyAPIAccess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index af2fe51b38..be3859b1eb 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -18,7 +18,7 @@ namespace osu.Game.Online.API public string ProvidedUsername => LocalUser.Value.Username; - public string Endpoint => "https://test.com"; + public string Endpoint => "http://localhost"; public APIState State => LocalUser.Value.Id == 1 ? APIState.Offline : APIState.Online; From 7d637691d77ccd7d490beff037ee1166daf022f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Mar 2019 19:01:42 +0900 Subject: [PATCH 32/64] Use non-guest user ID for non-guest user --- osu.Game/Online/API/DummyAPIAccess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index be3859b1eb..0cb49951f7 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -41,7 +41,7 @@ namespace osu.Game.Online.API LocalUser.Value = new User { Username = @"Dummy", - Id = 1, + Id = 1001, }; } From dd6fbccb5614a62ae943ab0ef53584729221038b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Mar 2019 19:57:45 +0900 Subject: [PATCH 33/64] Slight refactoring of order for readability --- osu.Game/Screens/Select/BeatmapDetails.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 46979d0000..2784e4fc3b 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using System.Linq; +using JetBrains.Annotations; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Framework.Threading; @@ -180,15 +181,15 @@ namespace osu.Game.Screens.Select source.Text = Beatmap?.Metadata?.Source; tags.Text = Beatmap?.Metadata?.Tags; - if (Beatmap == null) + // metrics may have been previously fetched + if (Beatmap?.Metrics != null) { - updateMetrics(null); - ratingsContainer.FadeOut(transition_duration); - failRetryContainer.FadeOut(transition_duration); + updateMetrics(Beatmap.Metrics); return; } - if (Beatmap.Metrics == null && Beatmap.OnlineBeatmapID != null) + // metrics may not be fetched but can be + if (Beatmap?.OnlineBeatmapID != null) { var requestedBeatmap = Beatmap; var lookup = new GetBeatmapDetailsRequest(requestedBeatmap); @@ -204,14 +205,13 @@ namespace osu.Game.Screens.Select lookup.Failure += e => Schedule(() => updateMetrics(null)); api.Queue(lookup); loading.Show(); + return; } - else - { - updateMetrics(Beatmap.Metrics); - } + + updateMetrics(null); } - private void updateMetrics(BeatmapMetrics metrics) + private void updateMetrics([CanBeNull] BeatmapMetrics metrics) { var hasRatings = metrics?.Ratings?.Any() ?? false; var hasRetriesFails = (metrics?.Retries?.Any() ?? false) && (metrics.Fails?.Any() ?? false); From 5d23a966d71984f170fc20fad3932829020e4e52 Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Wed, 13 Mar 2019 20:55:33 +0900 Subject: [PATCH 34/64] Fix incorrect application logic for rate fallback Co-Authored-By: peppy --- osu.Game/Rulesets/Mods/ModTimeRamp.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModTimeRamp.cs b/osu.Game/Rulesets/Mods/ModTimeRamp.cs index 1573418d95..0fadbd1d39 100644 --- a/osu.Game/Rulesets/Mods/ModTimeRamp.cs +++ b/osu.Game/Rulesets/Mods/ModTimeRamp.cs @@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Mods if (clock is IHasPitchAdjust tempo) tempo.PitchAdjust = baseAdjust * localAdjust; else - clock.Rate *= baseAdjust * localAdjust; + clock.Rate = baseAdjust * localAdjust; } } } From c40e24739b2040a62035021786226e26b9cdfaf0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Mar 2019 21:37:33 +0900 Subject: [PATCH 35/64] Fix weird application logic --- osu.Game/Rulesets/Mods/ModTimeRamp.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModTimeRamp.cs b/osu.Game/Rulesets/Mods/ModTimeRamp.cs index 0fadbd1d39..082f0091c6 100644 --- a/osu.Game/Rulesets/Mods/ModTimeRamp.cs +++ b/osu.Game/Rulesets/Mods/ModTimeRamp.cs @@ -62,12 +62,14 @@ namespace osu.Game.Rulesets.Mods public virtual void Update(Playfield playfield) { var absRate = Math.Abs(FinalRateAdjustment); - applyAdjustment(MathHelper.Clamp(absRate * ((clock.CurrentTime - beginRampTime) / finalRateTime), 0, absRate)); + applyAdjustment((clock.CurrentTime - beginRampTime) / finalRateTime); } - private void applyAdjustment(double adjustment) + private void applyAdjustment(double adjustAmount) { - var localAdjust = 1 + Math.Sign(FinalRateAdjustment) * adjustment; + adjustAmount = MathHelper.Clamp(adjustAmount, 0, 1); + + var localAdjust = 1 + Math.Sign(FinalRateAdjustment) * adjustAmount * Math.Abs(FinalRateAdjustment); if (clock is IHasPitchAdjust tempo) tempo.PitchAdjust = baseAdjust * localAdjust; From 108dcd0a92e61a281e4bd7308e7b4c3e55e0c66f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Mar 2019 21:58:50 +0900 Subject: [PATCH 36/64] Update framework --- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 2e945c212d..e2c96effb6 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -16,7 +16,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index b25e2a8bb2..288630d1ec 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -105,8 +105,8 @@ - - + + From 85c518f146f4b8ff1c8bbd7971d0023545825701 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 14 Mar 2019 12:29:16 +0900 Subject: [PATCH 37/64] Change logic to better handle external adjustments --- osu.Game/Rulesets/Mods/ModTimeRamp.cs | 43 +++++++++++++++++---------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModTimeRamp.cs b/osu.Game/Rulesets/Mods/ModTimeRamp.cs index 082f0091c6..8cd4b28ce3 100644 --- a/osu.Game/Rulesets/Mods/ModTimeRamp.cs +++ b/osu.Game/Rulesets/Mods/ModTimeRamp.cs @@ -34,18 +34,11 @@ namespace osu.Game.Rulesets.Mods /// private const double final_rate_progress = 0.75f; - /// - /// The adjustment applied on entering this mod's application method. - /// - private double baseAdjust; - public virtual void ApplyToClock(IAdjustableClock clock) { this.clock = clock; - // we capture the adjustment applied before entering our application method. - // this will cover external changes, which should re-fire this method. - baseAdjust = (clock as IHasPitchAdjust)?.PitchAdjust ?? clock.Rate; + lastAdjust = 1; // for preview purposes. during gameplay, Update will overwrite this setting. applyAdjustment(1); @@ -61,20 +54,38 @@ namespace osu.Game.Rulesets.Mods public virtual void Update(Playfield playfield) { - var absRate = Math.Abs(FinalRateAdjustment); applyAdjustment((clock.CurrentTime - beginRampTime) / finalRateTime); } - private void applyAdjustment(double adjustAmount) + private double lastAdjust = 1; + + private bool reported; + + /// + /// Adjust the rate along the specified ramp + /// + /// The amount of adjustment to apply (from 0..1). + private void applyAdjustment(double amount) { - adjustAmount = MathHelper.Clamp(adjustAmount, 0, 1); + double adjust = 1 + (Math.Sign(FinalRateAdjustment) * MathHelper.Clamp(amount, 0, 1) * Math.Abs(FinalRateAdjustment)); - var localAdjust = 1 + Math.Sign(FinalRateAdjustment) * adjustAmount * Math.Abs(FinalRateAdjustment); + switch (clock) + { + case IHasPitchAdjust pitch: + pitch.PitchAdjust /= lastAdjust; + pitch.PitchAdjust *= adjust; + break; + case IHasTempoAdjust tempo: + tempo.TempoAdjust /= lastAdjust; + tempo.TempoAdjust *= adjust; + break; + default: + clock.Rate /= lastAdjust; + clock.Rate *= adjust; + break; + } - if (clock is IHasPitchAdjust tempo) - tempo.PitchAdjust = baseAdjust * localAdjust; - else - clock.Rate = baseAdjust * localAdjust; + lastAdjust = adjust; } } } From 7d56ce63d38433541f12932b2b015d9f6f059615 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 14 Mar 2019 12:31:17 +0900 Subject: [PATCH 38/64] Fix test case failures --- osu.Game/Tests/Visual/RateAdjustedBeatmapTestCase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/RateAdjustedBeatmapTestCase.cs b/osu.Game/Tests/Visual/RateAdjustedBeatmapTestCase.cs index 14b4af1e7d..3b3adb4d76 100644 --- a/osu.Game/Tests/Visual/RateAdjustedBeatmapTestCase.cs +++ b/osu.Game/Tests/Visual/RateAdjustedBeatmapTestCase.cs @@ -13,7 +13,7 @@ namespace osu.Game.Tests.Visual base.Update(); // note that this will override any mod rate application - Beatmap.Value.Track.Rate = Clock.Rate; + Beatmap.Value.Track.TempoAdjust = Clock.Rate; } } } From 69eb4ef9830f41c425c08ac307f5083cd78934b5 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 14 Mar 2019 13:23:31 +0900 Subject: [PATCH 39/64] Change updateMetrics parameter to be optional --- osu.Game/Screens/Select/BeatmapDetails.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 2784e4fc3b..e8ef94c101 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using System.Linq; -using JetBrains.Annotations; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Framework.Threading; @@ -202,16 +201,16 @@ namespace osu.Game.Screens.Select requestedBeatmap.Metrics = res; Schedule(() => updateMetrics(res)); }; - lookup.Failure += e => Schedule(() => updateMetrics(null)); + lookup.Failure += e => Schedule(() => updateMetrics()); api.Queue(lookup); loading.Show(); return; } - updateMetrics(null); + updateMetrics(); } - private void updateMetrics([CanBeNull] BeatmapMetrics metrics) + private void updateMetrics(BeatmapMetrics metrics = null) { var hasRatings = metrics?.Ratings?.Any() ?? false; var hasRetriesFails = (metrics?.Retries?.Any() ?? false) && (metrics.Fails?.Any() ?? false); From 2815c3b07cc296b8c13c9d8c0006f4e1ae75aee7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Mar 2019 15:12:26 +0900 Subject: [PATCH 40/64] Remove unused variable --- osu.Game/Rulesets/Mods/ModTimeRamp.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModTimeRamp.cs b/osu.Game/Rulesets/Mods/ModTimeRamp.cs index 8cd4b28ce3..62407907c1 100644 --- a/osu.Game/Rulesets/Mods/ModTimeRamp.cs +++ b/osu.Game/Rulesets/Mods/ModTimeRamp.cs @@ -59,8 +59,6 @@ namespace osu.Game.Rulesets.Mods private double lastAdjust = 1; - private bool reported; - /// /// Adjust the rate along the specified ramp /// From 71d79f0a3914a2f858514e9b173e4f4db93a36aa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Mar 2019 15:20:09 +0900 Subject: [PATCH 41/64] Fix ticks not being generated at the minimum tick distance --- osu.Game/Rulesets/Objects/SliderEventGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/SliderEventGenerator.cs b/osu.Game/Rulesets/Objects/SliderEventGenerator.cs index a0f9d0a481..7cda7485f9 100644 --- a/osu.Game/Rulesets/Objects/SliderEventGenerator.cs +++ b/osu.Game/Rulesets/Objects/SliderEventGenerator.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Objects for (var d = tickDistance; d <= length; d += tickDistance) { - if (d > length - minDistanceFromEnd) + if (d >= length - minDistanceFromEnd) break; var pathProgress = d / length; From 5cc670cd19012a0a6b26d83404e7221c5faf9826 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 14 Mar 2019 18:51:28 +0900 Subject: [PATCH 42/64] Prevent ApplyTransformsAt from propogating to SliderBall children --- .../Objects/Drawables/Pieces/SliderBall.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs index 1b2e2c1f47..e41c568403 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs @@ -132,6 +132,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces base.ClearTransformsAfter(time, false, targetMember); } + public override void ApplyTransformsAt(double time, bool propagateChildren = false) + { + // For the same reasons as above w.r.t rewinding, we shouldn't propagate to children here either. + base.ApplyTransformsAt(time, false); + } + private bool tracking; public bool Tracking From 144b8761d4e01fcb9c6aa1bf7f5a9e10c2b8275e Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 14 Mar 2019 19:15:47 +0900 Subject: [PATCH 43/64] Change "Redundant argument with default value" inspection from warning to hint. --- osu.sln.DotSettings | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index b1ac31f2ce..71cbd83e3e 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -111,6 +111,7 @@ HINT WARNING WARNING + HINT WARNING WARNING WARNING From d13423fcdbcf7a723c0c7afaa0ea66f4c9b5bb00 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Mar 2019 23:06:23 +0900 Subject: [PATCH 44/64] Fix catch difficulty calculator not providing adjustment mods --- .../Difficulty/CatchDifficultyCalculator.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 8cfda5d532..f3b88bd928 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Difficulty.Preprocessing; using osu.Game.Rulesets.Catch.Difficulty.Skills; +using osu.Game.Rulesets.Catch.Mods; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Difficulty; @@ -88,5 +89,13 @@ namespace osu.Game.Rulesets.Catch.Difficulty { new Movement(), }; + + protected override Mod[] DifficultyAdjustmentMods => new Mod[] + { + new CatchModDoubleTime(), + new CatchModHalfTime(), + new CatchModHardRock(), + new CatchModEasy(), + }; } } From e31680e3730a04a27dacd019476a41b002e12bac Mon Sep 17 00:00:00 2001 From: Joehu Date: Thu, 14 Mar 2019 16:05:54 -0700 Subject: [PATCH 45/64] Address styling issues on CodeFactor --- osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.cs | 1 - osu.iOS/Application.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.cs b/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.cs index c38cd19b42..026442f328 100644 --- a/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.cs +++ b/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.cs @@ -13,7 +13,6 @@ namespace osu.Game.Migrations protected override void Down(MigrationBuilder migrationBuilder) { - } } } diff --git a/osu.iOS/Application.cs b/osu.iOS/Application.cs index 8a5cfcdbe8..cb75e5c159 100644 --- a/osu.iOS/Application.cs +++ b/osu.iOS/Application.cs @@ -13,4 +13,3 @@ namespace osu.iOS } } } - From 8c6caf0b18383b015a79f14976b668270c00214e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 16 Mar 2019 01:03:13 +0900 Subject: [PATCH 46/64] Update framework --- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index e2c96effb6..c56d50ae15 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -16,7 +16,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 288630d1ec..fedc20397d 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -105,8 +105,8 @@ - - + + From 771d676ba1a8baed1661985929598598893b5a33 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 16 Mar 2019 13:47:11 +0900 Subject: [PATCH 47/64] Split RulesetInputManager out to FrameStabilityContainer --- .../Rulesets/UI/FrameStabilityContainer.cs | 161 ++++++++++++++++++ osu.Game/Rulesets/UI/RulesetContainer.cs | 14 +- osu.Game/Rulesets/UI/RulesetInputManager.cs | 140 +-------------- 3 files changed, 178 insertions(+), 137 deletions(-) create mode 100644 osu.Game/Rulesets/UI/FrameStabilityContainer.cs diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs new file mode 100644 index 0000000000..921ed46d0e --- /dev/null +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -0,0 +1,161 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Timing; +using osu.Game.Input.Handlers; +using osu.Game.Screens.Play; + +namespace osu.Game.Rulesets.UI +{ + /// + /// A container which consumes a parent gameplay clock and standardises frame counts for children. + /// Will ensure a minimum of 40 frames per clock second is maintained, regardless of any system lag or seeks. + /// + public class FrameStabilityContainer : Container, IHasReplayHandler + { + public FrameStabilityContainer() + { + RelativeSizeAxes = Axes.Both; + gameplayClock = new GameplayClock(framedClock = new FramedClock(manualClock = new ManualClock())); + } + + #region Clock control + + private readonly ManualClock manualClock; + + private readonly FramedClock framedClock; + + [Cached] + private GameplayClock gameplayClock; + + private IFrameBasedClock parentGameplayClock; + + [BackgroundDependencyLoader(true)] + private void load(GameplayClock clock) + { + if (clock != null) + parentGameplayClock = clock; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + setClock(); + } + + /// + /// Whether we are running up-to-date with our parent clock. + /// If not, we will need to keep processing children until we catch up. + /// + private bool requireMoreUpdateLoops; + + /// + /// Whether we are in a valid state (ie. should we keep processing children frames). + /// This should be set to false when the replay is, for instance, waiting for future frames to arrive. + /// + private bool validState; + + protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState; + + private bool isAttached => ReplayInputHandler != null; + + private const int max_catch_up_updates_per_frame = 50; + + private const double sixty_frame_time = 1000.0 / 60; + + public override bool UpdateSubTree() + { + requireMoreUpdateLoops = true; + validState = true; + + int loops = 0; + + while (validState && requireMoreUpdateLoops && loops++ < max_catch_up_updates_per_frame) + { + updateClock(); + + if (validState) + { + base.UpdateSubTree(); + UpdateSubTreeMasking(this, ScreenSpaceDrawQuad.AABBFloat); + } + } + + return true; + } + + private void updateClock() + { + if (parentGameplayClock == null) + setClock(); // LoadComplete may not be run yet, but we still want the clock. + + validState = true; + + manualClock.Rate = parentGameplayClock.Rate; + manualClock.IsRunning = parentGameplayClock.IsRunning; + + var newProposedTime = parentGameplayClock.CurrentTime; + + try + { + if (Math.Abs(manualClock.CurrentTime - newProposedTime) > sixty_frame_time * 1.2f) + { + newProposedTime = manualClock.Rate > 0 + ? Math.Min(newProposedTime, manualClock.CurrentTime + sixty_frame_time) + : Math.Max(newProposedTime, manualClock.CurrentTime - sixty_frame_time); + } + + if (!isAttached) + { + manualClock.CurrentTime = newProposedTime; + } + else + { + double? newTime = ReplayInputHandler.SetFrameFromTime(newProposedTime); + + if (newTime == null) + { + // we shouldn't execute for this time value. probably waiting on more replay data. + validState = false; + + requireMoreUpdateLoops = true; + manualClock.CurrentTime = newProposedTime; + return; + } + + manualClock.CurrentTime = newTime.Value; + } + + requireMoreUpdateLoops = manualClock.CurrentTime != parentGameplayClock.CurrentTime; + } + finally + { + // The manual clock time has changed in the above code. The framed clock now needs to be updated + // to ensure that the its time is valid for our children before input is processed + framedClock.ProcessFrame(); + } + } + + private void setClock() + { + // in case a parent gameplay clock isn't available, just use the parent clock. + if (parentGameplayClock == null) + parentGameplayClock = Clock; + + Clock = gameplayClock; + ProcessCustomClock = false; + } + + #endregion + + #region IHasReplayHandler + + public ReplayInputHandler ReplayInputHandler { get; set; } + + #endregion + } +} diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index ed5f23dc7f..d8813631dc 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -132,6 +132,8 @@ namespace osu.Game.Rulesets.UI protected virtual ReplayInputHandler CreateReplayInputHandler(Replay replay) => null; + protected FrameStabilityContainer FrameStabilityContainer; + public Score ReplayScore { get; private set; } /// @@ -149,7 +151,11 @@ namespace osu.Game.Rulesets.UI throw new InvalidOperationException($"A {nameof(KeyBindingInputManager)} which supports replay loading is not available"); ReplayScore = replayScore; - ReplayInputManager.ReplayInputHandler = replayScore != null ? CreateReplayInputHandler(replayScore.Replay) : null; + + var handler = replayScore != null ? CreateReplayInputHandler(replayScore.Replay) : null; + + ReplayInputManager.ReplayInputHandler = handler; + FrameStabilityContainer.ReplayInputHandler = handler; HasReplayLoaded.Value = ReplayInputManager.ReplayInputHandler != null; } @@ -243,7 +249,6 @@ namespace osu.Game.Rulesets.UI Beatmap = (Beatmap)workingBeatmap.GetPlayableBeatmap(ruleset.RulesetInfo); KeyBindingInputManager = CreateInputManager(); - KeyBindingInputManager.RelativeSizeAxes = Axes.Both; applyBeatmapMods(Mods); } @@ -262,7 +267,10 @@ namespace osu.Game.Rulesets.UI InternalChildren = new Drawable[] { - KeyBindingInputManager, + FrameStabilityContainer = new FrameStabilityContainer + { + Child = KeyBindingInputManager, + }, Overlays = new Container { RelativeSizeAxes = Axes.Both } }; diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 87220a37e8..e303166774 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.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; @@ -12,7 +11,6 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Input.StateChanges.Events; using osu.Framework.Input.States; -using osu.Framework.Timing; using osu.Game.Configuration; using osu.Game.Input.Bindings; using osu.Game.Input.Handlers; @@ -41,7 +39,12 @@ namespace osu.Game.Rulesets.UI protected RulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) { InternalChild = KeyBindingContainer = CreateKeyBindingContainer(ruleset, variant, unique); - gameplayClock = new GameplayClock(framedClock = new FramedClock(manualClock = new ManualClock())); + } + + [BackgroundDependencyLoader(true)] + private void load(OsuConfigManager config) + { + mouseDisabled = config.GetBindable(OsuSetting.MouseDisableButtons); } #region Action mapping (for replays) @@ -85,137 +88,6 @@ namespace osu.Game.Rulesets.UI #endregion - #region Clock control - - private readonly ManualClock manualClock; - - private readonly FramedClock framedClock; - - [Cached] - private GameplayClock gameplayClock; - - private IFrameBasedClock parentGameplayClock; - - [BackgroundDependencyLoader(true)] - private void load(OsuConfigManager config, GameplayClock clock) - { - mouseDisabled = config.GetBindable(OsuSetting.MouseDisableButtons); - - if (clock != null) - parentGameplayClock = clock; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - setClock(); - } - - /// - /// Whether we are running up-to-date with our parent clock. - /// If not, we will need to keep processing children until we catch up. - /// - private bool requireMoreUpdateLoops; - - /// - /// Whether we are in a valid state (ie. should we keep processing children frames). - /// This should be set to false when the replay is, for instance, waiting for future frames to arrive. - /// - private bool validState; - - protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState; - - private bool isAttached => replayInputHandler != null && !UseParentInput; - - private const int max_catch_up_updates_per_frame = 50; - - private const double sixty_frame_time = 1000.0 / 60; - - public override bool UpdateSubTree() - { - requireMoreUpdateLoops = true; - validState = true; - - int loops = 0; - - while (validState && requireMoreUpdateLoops && loops++ < max_catch_up_updates_per_frame) - { - updateClock(); - - if (validState) - { - base.UpdateSubTree(); - UpdateSubTreeMasking(this, ScreenSpaceDrawQuad.AABBFloat); - } - } - - return true; - } - - private void updateClock() - { - if (parentGameplayClock == null) - setClock(); // LoadComplete may not be run yet, but we still want the clock. - - validState = true; - - manualClock.Rate = parentGameplayClock.Rate; - manualClock.IsRunning = parentGameplayClock.IsRunning; - - var newProposedTime = parentGameplayClock.CurrentTime; - - try - { - if (Math.Abs(manualClock.CurrentTime - newProposedTime) > sixty_frame_time * 1.2f) - { - newProposedTime = manualClock.Rate > 0 - ? Math.Min(newProposedTime, manualClock.CurrentTime + sixty_frame_time) - : Math.Max(newProposedTime, manualClock.CurrentTime - sixty_frame_time); - } - - if (!isAttached) - { - manualClock.CurrentTime = newProposedTime; - } - else - { - double? newTime = replayInputHandler.SetFrameFromTime(newProposedTime); - - if (newTime == null) - { - // we shouldn't execute for this time value. probably waiting on more replay data. - validState = false; - - requireMoreUpdateLoops = true; - manualClock.CurrentTime = newProposedTime; - return; - } - - manualClock.CurrentTime = newTime.Value; - } - - requireMoreUpdateLoops = manualClock.CurrentTime != parentGameplayClock.CurrentTime; - } - finally - { - // The manual clock time has changed in the above code. The framed clock now needs to be updated - // to ensure that the its time is valid for our children before input is processed - framedClock.ProcessFrame(); - } - } - - private void setClock() - { - // in case a parent gameplay clock isn't available, just use the parent clock. - if (parentGameplayClock == null) - parentGameplayClock = Clock; - - Clock = gameplayClock; - ProcessCustomClock = false; - } - - #endregion - #region Setting application (disables etc.) private Bindable mouseDisabled; From c496f6e56bc6440ba91f12a52971f4e8f4b4c65e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 17 Mar 2019 13:43:23 +0900 Subject: [PATCH 48/64] Fix usages of OnLoadComplete --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 2 +- .../UpdateableBeatmapBackgroundSprite.cs | 2 +- .../Drawables/UpdateableBeatmapSetCover.cs | 7 +++++-- osu.Game/Online/Leaderboards/LeaderboardScore.cs | 7 +++++-- .../Overlays/Chat/Tabs/PrivateChannelTabItem.cs | 7 +++++-- osu.Game/Overlays/MedalSplash/DrawableMedal.cs | 2 +- osu.Game/Overlays/Profile/ProfileHeader.cs | 7 +++++-- .../Multi/Match/Components/Participants.cs | 16 +++++++++++----- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- .../Carousel/DrawableCarouselBeatmapSet.cs | 11 ++++++++--- osu.Game/Users/UpdateableAvatar.cs | 2 +- osu.Game/Users/UserPanel.cs | 7 +++++-- 12 files changed, 49 insertions(+), 23 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index d0f50c6af2..c6dd0a86a0 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Catch.UI if (lastPlateableFruit.IsLoaded) action(); else - lastPlateableFruit.OnLoadComplete = _ => action(); + lastPlateableFruit.OnLoadComplete += _ => action(); } if (result.IsHit && fruit.CanBePlated) diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs index ec75c1a1fb..ce7811fc0d 100644 --- a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs +++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs @@ -51,7 +51,7 @@ namespace osu.Game.Beatmaps.Drawables drawable.Anchor = Anchor.Centre; drawable.Origin = Anchor.Centre; drawable.FillMode = FillMode.Fill; - drawable.OnLoadComplete = d => d.FadeInFromZero(400); + drawable.OnLoadComplete += d => d.FadeInFromZero(400); return drawable; } diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs index 367b63d6d1..c7c4c1fb1e 100644 --- a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs +++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs @@ -67,16 +67,19 @@ namespace osu.Game.Beatmaps.Drawables if (beatmapSet != null) { + BeatmapSetCover cover; + Add(displayedCover = new DelayedLoadWrapper( - new BeatmapSetCover(beatmapSet, coverType) + cover = new BeatmapSetCover(beatmapSet, coverType) { Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fill, - OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), }) ); + + cover.OnLoadComplete += d => d.FadeInFromZero(400, Easing.Out); } } } diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index 34981bf849..c5602fc4ad 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -64,6 +64,8 @@ namespace osu.Game.Online.Leaderboards statisticsLabels = GetStatistics(score).Select(s => new ScoreComponentLabel(s)).ToList(); + Avatar innerAvatar; + Children = new Drawable[] { new Container @@ -109,12 +111,11 @@ namespace osu.Game.Online.Leaderboards Children = new[] { avatar = new DelayedLoadWrapper( - new Avatar(user) + innerAvatar = new Avatar(user) { RelativeSizeAxes = Axes.Both, CornerRadius = corner_radius, Masking = true, - OnLoadComplete = d => d.FadeInFromZero(200), EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Shadow, @@ -214,6 +215,8 @@ namespace osu.Game.Online.Leaderboards }, }, }; + + innerAvatar.OnLoadComplete += d => d.FadeInFromZero(200); } public override void Show() diff --git a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs index 8cedde82ff..8111ac7394 100644 --- a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs @@ -28,6 +28,8 @@ namespace osu.Game.Overlays.Chat.Tabs if (value.Type != ChannelType.PM) throw new ArgumentException("Argument value needs to have the targettype user!"); + Avatar avatar; + AddRange(new Drawable[] { new Container @@ -49,11 +51,10 @@ namespace osu.Game.Overlays.Chat.Tabs Anchor = Anchor.Centre, Origin = Anchor.Centre, Masking = true, - Child = new DelayedLoadWrapper(new Avatar(value.Users.First()) + Child = new DelayedLoadWrapper(avatar = new Avatar(value.Users.First()) { RelativeSizeAxes = Axes.Both, OpenOnClick = { Value = false }, - OnLoadComplete = d => d.FadeInFromZero(300, Easing.OutQuint), }) { RelativeSizeAxes = Axes.Both, @@ -63,6 +64,8 @@ namespace osu.Game.Overlays.Chat.Tabs }, }); + avatar.OnLoadComplete += d => d.FadeInFromZero(300, Easing.OutQuint); + Text.X = ChatOverlay.TAB_AREA_HEIGHT; TextBold.X = ChatOverlay.TAB_AREA_HEIGHT; } diff --git a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs index eeb42ec991..431ae98c2c 100644 --- a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs +++ b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs @@ -109,7 +109,7 @@ namespace osu.Game.Overlays.MedalSplash s.Font = s.Font.With(size: 16); }); - medalContainer.OnLoadComplete = d => + medalContainer.OnLoadComplete += d => { unlocked.Position = new Vector2(0f, medalContainer.DrawSize.Y / 2 + 10); infoFlow.Position = new Vector2(0f, unlocked.Position.Y + 90); diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 2641a0551d..c41d977701 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -335,9 +335,12 @@ namespace osu.Game.Overlays.Profile Anchor = Anchor.Centre, Origin = Anchor.Centre, FillMode = FillMode.Fill, - OnLoadComplete = d => d.FadeInFromZero(200), Depth = float.MaxValue, - }, coverContainer.Add); + }, background => + { + coverContainer.Add(background); + background.FadeInFromZero(200); + }); if (user.IsSupporter) SupporterTag.Show(); diff --git a/osu.Game/Screens/Multi/Match/Components/Participants.cs b/osu.Game/Screens/Multi/Match/Components/Participants.cs index 2d6099c65d..09d25572ec 100644 --- a/osu.Game/Screens/Multi/Match/Components/Participants.cs +++ b/osu.Game/Screens/Multi/Match/Components/Participants.cs @@ -52,12 +52,18 @@ namespace osu.Game.Screens.Multi.Match.Components Participants.BindValueChanged(participants => { - usersFlow.Children = participants.NewValue.Select(u => new UserPanel(u) + usersFlow.Children = participants.NewValue.Select(u => { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Width = 300, - OnLoadComplete = d => d.FadeInFromZero(60), + var panel = new UserPanel(u) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Width = 300, + }; + + panel.OnLoadComplete += d => d.FadeInFromZero(60); + + return panel; }).ToList(); }, true); } diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 389f614ef2..bfd1d3d236 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -577,7 +577,7 @@ namespace osu.Game.Screens.Select else { float y = currentY; - d.OnLoadComplete = _ => performMove(y, setY); + d.OnLoadComplete += _ => performMove(y, setY); } break; diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index e01149ebc8..51ca9902d2 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -49,11 +49,16 @@ namespace osu.Game.Screens.Select.Carousel Children = new Drawable[] { new DelayedLoadUnloadWrapper(() => - new PanelBackground(manager.GetWorkingBeatmap(beatmapSet.Beatmaps.FirstOrDefault())) + { + var background = new PanelBackground(manager.GetWorkingBeatmap(beatmapSet.Beatmaps.FirstOrDefault())) { RelativeSizeAxes = Axes.Both, - OnLoadComplete = d => d.FadeInFromZero(1000, Easing.OutQuint), - }, 300, 5000 + }; + + background.OnLoadComplete += d => d.FadeInFromZero(1000, Easing.OutQuint); + + return background; + }, 300, 5000 ), new FillFlowContainer { diff --git a/osu.Game/Users/UpdateableAvatar.cs b/osu.Game/Users/UpdateableAvatar.cs index cefb91797b..7259468674 100644 --- a/osu.Game/Users/UpdateableAvatar.cs +++ b/osu.Game/Users/UpdateableAvatar.cs @@ -57,9 +57,9 @@ namespace osu.Game.Users var avatar = new Avatar(user) { RelativeSizeAxes = Axes.Both, - OnLoadComplete = d => d.FadeInFromZero(300, Easing.OutQuint), }; + avatar.OnLoadComplete += d => d.FadeInFromZero(300, Easing.OutQuint); avatar.OpenOnClick.BindTo(OpenOnClick); Add(displayedAvatar = new DelayedLoadWrapper(avatar)); diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index 4dfde04e07..65062dc58e 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -59,6 +59,8 @@ namespace osu.Game.Users FillFlowContainer infoContainer; + UserCoverBackground coverBackground; + AddInternal(content = new Container { RelativeSizeAxes = Axes.Both, @@ -73,13 +75,12 @@ namespace osu.Game.Users Children = new Drawable[] { - new DelayedLoadWrapper(new UserCoverBackground(user) + new DelayedLoadWrapper(coverBackground = new UserCoverBackground(user) { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, FillMode = FillMode.Fill, - OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out) }, 300) { RelativeSizeAxes = Axes.Both }, new Box { @@ -181,6 +182,8 @@ namespace osu.Game.Users } }); + coverBackground.OnLoadComplete += d => d.FadeInFromZero(400, Easing.Out); + if (user.IsSupporter) { infoContainer.Add(new SupporterIcon From 9ca4d9d4d1acff69ae673621b7fdcec0b9b92178 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Mar 2019 10:48:44 +0900 Subject: [PATCH 49/64] Remove regions --- osu.Game/Rulesets/UI/FrameStabilityContainer.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 921ed46d0e..161e7aecb4 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -23,8 +23,6 @@ namespace osu.Game.Rulesets.UI gameplayClock = new GameplayClock(framedClock = new FramedClock(manualClock = new ManualClock())); } - #region Clock control - private readonly ManualClock manualClock; private readonly FramedClock framedClock; @@ -150,12 +148,6 @@ namespace osu.Game.Rulesets.UI ProcessCustomClock = false; } - #endregion - - #region IHasReplayHandler - public ReplayInputHandler ReplayInputHandler { get; set; } - - #endregion } } From 6a26972284d9cc6d89cea1263331fedb28510c0d Mon Sep 17 00:00:00 2001 From: David Zhao Date: Mon, 18 Mar 2019 15:25:54 +0900 Subject: [PATCH 50/64] DI gameplay clock for Storyboards --- osu.Game/Storyboards/Drawables/DrawableStoryboard.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index f5e1f612ca..12507b215e 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; using osu.Game.IO; +using osu.Game.Screens.Play; namespace osu.Game.Storyboards.Drawables { @@ -56,8 +57,11 @@ namespace osu.Game.Storyboards.Drawables } [BackgroundDependencyLoader] - private void load(FileStore fileStore) + private void load(FileStore fileStore, GameplayClock clock) { + if (Clock != null) + Clock = clock; + dependencies.Cache(new TextureStore(new TextureLoaderStore(fileStore.Store), false, scaleAdjust: 1)); foreach (var layer in Storyboard.Layers) From 05147768d3100d3e429df27b62acaf5ee4ee1128 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Mon, 18 Mar 2019 15:50:34 +0900 Subject: [PATCH 51/64] Permit nulls --- osu.Game/Storyboards/Drawables/DrawableStoryboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index 12507b215e..ffd9b71254 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -56,7 +56,7 @@ namespace osu.Game.Storyboards.Drawables }); } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(FileStore fileStore, GameplayClock clock) { if (Clock != null) From acc133896ba4acfb29badc842d4f7531e2733825 Mon Sep 17 00:00:00 2001 From: David Zhao Date: Mon, 18 Mar 2019 18:19:59 +0900 Subject: [PATCH 52/64] Correct null check --- osu.Game/Storyboards/Drawables/DrawableStoryboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index ffd9b71254..1182cacfc1 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -59,7 +59,7 @@ namespace osu.Game.Storyboards.Drawables [BackgroundDependencyLoader(true)] private void load(FileStore fileStore, GameplayClock clock) { - if (Clock != null) + if (clock != null) Clock = clock; dependencies.Cache(new TextureStore(new TextureLoaderStore(fileStore.Store), false, scaleAdjust: 1)); From bb8171b88a1fdd95ef90a4f4ef7bfe448b6c40dc Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 18 Mar 2019 18:36:16 +0900 Subject: [PATCH 53/64] Fix HR mod being applied to non-fruit objects --- osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs index 0cfa3e98f7..c04afb4ddb 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs @@ -20,6 +20,9 @@ namespace osu.Game.Rulesets.Catch.Mods public void ApplyToHitObject(HitObject hitObject) { + if (!(hitObject is Fruit)) + return; + var catchObject = (CatchHitObject)hitObject; float position = catchObject.X; From a26e237e261ec83883962f0b971da2242222193b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 18 Mar 2019 18:59:38 +0900 Subject: [PATCH 54/64] Fix relative position being compared to time --- osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs index c04afb4ddb..e96a9c7441 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Catch.Mods return; } - if (Math.Abs(diff) < timeDiff / 3d) + if (Math.Abs(diff * CatchPlayfield.BASE_WIDTH) < timeDiff / 3d) { if (diff > 0) { From 1b696ade50b6b4c202f28aac0fc9fb1b9655084d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 19 Mar 2019 14:10:39 +0900 Subject: [PATCH 55/64] Refactor to reduce code complexity --- .../Mods/CatchModHardRock.cs | 104 ++++++++++-------- 1 file changed, 61 insertions(+), 43 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs index e96a9c7441..ad7e762f6e 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs @@ -15,8 +15,8 @@ namespace osu.Game.Rulesets.Catch.Mods public override double ScoreMultiplier => 1.12; public override bool Ranked => true; - private float lastStartX; - private int lastStartTime; + private float? lastPosition; + private double lastStartTime; public void ApplyToHitObject(HitObject hitObject) { @@ -26,69 +26,87 @@ namespace osu.Game.Rulesets.Catch.Mods var catchObject = (CatchHitObject)hitObject; float position = catchObject.X; - int startTime = (int)hitObject.StartTime; + double startTime = hitObject.StartTime; - if (lastStartX == 0) + if (lastPosition == null) { - lastStartX = position; + lastPosition = position; lastStartTime = startTime; + return; } - float diff = lastStartX - position; - int timeDiff = startTime - lastStartTime; + float positionDiff = lastPosition.Value - position; + double timeDiff = startTime - lastStartTime; if (timeDiff > 1000) { - lastStartX = position; + lastPosition = position; lastStartTime = startTime; return; } - if (diff == 0) + if (positionDiff == 0) { - bool right = RNG.NextBool(); - - float rand = Math.Min(20, (float)RNG.NextDouble(0, timeDiff / 4d)) / CatchPlayfield.BASE_WIDTH; - - if (right) - { - if (position + rand <= 1) - position += rand; - else - position -= rand; - } - else - { - if (position - rand >= 0) - position -= rand; - else - position += rand; - } - + applyRandomOffset(ref position, timeDiff / 4d); catchObject.X = position; - return; } - if (Math.Abs(diff * CatchPlayfield.BASE_WIDTH) < timeDiff / 3d) - { - if (diff > 0) - { - if (position - diff > 0) - position -= diff; - } - else - { - if (position - diff < 1) - position -= diff; - } - } + if (Math.Abs(positionDiff * CatchPlayfield.BASE_WIDTH) < timeDiff / 3d) + applyOffset(ref position, positionDiff); catchObject.X = position; - lastStartX = position; + lastPosition = position; lastStartTime = startTime; } + + /// + /// Applies a random offset in a random direction to a position, ensuring that the final position remains within the boundary of the playfield. + /// + /// The position which the offset should be applied to. + /// The maximum offset, cannot exceed 20px. + private void applyRandomOffset(ref float position, double maxOffset) + { + bool right = RNG.NextBool(); + float rand = Math.Min(20, (float)RNG.NextDouble(0, maxOffset)) / CatchPlayfield.BASE_WIDTH; + + if (right) + { + // Clamp to the right bound + if (position + rand <= 1) + position += rand; + else + position -= rand; + } + else + { + // Clamp to the left bound + if (position - rand >= 0) + position -= rand; + else + position += rand; + } + } + + /// + /// Applies an offset to a position, ensuring that the final position remains within the boundary of the playfield. + /// + /// The position which the offset should be applied to. + /// The amount to offset by. + private void applyOffset(ref float position, float amount) + { + if (amount > 0) + { + if (position - amount > 0) + position -= amount; + } + else + { + if (position - amount < 1) + position -= amount; + } + } } } From 5b07cce3cb4cf888194f98d49de0517717aede12 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 19 Mar 2019 14:12:10 +0900 Subject: [PATCH 56/64] Invert unintuitive variable --- osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs index ad7e762f6e..275c9a500c 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModHardRock.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.Mods return; } - float positionDiff = lastPosition.Value - position; + float positionDiff = position - lastPosition.Value; double timeDiff = startTime - lastStartTime; if (timeDiff > 1000) @@ -99,13 +99,15 @@ namespace osu.Game.Rulesets.Catch.Mods { if (amount > 0) { - if (position - amount > 0) - position -= amount; + // Clamp to the right bound + if (position + amount < 1) + position += amount; } else { - if (position - amount < 1) - position -= amount; + // Clamp to the left bound + if (position + amount > 0) + position += amount; } } } From 5d9477e1e4935df5357c86f30a260f79aef67526 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 19 Mar 2019 15:35:14 +0900 Subject: [PATCH 57/64] Fix difficulty calculation using the pre-mod catcher size --- .../Difficulty/CatchDifficultyCalculator.cs | 8 +++++++- osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs | 9 +++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index f3b88bd928..502aeac84d 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -23,11 +23,17 @@ namespace osu.Game.Rulesets.Catch.Difficulty protected override int SectionLength => 750; - private readonly float halfCatchWidth; + private float halfCatchWidth; public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { + } + + protected override void PreProcess(IBeatmap beatmap, Mod[] mods, double clockRate) + { + base.PreProcess(beatmap, mods, clockRate); + var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty); halfCatchWidth = catcher.CatchWidth * 0.5f; diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index db8bdde6bb..c404fc6909 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -63,6 +63,8 @@ namespace osu.Game.Rulesets.Difficulty private DifficultyAttributes calculate(IBeatmap beatmap, Mod[] mods, double clockRate) { + PreProcess(beatmap, mods, clockRate); + var skills = CreateSkills(beatmap); if (!beatmap.HitObjects.Any()) @@ -99,6 +101,13 @@ namespace osu.Game.Rulesets.Difficulty return CreateDifficultyAttributes(beatmap, mods, skills, clockRate); } + /// + /// Computes any values to be used for difficulty calculation, prior to difficulty calculation taking place. + /// + protected virtual void PreProcess(IBeatmap beatmap, Mod[] mods, double clockRate) + { + } + /// /// Creates all combinations which adjust the difficulty. /// From 57727ac184443ea6c6336fc78830a969222bc77d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 19 Mar 2019 15:53:27 +0900 Subject: [PATCH 58/64] Remove preprocess until a later point in time --- .../Difficulty/CatchDifficultyCalculator.cs | 26 +++++++++---------- .../Difficulty/DifficultyCalculator.cs | 9 ------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 502aeac84d..a3d5165df5 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -23,24 +23,13 @@ namespace osu.Game.Rulesets.Catch.Difficulty protected override int SectionLength => 750; - private float halfCatchWidth; + private float? halfCatchWidth; public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { } - protected override void PreProcess(IBeatmap beatmap, Mod[] mods, double clockRate) - { - base.PreProcess(beatmap, mods, clockRate); - - var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty); - halfCatchWidth = catcher.CatchWidth * 0.5f; - - // We're only using 80% of the catcher's width to simulate imperfect gameplay. - halfCatchWidth *= 0.8f; - } - protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) { if (beatmap.HitObjects.Count == 0) @@ -60,6 +49,15 @@ namespace osu.Game.Rulesets.Catch.Difficulty protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) { + if (halfCatchWidth == null) + { + var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty); + halfCatchWidth = catcher.CatchWidth * 0.5f; + + // We're only using 80% of the catcher's width to simulate imperfect gameplay. + halfCatchWidth *= 0.8f; + } + CatchHitObject lastObject = null; foreach (var hitObject in beatmap.HitObjects.OfType()) @@ -74,14 +72,14 @@ namespace osu.Game.Rulesets.Catch.Difficulty { // We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations. case Fruit fruit: - yield return new CatchDifficultyHitObject(fruit, lastObject, clockRate, halfCatchWidth); + yield return new CatchDifficultyHitObject(fruit, lastObject, clockRate, halfCatchWidth.Value); lastObject = hitObject; break; case JuiceStream _: foreach (var nested in hitObject.NestedHitObjects.OfType().Where(o => !(o is TinyDroplet))) { - yield return new CatchDifficultyHitObject(nested, lastObject, clockRate, halfCatchWidth); + yield return new CatchDifficultyHitObject(nested, lastObject, clockRate, halfCatchWidth.Value); lastObject = nested; } diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index c404fc6909..db8bdde6bb 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -63,8 +63,6 @@ namespace osu.Game.Rulesets.Difficulty private DifficultyAttributes calculate(IBeatmap beatmap, Mod[] mods, double clockRate) { - PreProcess(beatmap, mods, clockRate); - var skills = CreateSkills(beatmap); if (!beatmap.HitObjects.Any()) @@ -101,13 +99,6 @@ namespace osu.Game.Rulesets.Difficulty return CreateDifficultyAttributes(beatmap, mods, skills, clockRate); } - /// - /// Computes any values to be used for difficulty calculation, prior to difficulty calculation taking place. - /// - protected virtual void PreProcess(IBeatmap beatmap, Mod[] mods, double clockRate) - { - } - /// /// Creates all combinations which adjust the difficulty. /// From dd60e3f1c46e619b5cc454bdeb17897e3943f8da Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 19 Mar 2019 15:59:04 +0900 Subject: [PATCH 59/64] Fix halfCatchWidth not being reset between runs --- .../Difficulty/CatchDifficultyCalculator.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index a3d5165df5..810a7bef97 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -23,8 +23,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty protected override int SectionLength => 750; - private float? halfCatchWidth; - public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { @@ -49,15 +47,15 @@ namespace osu.Game.Rulesets.Catch.Difficulty protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) { - if (halfCatchWidth == null) - { - var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty); - halfCatchWidth = catcher.CatchWidth * 0.5f; + float halfCatchWidth; - // We're only using 80% of the catcher's width to simulate imperfect gameplay. - halfCatchWidth *= 0.8f; + using (var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty)) + { + halfCatchWidth = catcher.CatchWidth * 0.5f; + halfCatchWidth *= 0.8f; // We're only using 80% of the catcher's width to simulate imperfect gameplay. } + CatchHitObject lastObject = null; foreach (var hitObject in beatmap.HitObjects.OfType()) @@ -72,14 +70,14 @@ namespace osu.Game.Rulesets.Catch.Difficulty { // We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations. case Fruit fruit: - yield return new CatchDifficultyHitObject(fruit, lastObject, clockRate, halfCatchWidth.Value); + yield return new CatchDifficultyHitObject(fruit, lastObject, clockRate, halfCatchWidth); lastObject = hitObject; break; case JuiceStream _: foreach (var nested in hitObject.NestedHitObjects.OfType().Where(o => !(o is TinyDroplet))) { - yield return new CatchDifficultyHitObject(nested, lastObject, clockRate, halfCatchWidth.Value); + yield return new CatchDifficultyHitObject(nested, lastObject, clockRate, halfCatchWidth); lastObject = nested; } From d2007cfb3813bcdd836a2cb1e5fac518d5d72bda Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Mar 2019 16:10:28 +0900 Subject: [PATCH 60/64] Fix weird transition --- osu.Game/Screens/Menu/Disclaimer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index af8c127a3c..9f0c75f0ad 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -114,7 +114,7 @@ namespace osu.Game.Screens.Menu currentUser.BindTo(api.LocalUser); currentUser.BindValueChanged(e => { - supportFlow.Children.ForEach(d => d.FadeOut(500, Easing.OutQuint).Expire()); + supportFlow.Children.ForEach(d => d.FadeOut().Expire()); if (e.NewValue.IsSupporter) { @@ -137,6 +137,9 @@ namespace osu.Game.Screens.Menu if (IsLoaded) animateHeart(); + + if (supportFlow.IsPresent) + supportFlow.FadeInFromZero(500); }, true); } From e36ad3eb6b8969279076994e01045cb55383485d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Mar 2019 16:11:22 +0900 Subject: [PATCH 61/64] Add initial alpha in case --- osu.Game/Screens/Menu/Disclaimer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 9f0c75f0ad..e6a90f76c0 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -84,6 +84,7 @@ namespace osu.Game.Screens.Menu TextAnchor = Anchor.TopCentre, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, + Alpha = 0, Spacing = new Vector2(0, 2), }, } From 0fbc049f8dbdc1832d33b40a8bff54ea2f0d20de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Mar 2019 16:25:34 +0900 Subject: [PATCH 62/64] Remove newline --- osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 810a7bef97..b4998347f4 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -55,7 +55,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty halfCatchWidth *= 0.8f; // We're only using 80% of the catcher's width to simulate imperfect gameplay. } - CatchHitObject lastObject = null; foreach (var hitObject in beatmap.HitObjects.OfType()) From def15645f78ca495f55d8f6d006e101786670524 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Mar 2019 17:24:26 +0900 Subject: [PATCH 63/64] Update framework --- .../TestCaseSliderInput.cs | 6 +++--- osu.Game.Tests/Visual/TestCaseAutoplay.cs | 4 ++-- .../Visual/TestCaseBackgroundScreenBeatmap.cs | 10 +++++----- .../Visual/TestCaseBeatmapCarousel.cs | 8 ++++---- .../Visual/TestCaseBeatmapInfoWedge.cs | 6 +++--- .../Visual/TestCaseChannelTabControl.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseChatLink.cs | 2 +- .../Visual/TestCaseHoldForMenuButton.cs | 6 +++--- .../Visual/TestCaseHoldToConfirmOverlay.cs | 2 +- osu.Game.Tests/Visual/TestCaseIdleTracker.cs | 12 ++++++------ .../Visual/TestCaseLoaderAnimation.cs | 16 ++++++++-------- .../Visual/TestCaseMatchSettingsOverlay.cs | 2 +- osu.Game.Tests/Visual/TestCaseMods.cs | 10 +++++----- .../Visual/TestCasePlaySongSelect.cs | 18 +++++++++--------- osu.Game.Tests/Visual/TestCasePlayerLoader.cs | 8 ++++---- osu.Game.Tests/Visual/TestCaseReplay.cs | 4 ++-- .../Visual/TestCaseScreenBreadcrumbControl.cs | 2 +- osu.Game.Tests/Visual/TestCaseSongProgress.cs | 16 ++++++++-------- ...estCaseUpdateableBeatmapBackgroundSprite.cs | 8 ++++---- osu.Game.Tests/Visual/TestCaseUserProfile.cs | 2 +- osu.Game/Tests/Visual/TestCasePlayer.cs | 10 +++++----- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 23 files changed, 81 insertions(+), 81 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderInput.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderInput.cs index 57effe01f1..2f33982d41 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderInput.cs @@ -354,9 +354,9 @@ namespace osu.Game.Rulesets.Osu.Tests judgementResults = new List(); }); - AddUntilStep(() => Beatmap.Value.Track.CurrentTime == 0, "Beatmap at 0"); - AddUntilStep(() => currentPlayer.IsCurrentScreen(), "Wait until player is loaded"); - AddUntilStep(() => allJudgedFired, "Wait for all judged"); + AddUntilStep("Beatmap at 0", () => Beatmap.Value.Track.CurrentTime == 0); + AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen()); + AddUntilStep("Wait for all judged", () => allJudgedFired); } private class ScoreAccessibleReplayPlayer : ReplayPlayer diff --git a/osu.Game.Tests/Visual/TestCaseAutoplay.cs b/osu.Game.Tests/Visual/TestCaseAutoplay.cs index 61339a6af8..09a745c913 100644 --- a/osu.Game.Tests/Visual/TestCaseAutoplay.cs +++ b/osu.Game.Tests/Visual/TestCaseAutoplay.cs @@ -27,8 +27,8 @@ namespace osu.Game.Tests.Visual protected override void AddCheckSteps(Func player) { base.AddCheckSteps(player); - AddUntilStep(() => ((ScoreAccessiblePlayer)player()).ScoreProcessor.TotalScore.Value > 0, "score above zero"); - AddUntilStep(() => ((ScoreAccessiblePlayer)player()).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0), "key counter counted keys"); + 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)); } private class ScoreAccessiblePlayer : Player diff --git a/osu.Game.Tests/Visual/TestCaseBackgroundScreenBeatmap.cs b/osu.Game.Tests/Visual/TestCaseBackgroundScreenBeatmap.cs index 5484824c5b..81aba9bee5 100644 --- a/osu.Game.Tests/Visual/TestCaseBackgroundScreenBeatmap.cs +++ b/osu.Game.Tests/Visual/TestCaseBackgroundScreenBeatmap.cs @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual { setupUserSettings(); AddStep("Start player loader", () => songSelect.Push(playerLoader = new DimAccessiblePlayerLoader(player = new DimAccessiblePlayer()))); - AddUntilStep(() => playerLoader?.IsLoaded ?? false, "Wait for Player Loader to load"); + AddUntilStep("Wait for Player Loader to load", () => playerLoader?.IsLoaded ?? false); AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent()); AddStep("Trigger background preview", () => { @@ -220,7 +220,7 @@ namespace osu.Game.Tests.Visual AddAssert("Screen is undimmed", () => songSelect.IsBackgroundUndimmed()); } - private void waitForDim() => AddWaitStep(5, "Wait for dim"); + private void waitForDim() => AddWaitStep("Wait for dim", 5); private void createFakeStoryboard() => AddStep("Create storyboard", () => { @@ -249,14 +249,14 @@ namespace osu.Game.Tests.Visual Ready = true, })); }); - AddUntilStep(() => playerLoader.IsLoaded, "Wait for Player Loader to load"); + AddUntilStep("Wait for Player Loader to load", () => playerLoader.IsLoaded); AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); - AddUntilStep(() => player.IsLoaded, "Wait for player to load"); + AddUntilStep("Wait for player to load", () => player.IsLoaded); } private void setupUserSettings() { - AddUntilStep(() => songSelect.Carousel.SelectedBeatmap != null, "Song select has selection"); + AddUntilStep("Song select has selection", () => songSelect.Carousel.SelectedBeatmap != null); AddStep("Set default user settings", () => { Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { new OsuModNoFail() }); diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs index 618d8376c0..956d84618c 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs @@ -87,7 +87,7 @@ namespace osu.Game.Tests.Visual carousel.BeatmapSetsChanged = () => changed = true; carousel.BeatmapSets = beatmapSets; }); - AddUntilStep(() => changed, "Wait for load"); + AddUntilStep("Wait for load", () => changed); } private void ensureRandomFetchSuccess() => @@ -214,7 +214,7 @@ namespace osu.Game.Tests.Visual checkSelected(3, 2); AddStep("Un-filter (debounce)", () => carousel.Filter(new FilterCriteria())); - AddUntilStep(() => !carousel.PendingFilterTask, "Wait for debounce"); + AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask); checkVisibleItemCount(diff: false, count: set_count); checkVisibleItemCount(diff: true, count: 3); @@ -327,13 +327,13 @@ namespace osu.Game.Tests.Visual AddStep("Remove first", () => carousel.RemoveBeatmapSet(carousel.BeatmapSets.First())); checkSelected(1); - AddUntilStep(() => + AddUntilStep("Remove all", () => { if (!carousel.BeatmapSets.Any()) return true; carousel.RemoveBeatmapSet(carousel.BeatmapSets.Last()); return false; - }, "Remove all"); + }); checkNoSelection(); } diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs index 31bb8b64a3..0d77ac666b 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapInfoWedge.cs @@ -56,11 +56,11 @@ namespace osu.Game.Tests.Visual // select part is redundant, but wait for load isn't selectBeatmap(Beatmap.Value.Beatmap); - AddWaitStep(3); + AddWaitStep("wait for select", 3); AddStep("hide", () => { infoWedge.State = Visibility.Hidden; }); - AddWaitStep(3); + AddWaitStep("wait for hide", 3); AddStep("show", () => { infoWedge.State = Visibility.Visible; }); @@ -135,7 +135,7 @@ namespace osu.Game.Tests.Visual infoWedge.Beatmap = Beatmap.Value = b == null ? Beatmap.Default : new TestWorkingBeatmap(b); }); - AddUntilStep(() => infoWedge.Info != infoBefore, "wait for async load"); + AddUntilStep("wait for async load", () => infoWedge.Info != infoBefore); } private IBeatmap createTestBeatmap(RulesetInfo ruleset) diff --git a/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs b/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs index 749303b1bb..e90b5f5372 100644 --- a/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs +++ b/osu.Game.Tests/Visual/TestCaseChannelTabControl.cs @@ -90,7 +90,7 @@ namespace osu.Game.Tests.Visual AddStep("set second channel", () => channelTabControl.Current.Value = channelTabControl.Items.Skip(1).First()); AddAssert("selector tab is inactive", () => !channelTabControl.ChannelSelectorActive.Value); - AddUntilStep(() => + AddUntilStep("remove all channels", () => { var first = channelTabControl.Items.First(); if (first.Name == "+") @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual channelTabControl.RemoveChannel(first); return false; - }, "remove all channels"); + }); AddAssert("selector tab is active", () => channelTabControl.ChannelSelectorActive.Value); } diff --git a/osu.Game.Tests/Visual/TestCaseChatLink.cs b/osu.Game.Tests/Visual/TestCaseChatLink.cs index b2ec2c9b47..ecab64ccf3 100644 --- a/osu.Game.Tests/Visual/TestCaseChatLink.cs +++ b/osu.Game.Tests/Visual/TestCaseChatLink.cs @@ -159,7 +159,7 @@ namespace osu.Game.Tests.Visual Scheduler.AddDelayed(() => newLine.Message = new DummyMessage(completeText ?? text), delay); }); - AddUntilStep(() => textContainer.All(line => line.Message is DummyMessage), $"wait for msg #{echoCounter}"); + AddUntilStep($"wait for msg #{echoCounter}", () => textContainer.All(line => line.Message is DummyMessage)); } } diff --git a/osu.Game.Tests/Visual/TestCaseHoldForMenuButton.cs b/osu.Game.Tests/Visual/TestCaseHoldForMenuButton.cs index 5ee1340044..a4fadbd3db 100644 --- a/osu.Game.Tests/Visual/TestCaseHoldForMenuButton.cs +++ b/osu.Game.Tests/Visual/TestCaseHoldForMenuButton.cs @@ -32,9 +32,9 @@ namespace osu.Game.Tests.Visual var text = holdForMenuButton.Children.OfType().First(); AddStep("Trigger text fade in", () => InputManager.MoveMouseTo(holdForMenuButton)); - AddUntilStep(() => text.IsPresent && !exitAction, "Text visible"); + AddUntilStep("Text visible", () => text.IsPresent && !exitAction); AddStep("Trigger text fade out", () => InputManager.MoveMouseTo(Vector2.One)); - AddUntilStep(() => !text.IsPresent && !exitAction, "Text is not visible"); + AddUntilStep("Text is not visible", () => !text.IsPresent && !exitAction); AddStep("Trigger exit action", () => { @@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual AddAssert("action not triggered", () => !exitAction); AddStep("Trigger exit action", () => InputManager.PressButton(MouseButton.Left)); - AddUntilStep(() => exitAction, $"{nameof(holdForMenuButton.Action)} was triggered"); + AddUntilStep($"{nameof(holdForMenuButton.Action)} was triggered", () => exitAction); } } } diff --git a/osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs b/osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs index f66bf34875..c9a7e9c39f 100644 --- a/osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseHoldToConfirmOverlay.cs @@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual AddStep("start confirming", () => overlay.Begin()); - AddUntilStep(() => fired, "wait until confirmed"); + AddUntilStep("wait until confirmed", () => fired); } private class TestHoldToConfirmOverlay : ExitConfirmOverlay diff --git a/osu.Game.Tests/Visual/TestCaseIdleTracker.cs b/osu.Game.Tests/Visual/TestCaseIdleTracker.cs index 8e8c4e38ae..a7a1831ba7 100644 --- a/osu.Game.Tests/Visual/TestCaseIdleTracker.cs +++ b/osu.Game.Tests/Visual/TestCaseIdleTracker.cs @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual { AddStep("move mouse to top left", () => InputManager.MoveMouseTo(box1.ScreenSpaceDrawQuad.Centre)); - AddUntilStep(() => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle, "Wait for all idle"); + AddUntilStep("Wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle); AddStep("nudge mouse", () => InputManager.MoveMouseTo(box1.ScreenSpaceDrawQuad.Centre + new Vector2(1))); @@ -87,7 +87,7 @@ namespace osu.Game.Tests.Visual AddAssert("check idle", () => !box3.IsIdle); AddAssert("check idle", () => !box4.IsIdle); - AddUntilStep(() => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle, "Wait for all idle"); + AddUntilStep("Wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle); } [Test] @@ -96,13 +96,13 @@ namespace osu.Game.Tests.Visual AddStep("move mouse", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.Centre)); AddAssert("check not idle", () => !box1.IsIdle && !box2.IsIdle && !box3.IsIdle && !box4.IsIdle); - AddUntilStep(() => box1.IsIdle, "Wait for idle"); + AddUntilStep("Wait for idle", () => box1.IsIdle); AddAssert("check not idle", () => !box2.IsIdle && !box3.IsIdle && !box4.IsIdle); - AddUntilStep(() => box2.IsIdle, "Wait for idle"); + AddUntilStep("Wait for idle", () => box2.IsIdle); AddAssert("check not idle", () => !box3.IsIdle && !box4.IsIdle); - AddUntilStep(() => box3.IsIdle, "Wait for idle"); + AddUntilStep("Wait for idle", () => box3.IsIdle); - AddUntilStep(() => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle, "Wait for all idle"); + AddUntilStep("Wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle); } private class IdleTrackingBox : CompositeDrawable diff --git a/osu.Game.Tests/Visual/TestCaseLoaderAnimation.cs b/osu.Game.Tests/Visual/TestCaseLoaderAnimation.cs index 2088f97580..3803764194 100644 --- a/osu.Game.Tests/Visual/TestCaseLoaderAnimation.cs +++ b/osu.Game.Tests/Visual/TestCaseLoaderAnimation.cs @@ -25,30 +25,30 @@ namespace osu.Game.Tests.Visual bool logoVisible = false; AddStep("almost instant display", () => Child = loader = new TestLoader(250)); - AddUntilStep(() => + AddUntilStep("loaded", () => { logoVisible = loader.Logo?.Alpha > 0; return loader.Logo != null && loader.ScreenLoaded; - }, "loaded"); + }); AddAssert("logo not visible", () => !logoVisible); AddStep("short load", () => Child = loader = new TestLoader(800)); - AddUntilStep(() => + AddUntilStep("loaded", () => { logoVisible = loader.Logo?.Alpha > 0; return loader.Logo != null && loader.ScreenLoaded; - }, "loaded"); + }); AddAssert("logo visible", () => logoVisible); - AddUntilStep(() => loader.Logo?.Alpha == 0, "logo gone"); + AddUntilStep("logo gone", () => loader.Logo?.Alpha == 0); AddStep("longer load", () => Child = loader = new TestLoader(1400)); - AddUntilStep(() => + AddUntilStep("loaded", () => { logoVisible = loader.Logo?.Alpha > 0; return loader.Logo != null && loader.ScreenLoaded; - }, "loaded"); + }); AddAssert("logo visible", () => logoVisible); - AddUntilStep(() => loader.Logo?.Alpha == 0, "logo gone"); + AddUntilStep("logo gone", () => loader.Logo?.Alpha == 0); } private class TestLoader : Loader diff --git a/osu.Game.Tests/Visual/TestCaseMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/TestCaseMatchSettingsOverlay.cs index a320fc88fa..11c7d3ef70 100644 --- a/osu.Game.Tests/Visual/TestCaseMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseMatchSettingsOverlay.cs @@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual settings.ApplyButton.Action.Invoke(); }); - AddUntilStep(() => !settings.ErrorText.IsPresent, "error not displayed"); + AddUntilStep("error not displayed", () => !settings.ErrorText.IsPresent); } private class TestRoomSettings : MatchSettingsOverlay diff --git a/osu.Game.Tests/Visual/TestCaseMods.cs b/osu.Game.Tests/Visual/TestCaseMods.cs index 99bc10d8cc..cb7e783bee 100644 --- a/osu.Game.Tests/Visual/TestCaseMods.cs +++ b/osu.Game.Tests/Visual/TestCaseMods.cs @@ -208,22 +208,22 @@ namespace osu.Game.Tests.Visual { checkLabelColor(Color4.White); selectNext(mod); - AddWaitStep(1, "wait for changing colour"); + AddWaitStep("wait for changing colour", 1); checkLabelColor(colour); selectPrevious(mod); - AddWaitStep(1, "wait for changing colour"); + AddWaitStep("wait for changing colour", 1); checkLabelColor(Color4.White); } private void testRankedText(Mod mod) { - AddWaitStep(1, "wait for fade"); + AddWaitStep("wait for fade", 1); AddAssert("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0); selectNext(mod); - AddWaitStep(1, "wait for fade"); + AddWaitStep("wait for fade", 1); AddAssert("check for unranked", () => modSelect.UnrankedLabel.Alpha != 0); selectPrevious(mod); - AddWaitStep(1, "wait for fade"); + AddWaitStep("wait for fade", 1); AddAssert("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0); } diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 5fa818472c..4a2cf24c6d 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -112,10 +112,10 @@ namespace osu.Game.Tests.Visual createSongSelect(); AddAssert("dummy selected", () => songSelect.CurrentBeatmap == defaultBeatmap); - AddUntilStep(() => songSelect.CurrentBeatmapDetailsBeatmap == defaultBeatmap, "dummy shown on wedge"); + AddUntilStep("dummy shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap == defaultBeatmap); addManyTestMaps(); - AddWaitStep(3); + AddWaitStep("wait for select", 3); AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); } @@ -125,7 +125,7 @@ namespace osu.Game.Tests.Visual { createSongSelect(); addManyTestMaps(); - AddWaitStep(3); + AddWaitStep("wait for add", 3); AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); @@ -142,7 +142,7 @@ namespace osu.Game.Tests.Visual createSongSelect(); changeRuleset(2); importForRuleset(0); - AddUntilStep(() => songSelect.Carousel.SelectedBeatmap == null, "no selection"); + AddUntilStep("no selection", () => songSelect.Carousel.SelectedBeatmap == null); } [Test] @@ -152,13 +152,13 @@ namespace osu.Game.Tests.Visual changeRuleset(2); importForRuleset(2); importForRuleset(1); - AddUntilStep(() => songSelect.Carousel.SelectedBeatmap.RulesetID == 2, "has selection"); + AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap.RulesetID == 2); changeRuleset(1); - AddUntilStep(() => songSelect.Carousel.SelectedBeatmap.RulesetID == 1, "has selection"); + AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap.RulesetID == 1); changeRuleset(0); - AddUntilStep(() => songSelect.Carousel.SelectedBeatmap == null, "no selection"); + AddUntilStep("no selection", () => songSelect.Carousel.SelectedBeatmap == null); } [Test] @@ -196,7 +196,7 @@ namespace osu.Game.Tests.Visual { createSongSelect(); addManyTestMaps(); - AddUntilStep(() => songSelect.Carousel.SelectedBeatmap != null, "has selection"); + AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null); bool startRequested = false; @@ -225,7 +225,7 @@ namespace osu.Game.Tests.Visual private void createSongSelect() { AddStep("create song select", () => LoadScreen(songSelect = new TestSongSelect())); - AddUntilStep(() => songSelect.IsCurrentScreen(), "wait for present"); + AddUntilStep("wait for present", () => songSelect.IsCurrentScreen()); } private void addManyTestMaps() diff --git a/osu.Game.Tests/Visual/TestCasePlayerLoader.cs b/osu.Game.Tests/Visual/TestCasePlayerLoader.cs index 244f553e97..2bc416f7f4 100644 --- a/osu.Game.Tests/Visual/TestCasePlayerLoader.cs +++ b/osu.Game.Tests/Visual/TestCasePlayerLoader.cs @@ -37,15 +37,15 @@ namespace osu.Game.Tests.Visual AllowResults = false, }))); - AddUntilStep(() => loader.IsCurrentScreen(), "wait for current"); + AddUntilStep("wait for current", () => loader.IsCurrentScreen()); AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre)); - AddUntilStep(() => !loader.IsCurrentScreen(), "wait for no longer current"); + AddUntilStep("wait for no longer current", () => !loader.IsCurrentScreen()); AddStep("exit loader", () => loader.Exit()); - AddUntilStep(() => !loader.IsAlive, "wait for no longer alive"); + AddUntilStep("wait for no longer alive", () => !loader.IsAlive); AddStep("load slow dummy beatmap", () => { @@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual Scheduler.AddDelayed(() => slow.Ready = true, 5000); }); - AddUntilStep(() => !loader.IsCurrentScreen(), "wait for no longer current"); + AddUntilStep("wait for no longer current", () => !loader.IsCurrentScreen()); } protected class SlowLoadPlayer : Player diff --git a/osu.Game.Tests/Visual/TestCaseReplay.cs b/osu.Game.Tests/Visual/TestCaseReplay.cs index c34190d567..5e23b21521 100644 --- a/osu.Game.Tests/Visual/TestCaseReplay.cs +++ b/osu.Game.Tests/Visual/TestCaseReplay.cs @@ -24,8 +24,8 @@ namespace osu.Game.Tests.Visual protected override void AddCheckSteps(Func player) { base.AddCheckSteps(player); - AddUntilStep(() => ((ScoreAccessibleReplayPlayer)player()).ScoreProcessor.TotalScore.Value > 0, "score above zero"); - AddUntilStep(() => ((ScoreAccessibleReplayPlayer)player()).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0), "key counter counted keys"); + 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)); } private class ScoreAccessibleReplayPlayer : ReplayPlayer diff --git a/osu.Game.Tests/Visual/TestCaseScreenBreadcrumbControl.cs b/osu.Game.Tests/Visual/TestCaseScreenBreadcrumbControl.cs index 204f4a493d..dad684689e 100644 --- a/osu.Game.Tests/Visual/TestCaseScreenBreadcrumbControl.cs +++ b/osu.Game.Tests/Visual/TestCaseScreenBreadcrumbControl.cs @@ -74,7 +74,7 @@ namespace osu.Game.Tests.Visual } private void pushNext() => AddStep(@"push next screen", () => ((TestScreen)screenStack.CurrentScreen).PushNext()); - private void waitForCurrent() => AddUntilStep(() => screenStack.CurrentScreen.IsCurrentScreen(), "current screen"); + private void waitForCurrent() => AddUntilStep("current screen", () => screenStack.CurrentScreen.IsCurrentScreen()); private abstract class TestScreen : OsuScreen { diff --git a/osu.Game.Tests/Visual/TestCaseSongProgress.cs b/osu.Game.Tests/Visual/TestCaseSongProgress.cs index cdb1cd2286..511272a5ae 100644 --- a/osu.Game.Tests/Visual/TestCaseSongProgress.cs +++ b/osu.Game.Tests/Visual/TestCaseSongProgress.cs @@ -46,23 +46,23 @@ namespace osu.Game.Tests.Visual Origin = Anchor.TopLeft, }); - AddWaitStep(5); + AddWaitStep("wait some", 5); AddAssert("ensure not created", () => graph.CreationCount == 0); AddStep("display values", displayNewValues); - AddWaitStep(5); - AddUntilStep(() => graph.CreationCount == 1, "wait for creation count"); + AddWaitStep("wait some", 5); + AddUntilStep("wait for creation count", () => graph.CreationCount == 1); AddStep("Toggle Bar", () => progress.AllowSeeking = !progress.AllowSeeking); - AddWaitStep(5); - AddUntilStep(() => graph.CreationCount == 1, "wait for creation count"); + AddWaitStep("wait some", 5); + AddUntilStep("wait for creation count", () => graph.CreationCount == 1); AddStep("Toggle Bar", () => progress.AllowSeeking = !progress.AllowSeeking); - AddWaitStep(5); - AddUntilStep(() => graph.CreationCount == 1, "wait for creation count"); + AddWaitStep("wait some", 5); + AddUntilStep("wait for creation count", () => graph.CreationCount == 1); AddRepeatStep("New Values", displayNewValues, 5); - AddWaitStep(5); + AddWaitStep("wait some", 5); AddAssert("ensure debounced", () => graph.CreationCount == 2); } diff --git a/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs b/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs index ac90c264c4..0981b482a1 100644 --- a/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs +++ b/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs @@ -36,18 +36,18 @@ namespace osu.Game.Tests.Visual api.Queue(req); AddStep("load null beatmap", () => beatmapBindable.Value = null); - AddUntilStep(() => backgroundSprite.ChildCount == 1, "wait for cleanup..."); + AddUntilStep("wait for cleanup...", () => backgroundSprite.ChildCount == 1); AddStep("load imported beatmap", () => beatmapBindable.Value = imported.Beatmaps.First()); - AddUntilStep(() => backgroundSprite.ChildCount == 1, "wait for cleanup..."); + AddUntilStep("wait for cleanup...", () => backgroundSprite.ChildCount == 1); if (api.IsLoggedIn) { - AddUntilStep(() => req.Result != null, "wait for api response"); + AddUntilStep("wait for api response", () => req.Result != null); AddStep("load online beatmap", () => beatmapBindable.Value = new BeatmapInfo { BeatmapSet = req.Result?.ToBeatmapSet(rulesets) }); - AddUntilStep(() => backgroundSprite.ChildCount == 1, "wait for cleanup..."); + AddUntilStep("wait for cleanup...", () => backgroundSprite.ChildCount == 1); } else { diff --git a/osu.Game.Tests/Visual/TestCaseUserProfile.cs b/osu.Game.Tests/Visual/TestCaseUserProfile.cs index 46ee74b69f..aa0bd37449 100644 --- a/osu.Game.Tests/Visual/TestCaseUserProfile.cs +++ b/osu.Game.Tests/Visual/TestCaseUserProfile.cs @@ -108,7 +108,7 @@ namespace osu.Game.Tests.Visual private void checkSupporterTag(bool isSupporter) { - AddUntilStep(() => profile.Header.User != null, "wait for load"); + AddUntilStep("wait for load", () => profile.Header.User != null); if (isSupporter) AddAssert("is supporter", () => profile.Header.SupporterTag.Alpha == 1); else diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 5ff798c40d..fed56ba4d1 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual AddStep(r.Name, () => p = loadPlayerFor(r)); AddCheckSteps(() => p); - AddUntilStep(() => + AddUntilStep("no leaked beatmaps", () => { p = null; @@ -65,9 +65,9 @@ namespace osu.Game.Tests.Visual workingWeakReferences.ForEachAlive(_ => count++); return count == 1; - }, "no leaked beatmaps"); + }); - AddUntilStep(() => + AddUntilStep("no leaked players", () => { GC.Collect(); GC.WaitForPendingFinalizers(); @@ -75,14 +75,14 @@ namespace osu.Game.Tests.Visual playerWeakReferences.ForEachAlive(_ => count++); return count == 1; - }, "no leaked players"); + }); } } } protected virtual void AddCheckSteps(Func player) { - AddUntilStep(() => player().IsLoaded, "player loaded"); + AddUntilStep("player loaded", () => player().IsLoaded); } protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c56d50ae15..c02207702c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -16,7 +16,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index fedc20397d..2633da77b3 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -105,8 +105,8 @@ - - + + From 8f5e02cbe55535d3745607af8714dcbaf28026ea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Mar 2019 17:41:22 +0900 Subject: [PATCH 64/64] Fix a couple of missed cases --- osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs index d6a3361cf2..9e70df91b6 100644 --- a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs @@ -60,7 +60,7 @@ namespace osu.Game.Tests.Visual setState(Visibility.Hidden); AddRepeatStep(@"add many simple", sendManyNotifications, 3); - AddWaitStep(5); + AddWaitStep("wait some", 5); checkProgressingCount(0); @@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual AddAssert("Displayed count is 33", () => manager.UnreadCount.Value == 33); - AddWaitStep(10); + AddWaitStep("wait some", 10); checkProgressingCount(0);