From b352c1503ff2eff470dd573d08ad8e2015c07906 Mon Sep 17 00:00:00 2001 From: Susko3 <16479013+Susko3@users.noreply.github.com> Date: Mon, 28 Dec 2020 15:13:33 +0100 Subject: [PATCH 001/107] Fix IntentFilter capturing all file types Removed string arrays and split the IntentFilter into multiple. Also added DataHost and DataMimeType --- osu.Android/OsuGameActivity.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs index 953c06f4e2..7abaff3cdb 100644 --- a/osu.Android/OsuGameActivity.cs +++ b/osu.Android/OsuGameActivity.cs @@ -16,7 +16,10 @@ using osu.Framework.Android; namespace osu.Android { [Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false, LaunchMode = LaunchMode.SingleInstance)] - [IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataPathPatterns = new[] { ".*\\.osz", ".*\\.osk" }, DataMimeType = "application/*")] + [IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")] + [IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")] + [IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "file", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")] + [IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "file", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")] [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataSchemes = new[] { "osu", "osump" })] public class OsuGameActivity : AndroidGameActivity { From d971aa5295b7d20a471d8be62fdc4c6e263dd139 Mon Sep 17 00:00:00 2001 From: Susko3 <16479013+Susko3@users.noreply.github.com> Date: Mon, 28 Dec 2020 15:54:21 +0100 Subject: [PATCH 002/107] Remove file intents and add Send intent Removed IntentFilters with DataScheme = "file" Added Intent.ActionSend with application/octet-stream and application/zip --- osu.Android/OsuGameActivity.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs index 7abaff3cdb..cdf033e685 100644 --- a/osu.Android/OsuGameActivity.cs +++ b/osu.Android/OsuGameActivity.cs @@ -16,10 +16,10 @@ using osu.Framework.Android; namespace osu.Android { [Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false, LaunchMode = LaunchMode.SingleInstance)] - [IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")] - [IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")] - [IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "file", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")] - [IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "file", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")] + [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")] + [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")] + [IntentFilter(new[] { Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = "application/octet-stream")] + [IntentFilter(new[] { Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = "application/zip")] [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataSchemes = new[] { "osu", "osump" })] public class OsuGameActivity : AndroidGameActivity { From 770a5a85dff5cff621287732639eb33534ea95ad Mon Sep 17 00:00:00 2001 From: Susko3 <16479013+Susko3@users.noreply.github.com> Date: Mon, 28 Dec 2020 20:57:08 +0100 Subject: [PATCH 003/107] Merge Intent.ActionSend into one IntentFilter Co-authored-by: Lucas A. --- osu.Android/OsuGameActivity.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs index cdf033e685..da69b516dd 100644 --- a/osu.Android/OsuGameActivity.cs +++ b/osu.Android/OsuGameActivity.cs @@ -19,7 +19,7 @@ namespace osu.Android [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")] [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")] [IntentFilter(new[] { Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = "application/octet-stream")] - [IntentFilter(new[] { Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = "application/zip")] + [IntentFilter(new[] { Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataMimeTypes = new[] { "application/zip", "application/octet-stream" })] [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataSchemes = new[] { "osu", "osump" })] public class OsuGameActivity : AndroidGameActivity { From eb64e6bf4da427df3b3b0f1bfab8dbab42f4819f Mon Sep 17 00:00:00 2001 From: Susko3 <16479013+Susko3@users.noreply.github.com> Date: Wed, 30 Dec 2020 23:35:07 +0100 Subject: [PATCH 004/107] Remove duplicate application/octet-stream --- osu.Android/OsuGameActivity.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs index da69b516dd..9d28ad7c5b 100644 --- a/osu.Android/OsuGameActivity.cs +++ b/osu.Android/OsuGameActivity.cs @@ -18,7 +18,6 @@ namespace osu.Android [Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false, LaunchMode = LaunchMode.SingleInstance)] [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")] [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")] - [IntentFilter(new[] { Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = "application/octet-stream")] [IntentFilter(new[] { Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataMimeTypes = new[] { "application/zip", "application/octet-stream" })] [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataSchemes = new[] { "osu", "osump" })] public class OsuGameActivity : AndroidGameActivity From 2d279350ad5f6a4e544601c7be7bca768bef1cbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 31 Dec 2020 11:29:02 +0100 Subject: [PATCH 005/107] Catch multiplayer client-related unobserved exceptions better Silencing an exception from a task continuation requires accessing `task.Exception` in any way, which was not done previously if `logOnError` was false. To resolve without having to worry whether the compiler will optimise away a useless access or now, just always log, but switch the logging level. The unimportant errors will be logged as debug and therefore essentially silenced on release builds (but could still be potentially useful in debugging). --- osu.Game/Extensions/TaskExtensions.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/osu.Game/Extensions/TaskExtensions.cs b/osu.Game/Extensions/TaskExtensions.cs index a1215d786b..4138c2757a 100644 --- a/osu.Game/Extensions/TaskExtensions.cs +++ b/osu.Game/Extensions/TaskExtensions.cs @@ -1,7 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +#nullable enable + +using System; using System.Threading.Tasks; +using osu.Framework.Extensions.ExceptionExtensions; using osu.Framework.Logging; namespace osu.Game.Extensions @@ -13,13 +17,19 @@ namespace osu.Game.Extensions /// Avoids unobserved exceptions from being fired. /// /// The task. - /// Whether errors should be logged as important, or silently ignored. - public static void CatchUnobservedExceptions(this Task task, bool logOnError = false) + /// + /// Whether errors should be logged as errors visible to users, or as debug messages. + /// Logging as debug will essentially silence the errors on non-release builds. + /// + public static void CatchUnobservedExceptions(this Task task, bool logAsError = false) { task.ContinueWith(t => { - if (logOnError) - Logger.Log($"Error running task: {t.Exception?.Message ?? "unknown"}", LoggingTarget.Runtime, LogLevel.Important); + Exception? exception = t.Exception?.AsSingular(); + if (logAsError) + Logger.Error(exception, $"Error running task: {exception?.Message ?? "(unknown)"}", LoggingTarget.Runtime, true); + else + Logger.Log($"Error running task: {exception}", LoggingTarget.Runtime, LogLevel.Debug); }, TaskContinuationOptions.NotOnRanToCompletion); } } From e2de5bb8f940e71fcf9cfefa8fe504966c5e00bf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 2 Jan 2021 22:05:41 +0900 Subject: [PATCH 006/107] Fix the beatmap carousel not returning to centre correctly after resizing window --- osu.Game/Screens/Select/BeatmapCarousel.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index d76f0abb9e..c83c89bb7f 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Layout; using osu.Framework.Threading; using osu.Framework.Utils; using osu.Game.Beatmaps; @@ -567,6 +568,15 @@ namespace osu.Game.Screens.Select #endregion + protected override bool OnInvalidate(Invalidation invalidation, InvalidationSource source) + { + // handles the vertical size of the carousel changing (ie. on window resize when aspect ratio has changed). + if ((invalidation & Invalidation.Layout) > 0) + itemsCache.Invalidate(); + + return base.OnInvalidate(invalidation, source); + } + protected override void Update() { base.Update(); From caa5109e3a0e1e526c789024d2ecbc9d57767e76 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 3 Jan 2021 12:18:35 +0900 Subject: [PATCH 007/107] Add precautionary null checks to update methods in SongSelect --- osu.Game/Screens/Select/SongSelect.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index a5252fdc96..8ad1ace36a 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -428,7 +428,7 @@ namespace osu.Game.Screens.Select private void updateSelectedBeatmap(BeatmapInfo beatmap) { - if (beatmap?.Equals(beatmapNoDebounce) == true) + if (beatmap == null || beatmap.Equals(beatmapNoDebounce)) return; beatmapNoDebounce = beatmap; @@ -438,7 +438,7 @@ namespace osu.Game.Screens.Select private void updateSelectedRuleset(RulesetInfo ruleset) { - if (ruleset?.Equals(rulesetNoDebounce) == true) + if (ruleset == null || ruleset.Equals(rulesetNoDebounce)) return; rulesetNoDebounce = ruleset; From 2e5c67be3f415bc0841c4ae2cd122237ff49c380 Mon Sep 17 00:00:00 2001 From: LavaDesu Date: Wed, 30 Dec 2020 12:29:51 +0700 Subject: [PATCH 008/107] Add ability to toggle discord rich presence There are 3 modes: enabled, limited, and disabled. The limited mode hides identifiable information such as username, rank, and (if participating in one) multiplayer lobby name. --- osu.Desktop/DiscordRichPresence.cs | 15 ++++++++--- .../Configuration/DiscordRichPresenceMode.cs | 17 ++++++++++++ osu.Game/Configuration/OsuConfigManager.cs | 5 +++- .../Sections/Online/IntegrationSettings.cs | 27 +++++++++++++++++++ .../Settings/Sections/OnlineSection.cs | 3 ++- 5 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Configuration/DiscordRichPresenceMode.cs create mode 100644 osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index f1878d967d..6b331d4952 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -9,6 +9,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Logging; +using osu.Game.Configuration; using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Users; @@ -30,6 +31,7 @@ namespace osu.Desktop private readonly IBindable status = new Bindable(); private readonly IBindable activity = new Bindable(); + private readonly Bindable mode = new Bindable(); private readonly RichPresence presence = new RichPresence { @@ -37,7 +39,7 @@ namespace osu.Desktop }; [BackgroundDependencyLoader] - private void load(IAPIProvider provider) + private void load(IAPIProvider provider, OsuConfigManager config) { client = new DiscordRpcClient(client_id) { @@ -51,6 +53,7 @@ namespace osu.Desktop client.OnError += (_, e) => Logger.Log($"An error occurred with Discord RPC Client: {e.Code} {e.Message}", LoggingTarget.Network); + config.BindWith(OsuSetting.DiscordRichPresence, mode); (user = provider.LocalUser.GetBoundCopy()).BindValueChanged(u => { status.UnbindBindings(); @@ -63,6 +66,7 @@ namespace osu.Desktop ruleset.BindValueChanged(_ => updateStatus()); status.BindValueChanged(_ => updateStatus()); activity.BindValueChanged(_ => updateStatus()); + mode.BindValueChanged(_ => updateStatus()); client.Initialize(); } @@ -78,7 +82,7 @@ namespace osu.Desktop if (!client.IsInitialized) return; - if (status.Value is UserStatusOffline) + if (status.Value is UserStatusOffline || mode.Value == DiscordRichPresenceMode.Disabled) { client.ClearPresence(); return; @@ -96,7 +100,10 @@ namespace osu.Desktop } // update user information - presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.Ranks.Global > 0 ? $" (rank #{user.Value.Statistics.Ranks.Global:N0})" : string.Empty); + if (mode.Value == DiscordRichPresenceMode.Limited) + presence.Assets.LargeImageText = string.Empty; + else + presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.Ranks.Global > 0 ? $" (rank #{user.Value.Statistics.Ranks.Global:N0})" : string.Empty); // update ruleset presence.Assets.SmallImageKey = ruleset.Value.ID <= 3 ? $"mode_{ruleset.Value.ID}" : "mode_custom"; @@ -137,7 +144,7 @@ namespace osu.Desktop return edit.Beatmap.ToString(); case UserActivity.InLobby lobby: - return lobby.Room.Name.Value; + return mode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value; } return string.Empty; diff --git a/osu.Game/Configuration/DiscordRichPresenceMode.cs b/osu.Game/Configuration/DiscordRichPresenceMode.cs new file mode 100644 index 0000000000..bd39faff4d --- /dev/null +++ b/osu.Game/Configuration/DiscordRichPresenceMode.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.ComponentModel; + +namespace osu.Game.Configuration +{ + public enum DiscordRichPresenceMode + { + Disabled, + + [Description("Hide identifiable information")] + Limited, + + Enabled + } +} diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index a07e446d2e..c733fe2fb4 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.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; @@ -138,6 +138,8 @@ namespace osu.Game.Configuration Set(OsuSetting.MenuBackgroundSource, BackgroundSource.Skin); Set(OsuSetting.SeasonalBackgroundMode, SeasonalBackgroundMode.Sometimes); + Set(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Enabled); + Set(OsuSetting.EditorWaveformOpacity, 1f); } @@ -266,6 +268,7 @@ namespace osu.Game.Configuration GameplayDisableWinKey, SeasonalBackgroundMode, EditorWaveformOpacity, + DiscordRichPresence, AutomaticallyDownloadWhenSpectating, } } diff --git a/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs b/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs new file mode 100644 index 0000000000..d2867962c0 --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs @@ -0,0 +1,27 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Configuration; + +namespace osu.Game.Overlays.Settings.Sections.Online +{ + public class IntegrationSettings : SettingsSubsection + { + protected override string Header => "Integrations"; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + Children = new Drawable[] + { + new SettingsEnumDropdown + { + LabelText = "Discord Rich Presence", + Current = config.GetBindable(OsuSetting.DiscordRichPresence) + } + }; + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/OnlineSection.cs b/osu.Game/Overlays/Settings/Sections/OnlineSection.cs index 150cddb388..7aa4eff29a 100644 --- a/osu.Game/Overlays/Settings/Sections/OnlineSection.cs +++ b/osu.Game/Overlays/Settings/Sections/OnlineSection.cs @@ -20,7 +20,8 @@ namespace osu.Game.Overlays.Settings.Sections { Children = new Drawable[] { - new WebSettings() + new WebSettings(), + new IntegrationSettings() }; } } From a6d49929978a2617ef2f180d3e3e868513e8737e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 3 Jan 2021 12:53:25 +0900 Subject: [PATCH 009/107] Ensure SelectionChanged events are only sent once when selection is null --- osu.Game/Screens/Select/BeatmapCarousel.cs | 31 ++++++++++++++++------ 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index c83c89bb7f..37213c6003 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -125,6 +125,8 @@ namespace osu.Game.Screens.Select { BeatmapSetsChanged?.Invoke(); BeatmapSetsLoaded = true; + + itemsCache.Invalidate(); }); } @@ -731,6 +733,12 @@ namespace osu.Game.Screens.Select private const float panel_padding = 5; + /// + /// After loading, we want to invoke a selection changed event at least once. + /// This handles the case where this event is potentially sending a null selection. + /// + private bool sentInitialSelectionEvent; + /// /// Computes the target Y positions for every item in the carousel. /// @@ -787,13 +795,21 @@ namespace osu.Game.Screens.Select Scroll.ScrollContent.Height = currentY; - if (BeatmapSetsLoaded && (selectedBeatmapSet == null || selectedBeatmap == null || selectedBeatmapSet.State.Value != CarouselItemState.Selected)) - { - selectedBeatmapSet = null; - SelectionChanged?.Invoke(null); - } - itemsCache.Validate(); + + // update and let external consumers know about selection loss. + if (BeatmapSetsLoaded) + { + bool selectionLost = selectedBeatmapSet != null && selectedBeatmapSet.State.Value != CarouselItemState.Selected; + + if (selectionLost || !sentInitialSelectionEvent) + { + selectedBeatmapSet = null; + SelectionChanged?.Invoke(null); + + sentInitialSelectionEvent = true; + } + } } private bool firstScroll = true; @@ -816,14 +832,13 @@ namespace osu.Game.Screens.Select break; case PendingScrollOperation.Immediate: + // in order to simplify animation logic, rather than using the animated version of ScrollTo, // we take the difference in scroll height and apply to all visible panels. // this avoids edge cases like when the visible panels is reduced suddenly, causing ScrollContainer // to enter clamp-special-case mode where it animates completely differently to normal. float scrollChange = scrollTarget.Value - Scroll.Current; - Scroll.ScrollTo(scrollTarget.Value, false); - foreach (var i in Scroll.Children) i.Y += scrollChange; break; From 1a443381247492b9233ae9c01ebf1a44510359ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 3 Jan 2021 15:38:28 +0900 Subject: [PATCH 010/107] Use SingleOrDefault for added safety when looking up mod acronyms --- osu.Game/Online/API/APIMod.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/APIMod.cs b/osu.Game/Online/API/APIMod.cs index 780e5daa16..6c988e2e00 100644 --- a/osu.Game/Online/API/APIMod.cs +++ b/osu.Game/Online/API/APIMod.cs @@ -36,7 +36,7 @@ namespace osu.Game.Online.API public Mod ToMod(Ruleset ruleset) { - Mod resultMod = ruleset.GetAllMods().FirstOrDefault(m => m.Acronym == Acronym); + Mod resultMod = ruleset.GetAllMods().SingleOrDefault(m => m.Acronym == Acronym); if (resultMod == null) throw new InvalidOperationException($"There is no mod in the ruleset ({ruleset.ShortName}) matching the acronym {Acronym}."); From 23e216fa0b374e23751c97124dc069877004a60d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 3 Jan 2021 15:47:15 +0900 Subject: [PATCH 011/107] Simplify some default value checks (we are sure the return is an IBindable) --- osu.Game/Online/API/APIMod.cs | 7 ++++++- osu.Game/Rulesets/Mods/Mod.cs | 8 +++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/API/APIMod.cs b/osu.Game/Online/API/APIMod.cs index 6c988e2e00..a7e5f0d6f9 100644 --- a/osu.Game/Online/API/APIMod.cs +++ b/osu.Game/Online/API/APIMod.cs @@ -31,7 +31,12 @@ namespace osu.Game.Online.API Acronym = mod.Acronym; foreach (var (_, property) in mod.GetSettingsSourceProperties()) - Settings.Add(property.Name.Underscore(), property.GetValue(mod)); + { + var bindable = (IBindable)property.GetValue(mod); + + if (!bindable.IsDefault) + Settings.Add(property.Name.Underscore(), property.GetValue(mod)); + } } public Mod ToMod(Ruleset ruleset) diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index b8dc7a2661..92b548a9cc 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -84,12 +84,10 @@ namespace osu.Game.Rulesets.Mods foreach ((SettingSourceAttribute attr, PropertyInfo property) in this.GetOrderedSettingsSourceProperties()) { - object bindableObj = property.GetValue(this); + var bindable = (IBindable)property.GetValue(this); - if ((bindableObj as IHasDefaultValue)?.IsDefault == true) - continue; - - tooltipTexts.Add($"{attr.Label} {bindableObj}"); + if (!bindable.IsDefault) + tooltipTexts.Add($"{attr.Label} {bindable}"); } return string.Join(", ", tooltipTexts.Where(s => !string.IsNullOrEmpty(s))); From 29dbb1cc0d94d26b3fb077e924bd2eb6d6b16dfd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 3 Jan 2021 15:48:28 +0900 Subject: [PATCH 012/107] Add internal pathway for ensuring correct application of bindable mods --- osu.Game/Online/API/APIMod.cs | 2 +- osu.Game/Rulesets/Mods/Mod.cs | 21 ++++++++++++------- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 6 ++++++ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/osu.Game/Online/API/APIMod.cs b/osu.Game/Online/API/APIMod.cs index a7e5f0d6f9..6e3bdac61a 100644 --- a/osu.Game/Online/API/APIMod.cs +++ b/osu.Game/Online/API/APIMod.cs @@ -51,7 +51,7 @@ namespace osu.Game.Online.API if (!Settings.TryGetValue(property.Name.Underscore(), out object settingValue)) continue; - ((IBindable)property.GetValue(resultMod)).Parse(settingValue); + resultMod.CopyAdjustedSetting((IBindable)property.GetValue(resultMod), settingValue); } return resultMod; diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index 92b548a9cc..487cdedd13 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Reflection; using Newtonsoft.Json; @@ -134,19 +133,25 @@ namespace osu.Game.Rulesets.Mods // Copy bindable values across foreach (var (_, prop) in this.GetSettingsSourceProperties()) { - var origBindable = prop.GetValue(this); - var copyBindable = prop.GetValue(copy); + var origBindable = (IBindable)prop.GetValue(this); + var copyBindable = (IBindable)prop.GetValue(copy); - // The bindables themselves are readonly, so the value must be transferred through the Bindable.Value property. - var valueProperty = origBindable.GetType().GetProperty(nameof(Bindable.Value), BindingFlags.Public | BindingFlags.Instance); - Debug.Assert(valueProperty != null); - - valueProperty.SetValue(copyBindable, valueProperty.GetValue(origBindable)); + // we only care about changes that have been made away from defaults. + if (!origBindable.IsDefault) + copy.CopyAdjustedSetting(copyBindable, origBindable); } return copy; } + /// + /// When creating copies or clones of a Mod, this method will be called to copy explicitly adjusted user settings. + /// The base implementation will transfer the value via and should be called unless replaced with custom logic. + /// + /// The target bindable to apply the adjustment. + /// The adjustment to apply. + internal virtual void CopyAdjustedSetting(IBindable bindable, object value) => bindable.Parse(value); + public bool Equals(IMod other) => GetType() == other?.GetType(); } } diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index 165644edbe..58af96a8df 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -114,6 +114,12 @@ namespace osu.Game.Rulesets.Mods bindable.ValueChanged += _ => userChangedSettings[bindable] = !bindable.IsDefault; } + internal override void CopyAdjustedSetting(IBindable bindable, object value) + { + userChangedSettings[bindable] = true; + base.CopyAdjustedSetting(bindable, value); + } + /// /// Apply all custom settings to the provided beatmap. /// From 99fa0e25dcb542e98e6bdf3c71de45a891634806 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 3 Jan 2021 16:46:24 +0900 Subject: [PATCH 013/107] Switch back to FirstOrDefault to allow for weird testing logic to pass --- osu.Game/Online/API/APIMod.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/APIMod.cs b/osu.Game/Online/API/APIMod.cs index 6e3bdac61a..3ceafc5160 100644 --- a/osu.Game/Online/API/APIMod.cs +++ b/osu.Game/Online/API/APIMod.cs @@ -41,7 +41,7 @@ namespace osu.Game.Online.API public Mod ToMod(Ruleset ruleset) { - Mod resultMod = ruleset.GetAllMods().SingleOrDefault(m => m.Acronym == Acronym); + Mod resultMod = ruleset.GetAllMods().FirstOrDefault(m => m.Acronym == Acronym); if (resultMod == null) throw new InvalidOperationException($"There is no mod in the ruleset ({ruleset.ShortName}) matching the acronym {Acronym}."); From 6ad1b7767e6ded5cd992838a7395c7205378b90c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 3 Jan 2021 17:04:16 +0900 Subject: [PATCH 014/107] Update osu.Game/Online/API/APIMod.cs Co-authored-by: Salman Ahmed --- osu.Game/Online/API/APIMod.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/APIMod.cs b/osu.Game/Online/API/APIMod.cs index 3ceafc5160..c8b76b9685 100644 --- a/osu.Game/Online/API/APIMod.cs +++ b/osu.Game/Online/API/APIMod.cs @@ -35,7 +35,7 @@ namespace osu.Game.Online.API var bindable = (IBindable)property.GetValue(mod); if (!bindable.IsDefault) - Settings.Add(property.Name.Underscore(), property.GetValue(mod)); + Settings.Add(property.Name.Underscore(), bindable); } } From 7c9f345cd27ff36ea5e638a53fb1c12f74712361 Mon Sep 17 00:00:00 2001 From: LavaDesu Date: Sun, 3 Jan 2021 16:46:25 +0700 Subject: [PATCH 015/107] Use better naming for DiscordRichPresenceMode --- osu.Desktop/DiscordRichPresence.cs | 2 +- osu.Game/Configuration/DiscordRichPresenceMode.cs | 4 ++-- osu.Game/Configuration/OsuConfigManager.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 6b331d4952..172db324cb 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -82,7 +82,7 @@ namespace osu.Desktop if (!client.IsInitialized) return; - if (status.Value is UserStatusOffline || mode.Value == DiscordRichPresenceMode.Disabled) + if (status.Value is UserStatusOffline || mode.Value == DiscordRichPresenceMode.Off) { client.ClearPresence(); return; diff --git a/osu.Game/Configuration/DiscordRichPresenceMode.cs b/osu.Game/Configuration/DiscordRichPresenceMode.cs index bd39faff4d..2e58e3554b 100644 --- a/osu.Game/Configuration/DiscordRichPresenceMode.cs +++ b/osu.Game/Configuration/DiscordRichPresenceMode.cs @@ -7,11 +7,11 @@ namespace osu.Game.Configuration { public enum DiscordRichPresenceMode { - Disabled, + Off, [Description("Hide identifiable information")] Limited, - Enabled + Full } } diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index c733fe2fb4..eb34a0885d 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -138,7 +138,7 @@ namespace osu.Game.Configuration Set(OsuSetting.MenuBackgroundSource, BackgroundSource.Skin); Set(OsuSetting.SeasonalBackgroundMode, SeasonalBackgroundMode.Sometimes); - Set(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Enabled); + Set(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full); Set(OsuSetting.EditorWaveformOpacity, 1f); } From 2501707d7d86c9927fda5f3ece0d75c14e769bb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 3 Jan 2021 20:44:57 +0900 Subject: [PATCH 016/107] Copy values using Bind to also copy defaults --- osu.Game/Rulesets/Mods/Mod.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index 487cdedd13..d2747d98c7 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -150,7 +150,17 @@ namespace osu.Game.Rulesets.Mods /// /// The target bindable to apply the adjustment. /// The adjustment to apply. - internal virtual void CopyAdjustedSetting(IBindable bindable, object value) => bindable.Parse(value); + internal virtual void CopyAdjustedSetting(IBindable bindable, object value) + { + if (value is IBindable incoming) + { + //copy including transfer of default values. + bindable.BindTo(incoming); + bindable.UnbindFrom(incoming); + } + else + bindable.Parse(value); + } public bool Equals(IMod other) => GetType() == other?.GetType(); } From a3e29b9154c996efbe051da95e9c8bbaac8c2096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 3 Jan 2021 13:25:44 +0100 Subject: [PATCH 017/107] Rename parameters for readability --- osu.Game/Rulesets/Mods/Mod.cs | 14 +++++++------- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index d2747d98c7..b7432ec966 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -148,18 +148,18 @@ namespace osu.Game.Rulesets.Mods /// When creating copies or clones of a Mod, this method will be called to copy explicitly adjusted user settings. /// The base implementation will transfer the value via and should be called unless replaced with custom logic. /// - /// The target bindable to apply the adjustment. - /// The adjustment to apply. - internal virtual void CopyAdjustedSetting(IBindable bindable, object value) + /// The target bindable to apply the adjustment. + /// The adjustment to apply. + internal virtual void CopyAdjustedSetting(IBindable target, object source) { - if (value is IBindable incoming) + if (source is IBindable sourceBindable) { //copy including transfer of default values. - bindable.BindTo(incoming); - bindable.UnbindFrom(incoming); + target.BindTo(sourceBindable); + target.UnbindFrom(sourceBindable); } else - bindable.Parse(value); + target.Parse(source); } public bool Equals(IMod other) => GetType() == other?.GetType(); diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index 58af96a8df..72a4bb297f 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -114,10 +114,10 @@ namespace osu.Game.Rulesets.Mods bindable.ValueChanged += _ => userChangedSettings[bindable] = !bindable.IsDefault; } - internal override void CopyAdjustedSetting(IBindable bindable, object value) + internal override void CopyAdjustedSetting(IBindable target, object source) { - userChangedSettings[bindable] = true; - base.CopyAdjustedSetting(bindable, value); + userChangedSettings[target] = true; + base.CopyAdjustedSetting(target, source); } /// From 9e4a925ab1f071fced203cc081f2c6f0b7c2ca96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 3 Jan 2021 13:30:21 +0100 Subject: [PATCH 018/107] Clarify & cleanup comments some --- osu.Game/Rulesets/Mods/Mod.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index b7432ec966..24d184e531 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -145,16 +145,19 @@ namespace osu.Game.Rulesets.Mods } /// - /// When creating copies or clones of a Mod, this method will be called to copy explicitly adjusted user settings. - /// The base implementation will transfer the value via and should be called unless replaced with custom logic. + /// When creating copies or clones of a Mod, this method will be called + /// to copy explicitly adjusted user settings from . + /// The base implementation will transfer the value via + /// or by binding and unbinding (if is an ) + /// and should be called unless replaced with custom logic. /// - /// The target bindable to apply the adjustment. + /// The target bindable to apply the adjustment to. /// The adjustment to apply. internal virtual void CopyAdjustedSetting(IBindable target, object source) { if (source is IBindable sourceBindable) { - //copy including transfer of default values. + // copy including transfer of default values. target.BindTo(sourceBindable); target.UnbindFrom(sourceBindable); } From efb71713efdde039ab6a3d0fce58476e6ef6d575 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 3 Jan 2021 22:43:02 +0900 Subject: [PATCH 019/107] Fix null condition inhibiting deselection events --- osu.Game/Screens/Select/SongSelect.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 8ad1ace36a..e3036c662b 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -428,7 +428,10 @@ namespace osu.Game.Screens.Select private void updateSelectedBeatmap(BeatmapInfo beatmap) { - if (beatmap == null || beatmap.Equals(beatmapNoDebounce)) + if (beatmap == null && beatmapNoDebounce == null) + return; + + if (beatmap?.Equals(beatmapNoDebounce) == true) return; beatmapNoDebounce = beatmap; From 53e6a349bbed8492c62b66ff8b47333da8101230 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 3 Jan 2021 22:44:30 +0900 Subject: [PATCH 020/107] Fix incorrect initial conditional Turns out this wasn't actually required. --- osu.Game/Screens/Select/BeatmapCarousel.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 37213c6003..36f8fbedb3 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -733,12 +733,6 @@ namespace osu.Game.Screens.Select private const float panel_padding = 5; - /// - /// After loading, we want to invoke a selection changed event at least once. - /// This handles the case where this event is potentially sending a null selection. - /// - private bool sentInitialSelectionEvent; - /// /// Computes the target Y positions for every item in the carousel. /// @@ -802,12 +796,10 @@ namespace osu.Game.Screens.Select { bool selectionLost = selectedBeatmapSet != null && selectedBeatmapSet.State.Value != CarouselItemState.Selected; - if (selectionLost || !sentInitialSelectionEvent) + if (selectionLost) { selectedBeatmapSet = null; SelectionChanged?.Invoke(null); - - sentInitialSelectionEvent = true; } } } From df04dd21de6a16da70031ee4fac020ae0f923211 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 4 Jan 2021 07:45:29 +0300 Subject: [PATCH 021/107] Add failing test case --- .../Beatmaps/IO/ImportBeatmapTest.cs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index c32e359de6..041df3e6ff 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -852,6 +852,39 @@ namespace osu.Game.Tests.Beatmaps.IO } } + [Test] + public async Task TestItemRemovedShouldPassConsumableBeatmapSet() + { + using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest))) + { + try + { + var osu = LoadOsuIntoHost(host); + var manager = osu.Dependencies.Get(); + + var removedQueue = new Queue(); + manager.ItemRemoved.BindValueChanged(evt => + { + if (evt.NewValue.TryGetTarget(out var target)) + removedQueue.Enqueue(target); + }); + + var imported = await LoadOszIntoOsu(osu); + deleteBeatmapSet(imported, osu); + + Assert.That(removedQueue.Count, Is.EqualTo(1)); + + var removedItem = removedQueue.Single(); + Assert.That(removedItem.Metadata, Is.EqualTo(imported.Metadata)); + Assert.That(removedItem.Beatmaps, Is.EquivalentTo(imported.Beatmaps)); + } + finally + { + host.Exit(); + } + } + } + public static async Task LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false) { var temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack); From 738c94d1938f99ff5fb638528cff02bf80f297df Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 4 Jan 2021 07:46:51 +0300 Subject: [PATCH 022/107] Update soft-deletion logic to use model store's consumable items instead --- osu.Game/Database/ArchiveModelManager.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 36cc4cce39..61b2f7668e 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -76,7 +76,7 @@ namespace osu.Game.Database protected readonly IDatabaseContextFactory ContextFactory; - protected readonly MutableDatabaseBackedStore ModelStore; + protected readonly MutableDatabaseBackedStoreWithFileIncludes ModelStore; // ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised) private ArchiveImportIPCChannel ipc; @@ -492,7 +492,7 @@ namespace osu.Game.Database using (ContextFactory.GetForWrite()) { // re-fetch the model on the import context. - var foundModel = queryModel().Include(s => s.Files).ThenInclude(f => f.FileInfo).FirstOrDefault(s => s.ID == item.ID); + var foundModel = ModelStore.ConsumableItems.SingleOrDefault(i => i.ID == item.ID); if (foundModel == null || foundModel.DeletePending) return false; @@ -731,8 +731,6 @@ namespace osu.Game.Database yield return f.Filename; } - private DbSet queryModel() => ContextFactory.Get().Set(); - protected virtual string HumanisedModelName => $"{typeof(TModel).Name.Replace("Info", "").ToLower()}"; #region Event handling / delaying From 1463ff288629232333880a0f18888c4f1a65e5d6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 4 Jan 2021 08:12:31 +0300 Subject: [PATCH 023/107] Remove unnecessary using directive --- osu.Game/Database/ArchiveModelManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 61b2f7668e..b9f805ae31 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -9,7 +9,6 @@ using System.Threading; using System.Threading.Tasks; using Humanizer; using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore; using osu.Framework; using osu.Framework.Bindables; using osu.Framework.Extensions; From ca5f2bcd4ca8395698a5267d6a8fb2a6cb214e45 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 4 Jan 2021 08:49:03 +0300 Subject: [PATCH 024/107] Revert database-side changes --- .../Beatmaps/IO/ImportBeatmapTest.cs | 33 ------------------- osu.Game/Database/ArchiveModelManager.cs | 6 ++-- 2 files changed, 4 insertions(+), 35 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 041df3e6ff..c32e359de6 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -852,39 +852,6 @@ namespace osu.Game.Tests.Beatmaps.IO } } - [Test] - public async Task TestItemRemovedShouldPassConsumableBeatmapSet() - { - using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest))) - { - try - { - var osu = LoadOsuIntoHost(host); - var manager = osu.Dependencies.Get(); - - var removedQueue = new Queue(); - manager.ItemRemoved.BindValueChanged(evt => - { - if (evt.NewValue.TryGetTarget(out var target)) - removedQueue.Enqueue(target); - }); - - var imported = await LoadOszIntoOsu(osu); - deleteBeatmapSet(imported, osu); - - Assert.That(removedQueue.Count, Is.EqualTo(1)); - - var removedItem = removedQueue.Single(); - Assert.That(removedItem.Metadata, Is.EqualTo(imported.Metadata)); - Assert.That(removedItem.Beatmaps, Is.EquivalentTo(imported.Beatmaps)); - } - finally - { - host.Exit(); - } - } - } - public static async Task LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false) { var temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack); diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index b9f805ae31..81d8668196 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -75,7 +75,7 @@ namespace osu.Game.Database protected readonly IDatabaseContextFactory ContextFactory; - protected readonly MutableDatabaseBackedStoreWithFileIncludes ModelStore; + protected readonly MutableDatabaseBackedStore ModelStore; // ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised) private ArchiveImportIPCChannel ipc; @@ -491,7 +491,7 @@ namespace osu.Game.Database using (ContextFactory.GetForWrite()) { // re-fetch the model on the import context. - var foundModel = ModelStore.ConsumableItems.SingleOrDefault(i => i.ID == item.ID); + var foundModel = queryModel().Include(s => s.Files).ThenInclude(f => f.FileInfo).FirstOrDefault(s => s.ID == item.ID); if (foundModel == null || foundModel.DeletePending) return false; @@ -730,6 +730,8 @@ namespace osu.Game.Database yield return f.Filename; } + private DbSet queryModel() => ContextFactory.Get().Set(); + protected virtual string HumanisedModelName => $"{typeof(TModel).Name.Replace("Info", "").ToLower()}"; #region Event handling / delaying From 445a4bd01c70428f33bc36b603a52e80e92d0aeb Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 4 Jan 2021 08:51:37 +0300 Subject: [PATCH 025/107] Re-query beatmap info on database changes --- osu.Game/Database/ArchiveModelManager.cs | 1 + .../OnlinePlay/Components/ReadyButton.cs | 34 ++++--------------- 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 81d8668196..36cc4cce39 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Humanizer; using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; using osu.Framework; using osu.Framework.Bindables; using osu.Framework.Extensions; diff --git a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs index 08f89d8ed8..144535ed4c 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs @@ -2,8 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Linq; -using System.Linq.Expressions; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Beatmaps; @@ -41,38 +39,20 @@ namespace osu.Game.Screens.OnlinePlay.Components SelectedItem.BindValueChanged(item => updateSelectedItem(item.NewValue), true); } - private void updateSelectedItem(PlaylistItem item) - { - hasBeatmap = findBeatmap(expr => beatmaps.QueryBeatmap(expr)); - } + private void updateSelectedItem(PlaylistItem _) => updateBeatmapState(); + private void beatmapUpdated(ValueChangedEvent> _) => updateBeatmapState(); + private void beatmapRemoved(ValueChangedEvent> _) => updateBeatmapState(); - private void beatmapUpdated(ValueChangedEvent> weakSet) - { - if (weakSet.NewValue.TryGetTarget(out var set)) - { - if (findBeatmap(expr => set.Beatmaps.AsQueryable().FirstOrDefault(expr))) - Schedule(() => hasBeatmap = true); - } - } - - private void beatmapRemoved(ValueChangedEvent> weakSet) - { - if (weakSet.NewValue.TryGetTarget(out var set)) - { - if (findBeatmap(expr => set.Beatmaps.AsQueryable().FirstOrDefault(expr))) - Schedule(() => hasBeatmap = false); - } - } - - private bool findBeatmap(Func>, BeatmapInfo> expression) + private void updateBeatmapState() { int? beatmapId = SelectedItem.Value?.Beatmap.Value?.OnlineBeatmapID; string checksum = SelectedItem.Value?.Beatmap.Value?.MD5Hash; if (beatmapId == null || checksum == null) - return false; + return; - return expression(b => b.OnlineBeatmapID == beatmapId && b.MD5Hash == checksum) != null; + var databasedBeatmap = beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmapId && b.MD5Hash == checksum); + hasBeatmap = databasedBeatmap != null && !databasedBeatmap.BeatmapSet.DeletePending; } protected override void Update() From cb7df0fe1172935581909b938cab6fe987fcc5ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Jan 2021 15:14:39 +0900 Subject: [PATCH 026/107] Add failing test for storyboard start time ordering --- .../Formats/LegacyStoryboardDecoderTest.cs | 20 +++++++++++++++++++ .../Resources/out-of-order-starttimes.osb | 6 ++++++ 2 files changed, 26 insertions(+) create mode 100644 osu.Game.Tests/Resources/out-of-order-starttimes.osb diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs index 9ebedb3c80..b36597a949 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs @@ -95,6 +95,26 @@ namespace osu.Game.Tests.Beatmaps.Formats } } + [Test] + public void TestOutOfOrderStartTimes() + { + var decoder = new LegacyStoryboardDecoder(); + + using (var resStream = TestResources.OpenResource("out-of-order-starttimes.osb")) + using (var stream = new LineBufferedReader(resStream)) + { + var storyboard = decoder.Decode(stream); + + StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3); + Assert.AreEqual(2, background.Elements.Count); + + Assert.AreEqual(1500, background.Elements[0].StartTime); + Assert.AreEqual(1000, background.Elements[1].StartTime); + + Assert.AreEqual(1000, storyboard.FirstEventTime); + } + } + [Test] public void TestDecodeVariableWithSuffix() { diff --git a/osu.Game.Tests/Resources/out-of-order-starttimes.osb b/osu.Game.Tests/Resources/out-of-order-starttimes.osb new file mode 100644 index 0000000000..09988ff64e --- /dev/null +++ b/osu.Game.Tests/Resources/out-of-order-starttimes.osb @@ -0,0 +1,6 @@ +[Events] +//Storyboard Layer 0 (Background) +Sprite,Background,TopCentre,"img.jpg",320,240 + F,0,1500,1600,0,1 +Sprite,Background,TopCentre,"img.jpg",320,240 + F,0,1000,1100,0,1 From 20d04d69332f18b7f14eedc44fed5bdf0ae9e9a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Jan 2021 15:16:01 +0900 Subject: [PATCH 027/107] Fix Storyboard's FirstEventTime not finding the true earliest event --- .../Beatmaps/Formats/LegacyStoryboardDecoderTest.cs | 2 +- osu.Game/Screens/Play/GameplayClockContainer.cs | 4 +++- osu.Game/Storyboards/Storyboard.cs | 10 +++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs index b36597a949..7bee580863 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs @@ -111,7 +111,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual(1500, background.Elements[0].StartTime); Assert.AreEqual(1000, background.Elements[1].StartTime); - Assert.AreEqual(1000, storyboard.FirstEventTime); + Assert.AreEqual(1000, storyboard.EarliestEventTime); } } diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 0248432917..ddbb087962 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -131,7 +131,9 @@ namespace osu.Game.Screens.Play // if a storyboard is present, it may dictate the appropriate start time by having events in negative time space. // this is commonly used to display an intro before the audio track start. - startTime = Math.Min(startTime, beatmap.Storyboard.FirstEventTime); + double? firstStoryboardEvent = beatmap.Storyboard.EarliestEventTime; + if (firstStoryboardEvent != null) + startTime = Math.Min(startTime, firstStoryboardEvent.Value); // some beatmaps specify a current lead-in time which should be used instead of the ruleset-provided value when available. // this is not available as an option in the live editor but can still be applied via .osu editing. diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index e0d18eab00..d4ba18d394 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.EntityFrameworkCore.Internal; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; @@ -27,7 +28,14 @@ namespace osu.Game.Storyboards public bool HasDrawable => Layers.Any(l => l.Elements.Any(e => e.IsDrawable)); - public double FirstEventTime => Layers.Min(l => l.Elements.FirstOrDefault()?.StartTime ?? 0); + /// + /// Across all layers, find the earliest point in time that a storyboard element exists at. + /// Will return null if there are no elements. + /// + /// + /// This iterates all elements and as such should be used sparingly or stored locally. + /// + public double? EarliestEventTime => Layers.SelectMany(l => l.Elements).OrderBy(e => e.StartTime).FirstOrDefault()?.StartTime; /// /// Depth of the currently front-most storyboard layer, excluding the overlay layer. From 9e0c490141e4e85ecde7c96d7a6b3f37f0b3b4fa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Jan 2021 15:40:22 +0900 Subject: [PATCH 028/107] Remove unused using --- osu.Game/Storyboards/Storyboard.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index d4ba18d394..1ba25cc11e 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.EntityFrameworkCore.Internal; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; From ea38b00b29adabf0ec91b0b085f2af0b11829b23 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 4 Jan 2021 10:27:08 +0300 Subject: [PATCH 029/107] Schedule all calls to `updateBeatmapState()` --- osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs index 144535ed4c..6f86f2b879 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs @@ -39,9 +39,9 @@ namespace osu.Game.Screens.OnlinePlay.Components SelectedItem.BindValueChanged(item => updateSelectedItem(item.NewValue), true); } - private void updateSelectedItem(PlaylistItem _) => updateBeatmapState(); - private void beatmapUpdated(ValueChangedEvent> _) => updateBeatmapState(); - private void beatmapRemoved(ValueChangedEvent> _) => updateBeatmapState(); + private void updateSelectedItem(PlaylistItem _) => Scheduler.AddOnce(updateBeatmapState); + private void beatmapUpdated(ValueChangedEvent> _) => Scheduler.AddOnce(updateBeatmapState); + private void beatmapRemoved(ValueChangedEvent> _) => Scheduler.AddOnce(updateBeatmapState); private void updateBeatmapState() { From 485a57776b205581528925011a1d2ec77d8fc26d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 4 Jan 2021 10:28:41 +0300 Subject: [PATCH 030/107] Fix `hasBeatmap` potentially checking on outdated `DeletePending` value --- osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs index 6f86f2b879..b782df75df 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs @@ -52,7 +52,15 @@ namespace osu.Game.Screens.OnlinePlay.Components return; var databasedBeatmap = beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmapId && b.MD5Hash == checksum); - hasBeatmap = databasedBeatmap != null && !databasedBeatmap.BeatmapSet.DeletePending; + + if (databasedBeatmap == null) + hasBeatmap = false; + else + { + // DeletePending isn't updated in the beatmap info query above, need to directly query the beatmap set from database as well. + var databasedSet = beatmaps.QueryBeatmapSet(s => s.Equals(databasedBeatmap.BeatmapSet)); + hasBeatmap = databasedSet?.DeletePending == false; + } } protected override void Update() From ba4e41142262d683e25185af98e13a07157214ce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Jan 2021 16:37:07 +0900 Subject: [PATCH 031/107] Clone and copy ControlPointInfo when retrieving a playable beatmap --- osu.Game/Beatmaps/ControlPoints/ControlPoint.cs | 17 +++++++++++++++++ .../Beatmaps/ControlPoints/ControlPointInfo.cs | 12 +++++++++++- .../ControlPoints/DifficultyControlPoint.cs | 7 +++++++ .../ControlPoints/EffectControlPoint.cs | 8 ++++++++ .../ControlPoints/SampleControlPoint.cs | 8 ++++++++ .../ControlPoints/TimingControlPoint.cs | 8 ++++++++ osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 15 +++++++++++++-- osu.Game/Beatmaps/IBeatmap.cs | 2 +- osu.Game/Beatmaps/WorkingBeatmap.cs | 3 +++ osu.Game/Screens/Edit/EditorBeatmap.cs | 6 +++++- osu.Game/Screens/Play/GameplayBeatmap.cs | 6 +++++- 11 files changed, 86 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs index c6649f6af1..090675473d 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs @@ -28,5 +28,22 @@ namespace osu.Game.Beatmaps.ControlPoints /// An existing control point to compare with. /// Whether this is redundant when placed alongside . public abstract bool IsRedundant(ControlPoint existing); + + /// + /// Create a copy of this room without online information. + /// Should be used to create a local copy of a room for submitting in the future. + /// + public ControlPoint CreateCopy() + { + var copy = (ControlPoint)Activator.CreateInstance(GetType()); + + copy.CopyFrom(this); + + return copy; + } + + public virtual void CopyFrom(ControlPoint other) + { + } } } diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index b843aad950..b56f9a106b 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -11,7 +11,7 @@ using osu.Framework.Lists; namespace osu.Game.Beatmaps.ControlPoints { [Serializable] - public class ControlPointInfo + public class ControlPointInfo : ICloneable { /// /// All control points grouped by time. @@ -297,5 +297,15 @@ namespace osu.Game.Beatmaps.ControlPoints break; } } + + public object Clone() + { + var controlPointInfo = new ControlPointInfo(); + + foreach (var point in AllControlPoints) + controlPointInfo.Add(point.Time, point.CreateCopy()); + + return controlPointInfo; + } } } diff --git a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs index 283bf76572..0bc5605051 100644 --- a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs @@ -39,5 +39,12 @@ namespace osu.Game.Beatmaps.ControlPoints public override bool IsRedundant(ControlPoint existing) => existing is DifficultyControlPoint existingDifficulty && SpeedMultiplier == existingDifficulty.SpeedMultiplier; + + public override void CopyFrom(ControlPoint other) + { + SpeedMultiplier = ((DifficultyControlPoint)other).SpeedMultiplier; + + base.CopyFrom(other); + } } } diff --git a/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs index ea28fca170..79bc88e773 100644 --- a/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs @@ -50,5 +50,13 @@ namespace osu.Game.Beatmaps.ControlPoints && existing is EffectControlPoint existingEffect && KiaiMode == existingEffect.KiaiMode && OmitFirstBarLine == existingEffect.OmitFirstBarLine; + + public override void CopyFrom(ControlPoint other) + { + KiaiMode = ((EffectControlPoint)other).KiaiMode; + OmitFirstBarLine = ((EffectControlPoint)other).OmitFirstBarLine; + + base.CopyFrom(other); + } } } diff --git a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs index fd0b496335..4aa6a3d6e9 100644 --- a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs @@ -72,5 +72,13 @@ namespace osu.Game.Beatmaps.ControlPoints => existing is SampleControlPoint existingSample && SampleBank == existingSample.SampleBank && SampleVolume == existingSample.SampleVolume; + + public override void CopyFrom(ControlPoint other) + { + SampleVolume = ((SampleControlPoint)other).SampleVolume; + SampleBank = ((SampleControlPoint)other).SampleBank; + + base.CopyFrom(other); + } } } diff --git a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs index d9378bca4a..580642f593 100644 --- a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs @@ -69,5 +69,13 @@ namespace osu.Game.Beatmaps.ControlPoints // Timing points are never redundant as they can change the time signature. public override bool IsRedundant(ControlPoint existing) => false; + + public override void CopyFrom(ControlPoint other) + { + TimeSignature = ((TimingControlPoint)other).TimeSignature; + BeatLength = ((TimingControlPoint)other).BeatLength; + + base.CopyFrom(other); + } } } diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index c9d139bdd0..06ff677aed 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -164,13 +164,24 @@ namespace osu.Game.Beatmaps.Formats /// Legacy BPM multiplier that introduces floating-point errors for rulesets that depend on it. /// DO NOT USE THIS UNLESS 100% SURE. /// - public readonly float BpmMultiplier; + public float BpmMultiplier { get; set; } public LegacyDifficultyControlPoint(double beatLength) + : this() + { + BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100f : 1; + } + + public LegacyDifficultyControlPoint() { SpeedMultiplierBindable.Precision = double.Epsilon; + } - BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100f : 1; + public override void CopyFrom(ControlPoint other) + { + base.CopyFrom(other); + + BpmMultiplier = ((LegacyDifficultyControlPoint)other).BpmMultiplier; } } diff --git a/osu.Game/Beatmaps/IBeatmap.cs b/osu.Game/Beatmaps/IBeatmap.cs index 8f27e0b0e9..7dd85e1232 100644 --- a/osu.Game/Beatmaps/IBeatmap.cs +++ b/osu.Game/Beatmaps/IBeatmap.cs @@ -24,7 +24,7 @@ namespace osu.Game.Beatmaps /// /// The control points in this beatmap. /// - ControlPointInfo ControlPointInfo { get; } + ControlPointInfo ControlPointInfo { get; set; } /// /// The breaks in this beatmap. diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 30382c444f..06b5913b18 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -14,6 +14,7 @@ using osu.Framework.Graphics.Textures; using osu.Framework.Logging; using osu.Framework.Statistics; using osu.Framework.Testing; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Types; @@ -111,6 +112,8 @@ namespace osu.Game.Beatmaps // Convert IBeatmap converted = converter.Convert(cancellationSource.Token); + converted.ControlPointInfo = (ControlPointInfo)converted.ControlPointInfo.Clone(); + // Apply conversion mods to the result foreach (var mod in mods.OfType()) { diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 165d2ba278..a54a95f59d 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -74,7 +74,11 @@ namespace osu.Game.Screens.Edit public BeatmapMetadata Metadata => PlayableBeatmap.Metadata; - public ControlPointInfo ControlPointInfo => PlayableBeatmap.ControlPointInfo; + public ControlPointInfo ControlPointInfo + { + get => PlayableBeatmap.ControlPointInfo; + set => PlayableBeatmap.ControlPointInfo = value; + } public List Breaks => PlayableBeatmap.Breaks; diff --git a/osu.Game/Screens/Play/GameplayBeatmap.cs b/osu.Game/Screens/Play/GameplayBeatmap.cs index 64894544f4..565595656f 100644 --- a/osu.Game/Screens/Play/GameplayBeatmap.cs +++ b/osu.Game/Screens/Play/GameplayBeatmap.cs @@ -29,7 +29,11 @@ namespace osu.Game.Screens.Play public BeatmapMetadata Metadata => PlayableBeatmap.Metadata; - public ControlPointInfo ControlPointInfo => PlayableBeatmap.ControlPointInfo; + public ControlPointInfo ControlPointInfo + { + get => PlayableBeatmap.ControlPointInfo; + set => PlayableBeatmap.ControlPointInfo = value; + } public List Breaks => PlayableBeatmap.Breaks; From b4a779108e7c87994198690cba57ca05e1a0e503 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Jan 2021 16:37:49 +0900 Subject: [PATCH 032/107] Ensure working beatmap is reloaded on exiting the editor --- osu.Game/Screens/Edit/Editor.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 223c678fba..a9fe7ba38d 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -483,6 +483,8 @@ namespace osu.Game.Screens.Edit Background.FadeColour(Color4.White, 500); resetTrack(); + Beatmap.Value = beatmapManager.GetWorkingBeatmap(Beatmap.Value.BeatmapInfo); + return base.OnExiting(next); } From 7fdf876b4c8fb19020033d080fca3ee08dd44adc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Jan 2021 16:38:15 +0900 Subject: [PATCH 033/107] Fix editor timing screen mutating the WorkingBeatmap instead of EditorBeatmap --- osu.Game/Screens/Edit/Timing/DifficultySection.cs | 2 +- osu.Game/Screens/Edit/Timing/EffectSection.cs | 2 +- osu.Game/Screens/Edit/Timing/GroupSection.cs | 9 ++++----- osu.Game/Screens/Edit/Timing/SampleSection.cs | 2 +- osu.Game/Screens/Edit/Timing/Section.cs | 3 +-- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 11 +++++------ osu.Game/Screens/Edit/Timing/TimingSection.cs | 2 +- 7 files changed, 14 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/DifficultySection.cs b/osu.Game/Screens/Edit/Timing/DifficultySection.cs index b55d74e3b4..b87b8961f8 100644 --- a/osu.Game/Screens/Edit/Timing/DifficultySection.cs +++ b/osu.Game/Screens/Edit/Timing/DifficultySection.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Edit.Timing protected override DifficultyControlPoint CreatePoint() { - var reference = Beatmap.Value.Beatmap.ControlPointInfo.DifficultyPointAt(SelectedGroup.Value.Time); + var reference = Beatmap.ControlPointInfo.DifficultyPointAt(SelectedGroup.Value.Time); return new DifficultyControlPoint { diff --git a/osu.Game/Screens/Edit/Timing/EffectSection.cs b/osu.Game/Screens/Edit/Timing/EffectSection.cs index 2f143108a9..6d23b52c05 100644 --- a/osu.Game/Screens/Edit/Timing/EffectSection.cs +++ b/osu.Game/Screens/Edit/Timing/EffectSection.cs @@ -37,7 +37,7 @@ namespace osu.Game.Screens.Edit.Timing protected override EffectControlPoint CreatePoint() { - var reference = Beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(SelectedGroup.Value.Time); + var reference = Beatmap.ControlPointInfo.EffectPointAt(SelectedGroup.Value.Time); return new EffectControlPoint { diff --git a/osu.Game/Screens/Edit/Timing/GroupSection.cs b/osu.Game/Screens/Edit/Timing/GroupSection.cs index 2605ea8b75..2e2c380d4a 100644 --- a/osu.Game/Screens/Edit/Timing/GroupSection.cs +++ b/osu.Game/Screens/Edit/Timing/GroupSection.cs @@ -6,7 +6,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; @@ -24,7 +23,7 @@ namespace osu.Game.Screens.Edit.Timing protected Bindable SelectedGroup { get; private set; } [Resolved] - protected IBindable Beatmap { get; private set; } + protected EditorBeatmap Beatmap { get; private set; } [Resolved] private EditorClock clock { get; set; } @@ -107,13 +106,13 @@ namespace osu.Game.Screens.Edit.Timing var currentGroupItems = SelectedGroup.Value.ControlPoints.ToArray(); - Beatmap.Value.Beatmap.ControlPointInfo.RemoveGroup(SelectedGroup.Value); + Beatmap.ControlPointInfo.RemoveGroup(SelectedGroup.Value); foreach (var cp in currentGroupItems) - Beatmap.Value.Beatmap.ControlPointInfo.Add(time, cp); + Beatmap.ControlPointInfo.Add(time, cp); // the control point might not necessarily exist yet, if currentGroupItems was empty. - SelectedGroup.Value = Beatmap.Value.Beatmap.ControlPointInfo.GroupAt(time, true); + SelectedGroup.Value = Beatmap.ControlPointInfo.GroupAt(time, true); changeHandler?.EndChange(); } diff --git a/osu.Game/Screens/Edit/Timing/SampleSection.cs b/osu.Game/Screens/Edit/Timing/SampleSection.cs index 280e19c99a..cc73af6349 100644 --- a/osu.Game/Screens/Edit/Timing/SampleSection.cs +++ b/osu.Game/Screens/Edit/Timing/SampleSection.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.Edit.Timing protected override SampleControlPoint CreatePoint() { - var reference = Beatmap.Value.Beatmap.ControlPointInfo.SamplePointAt(SelectedGroup.Value.Time); + var reference = Beatmap.ControlPointInfo.SamplePointAt(SelectedGroup.Value.Time); return new SampleControlPoint { diff --git a/osu.Game/Screens/Edit/Timing/Section.cs b/osu.Game/Screens/Edit/Timing/Section.cs index 7a81eeb1a4..5269fa9774 100644 --- a/osu.Game/Screens/Edit/Timing/Section.cs +++ b/osu.Game/Screens/Edit/Timing/Section.cs @@ -7,7 +7,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; @@ -27,7 +26,7 @@ namespace osu.Game.Screens.Edit.Timing private const float header_height = 20; [Resolved] - protected IBindable Beatmap { get; private set; } + protected EditorBeatmap Beatmap { get; private set; } [Resolved] protected Bindable SelectedGroup { get; private set; } diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index eab909b798..c5d2dd756a 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -7,7 +7,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -62,7 +61,7 @@ namespace osu.Game.Screens.Edit.Timing private EditorClock clock { get; set; } [Resolved] - protected IBindable Beatmap { get; private set; } + protected EditorBeatmap Beatmap { get; private set; } [Resolved] private Bindable selectedGroup { get; set; } @@ -124,7 +123,7 @@ namespace osu.Game.Screens.Edit.Timing selectedGroup.BindValueChanged(selected => { deleteButton.Enabled.Value = selected.NewValue != null; }, true); - controlPointGroups.BindTo(Beatmap.Value.Beatmap.ControlPointInfo.Groups); + controlPointGroups.BindTo(Beatmap.ControlPointInfo.Groups); controlPointGroups.BindCollectionChanged((sender, args) => { table.ControlGroups = controlPointGroups; @@ -137,14 +136,14 @@ namespace osu.Game.Screens.Edit.Timing if (selectedGroup.Value == null) return; - Beatmap.Value.Beatmap.ControlPointInfo.RemoveGroup(selectedGroup.Value); + Beatmap.ControlPointInfo.RemoveGroup(selectedGroup.Value); - selectedGroup.Value = Beatmap.Value.Beatmap.ControlPointInfo.Groups.FirstOrDefault(g => g.Time >= clock.CurrentTime); + selectedGroup.Value = Beatmap.ControlPointInfo.Groups.FirstOrDefault(g => g.Time >= clock.CurrentTime); } private void addNew() { - selectedGroup.Value = Beatmap.Value.Beatmap.ControlPointInfo.GroupAt(clock.CurrentTime, true); + selectedGroup.Value = Beatmap.ControlPointInfo.GroupAt(clock.CurrentTime, true); } } } diff --git a/osu.Game/Screens/Edit/Timing/TimingSection.cs b/osu.Game/Screens/Edit/Timing/TimingSection.cs index 1ae2a86885..a0bb9ac506 100644 --- a/osu.Game/Screens/Edit/Timing/TimingSection.cs +++ b/osu.Game/Screens/Edit/Timing/TimingSection.cs @@ -49,7 +49,7 @@ namespace osu.Game.Screens.Edit.Timing protected override TimingControlPoint CreatePoint() { - var reference = Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(SelectedGroup.Value.Time); + var reference = Beatmap.ControlPointInfo.TimingPointAt(SelectedGroup.Value.Time); return new TimingControlPoint { From b7dd54847fc97e98ac5d0eef7d06b5b4d12b509b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Jan 2021 16:47:08 +0900 Subject: [PATCH 034/107] Move resolved usage of WorkingBeatmap in editor components as local as possible to avoid misuse --- .../Screens/Edit/Compose/ComposeScreen.cs | 5 ++++- osu.Game/Screens/Edit/EditorScreen.cs | 5 ----- .../Screens/Edit/Setup/DifficultySection.cs | 16 ++++++++-------- .../Screens/Edit/Setup/MetadataSection.cs | 16 ++++++++-------- .../Screens/Edit/Setup/ResourcesSection.cs | 19 +++++++++++-------- osu.Game/Screens/Edit/Setup/SetupSection.cs | 4 +--- 6 files changed, 32 insertions(+), 33 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index c297a03dbf..81b1195a40 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -16,6 +16,9 @@ namespace osu.Game.Screens.Edit.Compose { public class ComposeScreen : EditorScreenWithTimeline { + [Resolved] + private IBindable beatmap { get; set; } + private HitObjectComposer composer; public ComposeScreen() @@ -59,7 +62,7 @@ namespace osu.Game.Screens.Edit.Compose { Debug.Assert(ruleset != null); - var beatmapSkinProvider = new BeatmapSkinProvidingContainer(Beatmap.Value.Skin); + var beatmapSkinProvider = new BeatmapSkinProvidingContainer(beatmap.Value.Skin); // the beatmapSkinProvider is used as the fallback source here to allow the ruleset-specific skin implementation // full access to all skin sources. diff --git a/osu.Game/Screens/Edit/EditorScreen.cs b/osu.Game/Screens/Edit/EditorScreen.cs index 4d62a7d3cd..7fbb6a8ca0 100644 --- a/osu.Game/Screens/Edit/EditorScreen.cs +++ b/osu.Game/Screens/Edit/EditorScreen.cs @@ -2,10 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; namespace osu.Game.Screens.Edit { @@ -14,9 +12,6 @@ namespace osu.Game.Screens.Edit /// public abstract class EditorScreen : Container { - [Resolved] - protected IBindable Beatmap { get; private set; } - [Resolved] protected EditorBeatmap EditorBeatmap { get; private set; } diff --git a/osu.Game/Screens/Edit/Setup/DifficultySection.cs b/osu.Game/Screens/Edit/Setup/DifficultySection.cs index 897ddc6955..f180d7e63e 100644 --- a/osu.Game/Screens/Edit/Setup/DifficultySection.cs +++ b/osu.Game/Screens/Edit/Setup/DifficultySection.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Edit.Setup { Label = "Object Size", Description = "The size of all hit objects", - Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize) + Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.CircleSize) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, MinValue = 0, @@ -46,7 +46,7 @@ namespace osu.Game.Screens.Edit.Setup { Label = "Health Drain", Description = "The rate of passive health drain throughout playable time", - Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.DrainRate) + Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.DrainRate) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, MinValue = 0, @@ -58,7 +58,7 @@ namespace osu.Game.Screens.Edit.Setup { Label = "Approach Rate", Description = "The speed at which objects are presented to the player", - Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.ApproachRate) + Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, MinValue = 0, @@ -70,7 +70,7 @@ namespace osu.Game.Screens.Edit.Setup { Label = "Overall Difficulty", Description = "The harshness of hit windows and difficulty of special objects (ie. spinners)", - Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty) + Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, MinValue = 0, @@ -88,10 +88,10 @@ namespace osu.Game.Screens.Edit.Setup { // for now, update these on commit rather than making BeatmapMetadata bindables. // after switching database engines we can reconsider if switching to bindables is a good direction. - Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize = circleSizeSlider.Current.Value; - Beatmap.Value.BeatmapInfo.BaseDifficulty.DrainRate = healthDrainSlider.Current.Value; - Beatmap.Value.BeatmapInfo.BaseDifficulty.ApproachRate = approachRateSlider.Current.Value; - Beatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty = overallDifficultySlider.Current.Value; + Beatmap.BeatmapInfo.BaseDifficulty.CircleSize = circleSizeSlider.Current.Value; + Beatmap.BeatmapInfo.BaseDifficulty.DrainRate = healthDrainSlider.Current.Value; + Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate = approachRateSlider.Current.Value; + Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty = overallDifficultySlider.Current.Value; editorBeatmap.UpdateAllHitObjects(); } diff --git a/osu.Game/Screens/Edit/Setup/MetadataSection.cs b/osu.Game/Screens/Edit/Setup/MetadataSection.cs index 4ddee2acc6..e812c042fb 100644 --- a/osu.Game/Screens/Edit/Setup/MetadataSection.cs +++ b/osu.Game/Screens/Edit/Setup/MetadataSection.cs @@ -29,25 +29,25 @@ namespace osu.Game.Screens.Edit.Setup artistTextBox = new LabelledTextBox { Label = "Artist", - Current = { Value = Beatmap.Value.Metadata.Artist }, + Current = { Value = Beatmap.Metadata.Artist }, TabbableContentContainer = this }, titleTextBox = new LabelledTextBox { Label = "Title", - Current = { Value = Beatmap.Value.Metadata.Title }, + Current = { Value = Beatmap.Metadata.Title }, TabbableContentContainer = this }, creatorTextBox = new LabelledTextBox { Label = "Creator", - Current = { Value = Beatmap.Value.Metadata.AuthorString }, + Current = { Value = Beatmap.Metadata.AuthorString }, TabbableContentContainer = this }, difficultyTextBox = new LabelledTextBox { Label = "Difficulty Name", - Current = { Value = Beatmap.Value.BeatmapInfo.Version }, + Current = { Value = Beatmap.BeatmapInfo.Version }, TabbableContentContainer = this }, }; @@ -62,10 +62,10 @@ namespace osu.Game.Screens.Edit.Setup // for now, update these on commit rather than making BeatmapMetadata bindables. // after switching database engines we can reconsider if switching to bindables is a good direction. - Beatmap.Value.Metadata.Artist = artistTextBox.Current.Value; - Beatmap.Value.Metadata.Title = titleTextBox.Current.Value; - Beatmap.Value.Metadata.AuthorString = creatorTextBox.Current.Value; - Beatmap.Value.BeatmapInfo.Version = difficultyTextBox.Current.Value; + Beatmap.Metadata.Artist = artistTextBox.Current.Value; + Beatmap.Metadata.Title = titleTextBox.Current.Value; + Beatmap.Metadata.AuthorString = creatorTextBox.Current.Value; + Beatmap.BeatmapInfo.Version = difficultyTextBox.Current.Value; } } } diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 0c957b80af..b3bceceea3 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -42,6 +42,9 @@ namespace osu.Game.Screens.Edit.Setup [Resolved] private BeatmapManager beatmaps { get; set; } + [Resolved] + private IBindable working { get; set; } + [Resolved(canBeNull: true)] private Editor editor { get; set; } @@ -70,7 +73,7 @@ namespace osu.Game.Screens.Edit.Setup audioTrackTextBox = new FileChooserLabelledTextBox { Label = "Audio Track", - Current = { Value = Beatmap.Value.Metadata.AudioFile ?? "Click to select a track" }, + Current = { Value = Beatmap.Metadata.AudioFile ?? "Click to select a track" }, Target = audioTrackFileChooserContainer, TabbableContentContainer = this }, @@ -115,11 +118,11 @@ namespace osu.Game.Screens.Edit.Setup if (!info.Exists) return false; - var set = Beatmap.Value.BeatmapSetInfo; + var set = working.Value.BeatmapSetInfo; // remove the previous background for now. // in the future we probably want to check if this is being used elsewhere (other difficulties?) - var oldFile = set.Files.FirstOrDefault(f => f.Filename == Beatmap.Value.Metadata.BackgroundFile); + var oldFile = set.Files.FirstOrDefault(f => f.Filename == working.Value.Metadata.BackgroundFile); using (var stream = info.OpenRead()) { @@ -129,7 +132,7 @@ namespace osu.Game.Screens.Edit.Setup beatmaps.AddFile(set, stream, info.Name); } - Beatmap.Value.Metadata.BackgroundFile = info.Name; + working.Value.Metadata.BackgroundFile = info.Name; updateBackgroundSprite(); return true; @@ -148,11 +151,11 @@ namespace osu.Game.Screens.Edit.Setup if (!info.Exists) return false; - var set = Beatmap.Value.BeatmapSetInfo; + var set = working.Value.BeatmapSetInfo; // remove the previous audio track for now. // in the future we probably want to check if this is being used elsewhere (other difficulties?) - var oldFile = set.Files.FirstOrDefault(f => f.Filename == Beatmap.Value.Metadata.AudioFile); + var oldFile = set.Files.FirstOrDefault(f => f.Filename == working.Value.Metadata.AudioFile); using (var stream = info.OpenRead()) { @@ -162,7 +165,7 @@ namespace osu.Game.Screens.Edit.Setup beatmaps.AddFile(set, stream, info.Name); } - Beatmap.Value.Metadata.AudioFile = info.Name; + working.Value.Metadata.AudioFile = info.Name; music.ReloadCurrentTrack(); @@ -178,7 +181,7 @@ namespace osu.Game.Screens.Edit.Setup private void updateBackgroundSprite() { - LoadComponentAsync(new BeatmapBackgroundSprite(Beatmap.Value) + LoadComponentAsync(new BeatmapBackgroundSprite(working.Value) { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, diff --git a/osu.Game/Screens/Edit/Setup/SetupSection.cs b/osu.Game/Screens/Edit/Setup/SetupSection.cs index cdf17d355e..88521a8fb0 100644 --- a/osu.Game/Screens/Edit/Setup/SetupSection.cs +++ b/osu.Game/Screens/Edit/Setup/SetupSection.cs @@ -2,10 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; using osu.Game.Graphics; using osuTK; @@ -19,7 +17,7 @@ namespace osu.Game.Screens.Edit.Setup protected OsuColour Colours { get; private set; } [Resolved] - protected IBindable Beatmap { get; private set; } + protected EditorBeatmap Beatmap { get; private set; } protected override Container Content => flow; From 3b08faa0ea134d99f6cd9dcd02096df1ffac115a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Jan 2021 17:49:11 +0900 Subject: [PATCH 035/107] Fix RemoveBlockingOverlay causing transform mutation from disposal threads --- osu.Game/OsuGame.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 17831ed26b..36e3078653 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -151,11 +151,11 @@ namespace osu.Game updateBlockingOverlayFade(); } - public void RemoveBlockingOverlay(OverlayContainer overlay) + public void RemoveBlockingOverlay(OverlayContainer overlay) => Schedule(() => { visibleBlockingOverlays.Remove(overlay); updateBlockingOverlayFade(); - } + }); /// /// Close all game-wide overlays. From 2d1b52be0d8e02ffc4c4fbbd6a9f8f621d54f211 Mon Sep 17 00:00:00 2001 From: KyeKiller Date: Mon, 4 Jan 2021 17:21:31 +0000 Subject: [PATCH 036/107] Moved "ToolbarSocialButton" This will remove it from coming off the screen. --- osu.Game/Overlays/Toolbar/Toolbar.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 393e349bd0..88a2518f84 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -69,12 +69,13 @@ namespace osu.Game.Overlays.Toolbar AutoSizeAxes = Axes.X, Children = new Drawable[] { + + new ToolbarSocialButton(), new ToolbarNewsButton(), new ToolbarChangelogButton(), new ToolbarRankingsButton(), new ToolbarBeatmapListingButton(), new ToolbarChatButton(), - new ToolbarSocialButton(), new ToolbarMusicButton(), //new ToolbarButton //{ From 2e2b3ab5d4f66cd0295cd939a209c51485d59b41 Mon Sep 17 00:00:00 2001 From: KyeKiller Date: Mon, 4 Jan 2021 17:26:42 +0000 Subject: [PATCH 037/107] Should remove codeFactor error --- osu.Game/Overlays/Toolbar/Toolbar.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 88a2518f84..c95d02cea4 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -69,7 +69,6 @@ namespace osu.Game.Overlays.Toolbar AutoSizeAxes = Axes.X, Children = new Drawable[] { - new ToolbarSocialButton(), new ToolbarNewsButton(), new ToolbarChangelogButton(), From 73f5e5aaf9fb94726b6906f98b6493202fedb680 Mon Sep 17 00:00:00 2001 From: KyeKiller Date: Mon, 4 Jan 2021 21:03:51 +0000 Subject: [PATCH 038/107] Moved "ToolbarSocialButton" back --- osu.Game/Overlays/Toolbar/Toolbar.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index c95d02cea4..393e349bd0 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -69,12 +69,12 @@ namespace osu.Game.Overlays.Toolbar AutoSizeAxes = Axes.X, Children = new Drawable[] { - new ToolbarSocialButton(), new ToolbarNewsButton(), new ToolbarChangelogButton(), new ToolbarRankingsButton(), new ToolbarBeatmapListingButton(), new ToolbarChatButton(), + new ToolbarSocialButton(), new ToolbarMusicButton(), //new ToolbarButton //{ From 3468df840b37291dfdae94af3fb0d29a8e7493fa Mon Sep 17 00:00:00 2001 From: KyeKiller Date: Mon, 4 Jan 2021 21:04:30 +0000 Subject: [PATCH 039/107] Moved tooltip to the left to stop the overflow --- osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs b/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs index e62c7bc807..ca334702ce 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs @@ -2,12 +2,16 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Game.Input.Bindings; namespace osu.Game.Overlays.Toolbar { public class ToolbarSocialButton : ToolbarOverlayToggleButton { + + protected override Anchor TooltipAnchor => Anchor.TopRight; + public ToolbarSocialButton() { Hotkey = GlobalAction.ToggleSocial; From 0e42d415c18888192358e4f7e2a41074ebd0530f Mon Sep 17 00:00:00 2001 From: KyeKiller Date: Mon, 4 Jan 2021 21:05:28 +0000 Subject: [PATCH 040/107] Hit another oopie --- osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs b/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs index ca334702ce..1e00afc5fd 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs @@ -9,7 +9,6 @@ namespace osu.Game.Overlays.Toolbar { public class ToolbarSocialButton : ToolbarOverlayToggleButton { - protected override Anchor TooltipAnchor => Anchor.TopRight; public ToolbarSocialButton() From 1234d0fa0409c786c4e4ec4e2a63b5a5da406292 Mon Sep 17 00:00:00 2001 From: KyeKiller Date: Mon, 4 Jan 2021 22:01:12 +0000 Subject: [PATCH 041/107] Applied all tooltips to the right --- osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs | 3 +++ osu.Game/Overlays/Toolbar/ToolbarChangelogButton.cs | 5 ++++- osu.Game/Overlays/Toolbar/ToolbarChatButton.cs | 3 +++ osu.Game/Overlays/Toolbar/ToolbarNewsButton.cs | 3 +++ osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs | 3 +++ 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs b/osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs index 0363873326..c495d673ce 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs @@ -2,12 +2,15 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Game.Input.Bindings; namespace osu.Game.Overlays.Toolbar { public class ToolbarBeatmapListingButton : ToolbarOverlayToggleButton { + protected override Anchor TooltipAnchor => Anchor.TopRight; + public ToolbarBeatmapListingButton() { Hotkey = GlobalAction.ToggleDirect; diff --git a/osu.Game/Overlays/Toolbar/ToolbarChangelogButton.cs b/osu.Game/Overlays/Toolbar/ToolbarChangelogButton.cs index 23f8b141b2..28112d178f 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarChangelogButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarChangelogButton.cs @@ -2,11 +2,14 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Graphics; namespace osu.Game.Overlays.Toolbar { public class ToolbarChangelogButton : ToolbarOverlayToggleButton - { + { + protected override Anchor TooltipAnchor => Anchor.TopRight; + [BackgroundDependencyLoader(true)] private void load(ChangelogOverlay changelog) { diff --git a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs index f9a66ae7bb..2d3b33e9bc 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs @@ -2,12 +2,15 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Game.Input.Bindings; namespace osu.Game.Overlays.Toolbar { public class ToolbarChatButton : ToolbarOverlayToggleButton { + protected override Anchor TooltipAnchor => Anchor.TopRight; + public ToolbarChatButton() { Hotkey = GlobalAction.ToggleChat; diff --git a/osu.Game/Overlays/Toolbar/ToolbarNewsButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNewsButton.cs index 0ba2935c80..9b2573ad07 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarNewsButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarNewsButton.cs @@ -2,11 +2,14 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Graphics; namespace osu.Game.Overlays.Toolbar { public class ToolbarNewsButton : ToolbarOverlayToggleButton { + protected override Anchor TooltipAnchor => Anchor.TopRight; + [BackgroundDependencyLoader(true)] private void load(NewsOverlay news) { diff --git a/osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs index 22a01bcdb5..312fc41aab 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs @@ -2,11 +2,14 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Graphics; namespace osu.Game.Overlays.Toolbar { public class ToolbarRankingsButton : ToolbarOverlayToggleButton { + protected override Anchor TooltipAnchor => Anchor.TopRight; + [BackgroundDependencyLoader(true)] private void load(RankingsOverlay rankings) { From 77e660e42677eee4d2407b3b59a649f836b35f34 Mon Sep 17 00:00:00 2001 From: KyeKiller Date: Mon, 4 Jan 2021 22:11:52 +0000 Subject: [PATCH 042/107] Should pass all checks again now. --- osu.Game/Overlays/Toolbar/ToolbarChangelogButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarChangelogButton.cs b/osu.Game/Overlays/Toolbar/ToolbarChangelogButton.cs index 28112d178f..86bc73361a 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarChangelogButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarChangelogButton.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics; namespace osu.Game.Overlays.Toolbar { public class ToolbarChangelogButton : ToolbarOverlayToggleButton - { + { protected override Anchor TooltipAnchor => Anchor.TopRight; [BackgroundDependencyLoader(true)] From 81355652fa8601d4537cb6998afe6208da1b925d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 5 Jan 2021 06:00:15 +0300 Subject: [PATCH 043/107] Add simple test coverage --- .../TestSceneMultiplayerReadyButton.cs | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs index 6b11613f1c..03ba73d35b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs @@ -7,8 +7,10 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Framework.Platform; +using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Rulesets; @@ -23,6 +25,7 @@ namespace osu.Game.Tests.Visual.Multiplayer public class TestSceneMultiplayerReadyButton : MultiplayerTestScene { private MultiplayerReadyButton button; + private BeatmapSetInfo importedSet; private BeatmapManager beatmaps; private RulesetStore rulesets; @@ -38,9 +41,8 @@ namespace osu.Game.Tests.Visual.Multiplayer [SetUp] public new void Setup() => Schedule(() => { - var beatmap = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First().Beatmaps.First(); - - Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap); + importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First(); + Beatmap.Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First()); Child = button = new MultiplayerReadyButton { @@ -51,13 +53,30 @@ namespace osu.Game.Tests.Visual.Multiplayer { Value = new PlaylistItem { - Beatmap = { Value = beatmap }, - Ruleset = { Value = beatmap.Ruleset } + Beatmap = { Value = Beatmap.Value.BeatmapInfo }, + Ruleset = { Value = Beatmap.Value.BeatmapInfo.Ruleset } } } }; }); + [Test] + public void TestDeletedBeatmapDisableReady() + { + OsuButton readyButton = null; + + AddAssert("ensure ready button enabled", () => + { + readyButton = button.ChildrenOfType().Single(); + return readyButton.Enabled.Value; + }); + + AddStep("delete beatmap", () => beatmaps.Delete(importedSet)); + AddAssert("ready button disabled", () => !readyButton.Enabled.Value); + AddStep("undelete beatmap", () => beatmaps.Undelete(importedSet)); + AddAssert("ready button enabled back", () => readyButton.Enabled.Value); + } + [Test] public void TestToggleStateWhenNotHost() { From caa88c6100cb17d3307336ab43e00f16fbe98b01 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 13:13:51 +0900 Subject: [PATCH 044/107] Use CreateCopy instead of Clone interface I was going for conformity by using the IClonable interface, but it doesn't look like we use it anywhere else in the project. --- osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs | 4 ++-- osu.Game/Beatmaps/WorkingBeatmap.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index b56f9a106b..e8a91e4001 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -11,7 +11,7 @@ using osu.Framework.Lists; namespace osu.Game.Beatmaps.ControlPoints { [Serializable] - public class ControlPointInfo : ICloneable + public class ControlPointInfo { /// /// All control points grouped by time. @@ -298,7 +298,7 @@ namespace osu.Game.Beatmaps.ControlPoints } } - public object Clone() + public ControlPointInfo CreateCopy() { var controlPointInfo = new ControlPointInfo(); diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 06b5913b18..8688017887 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -112,7 +112,7 @@ namespace osu.Game.Beatmaps // Convert IBeatmap converted = converter.Convert(cancellationSource.Token); - converted.ControlPointInfo = (ControlPointInfo)converted.ControlPointInfo.Clone(); + converted.ControlPointInfo = converted.ControlPointInfo.CreateCopy(); // Apply conversion mods to the result foreach (var mod in mods.OfType()) From 385c9cd2e23e9f66b3b316b11b594c5377d27b77 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 13:14:16 +0900 Subject: [PATCH 045/107] Add test coverage --- .../NonVisual/ControlPointInfoTest.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/osu.Game.Tests/NonVisual/ControlPointInfoTest.cs b/osu.Game.Tests/NonVisual/ControlPointInfoTest.cs index 90a487c0ac..b27c257795 100644 --- a/osu.Game.Tests/NonVisual/ControlPointInfoTest.cs +++ b/osu.Game.Tests/NonVisual/ControlPointInfoTest.cs @@ -246,5 +246,32 @@ namespace osu.Game.Tests.NonVisual Assert.That(cpi.DifficultyPoints.Count, Is.EqualTo(0)); Assert.That(cpi.AllControlPoints.Count, Is.EqualTo(0)); } + + [Test] + public void TestCreateCopyIsDeepClone() + { + var cpi = new ControlPointInfo(); + + cpi.Add(1000, new TimingControlPoint { BeatLength = 500 }); + + var cpiCopy = cpi.CreateCopy(); + + cpiCopy.Add(2000, new TimingControlPoint { BeatLength = 500 }); + + Assert.That(cpi.Groups.Count, Is.EqualTo(1)); + Assert.That(cpiCopy.Groups.Count, Is.EqualTo(2)); + + Assert.That(cpi.TimingPoints.Count, Is.EqualTo(1)); + Assert.That(cpiCopy.TimingPoints.Count, Is.EqualTo(2)); + + Assert.That(cpi.TimingPoints[0], Is.Not.SameAs(cpiCopy.TimingPoints[0])); + Assert.That(cpi.TimingPoints[0].BeatLengthBindable, Is.Not.SameAs(cpiCopy.TimingPoints[0].BeatLengthBindable)); + + Assert.That(cpi.TimingPoints[0].BeatLength, Is.EqualTo(cpiCopy.TimingPoints[0].BeatLength)); + + cpi.TimingPoints[0].BeatLength = 800; + + Assert.That(cpi.TimingPoints[0].BeatLength, Is.Not.EqualTo(cpiCopy.TimingPoints[0].BeatLength)); + } } } From 6b8e1913eee030038ed4af72be5168d0c2ba7fab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 13:27:45 +0900 Subject: [PATCH 046/107] Fix dependency not always available due to nested LoadComponentAsync call --- osu.Game/Screens/Edit/EditorScreenWithTimeline.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs b/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs index b9457f422a..2d623a200c 100644 --- a/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs +++ b/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs @@ -30,16 +30,16 @@ namespace osu.Game.Screens.Edit { } + private Container mainContent; + + private LoadingSpinner spinner; + [BackgroundDependencyLoader(true)] private void load([CanBeNull] BindableBeatDivisor beatDivisor) { if (beatDivisor != null) this.beatDivisor.BindTo(beatDivisor); - Container mainContent; - - LoadingSpinner spinner; - Children = new Drawable[] { mainContent = new Container @@ -99,6 +99,11 @@ namespace osu.Game.Screens.Edit } }, }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); LoadComponentAsync(CreateMainContent(), content => { From afab35a31ad71e8f25e0d9084dc4edbb8e0183b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 13:41:31 +0900 Subject: [PATCH 047/107] Fix missing copy implementation in LegacySampleControlPiont --- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 06ff677aed..a06ad35b89 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -203,6 +203,13 @@ namespace osu.Game.Beatmaps.Formats => base.IsRedundant(existing) && existing is LegacySampleControlPoint existingSample && CustomSampleBank == existingSample.CustomSampleBank; + + public override void CopyFrom(ControlPoint other) + { + base.CopyFrom(other); + + CustomSampleBank = ((LegacySampleControlPoint)other).CustomSampleBank; + } } } } From 31a6e9b860ceb9ee1ece9441beb41b8aca042f5d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 14:24:49 +0900 Subject: [PATCH 048/107] Remove unused using --- osu.Game/Beatmaps/WorkingBeatmap.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 8688017887..d25adca92b 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -14,7 +14,6 @@ using osu.Framework.Graphics.Textures; using osu.Framework.Logging; using osu.Framework.Statistics; using osu.Framework.Testing; -using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Types; From ed6ffe2ef1b55d957851391d4635d0e93585dcf2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 14:54:59 +0900 Subject: [PATCH 049/107] Remove hacky code --- osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs index b782df75df..64ddba669d 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs @@ -53,14 +53,7 @@ namespace osu.Game.Screens.OnlinePlay.Components var databasedBeatmap = beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmapId && b.MD5Hash == checksum); - if (databasedBeatmap == null) - hasBeatmap = false; - else - { - // DeletePending isn't updated in the beatmap info query above, need to directly query the beatmap set from database as well. - var databasedSet = beatmaps.QueryBeatmapSet(s => s.Equals(databasedBeatmap.BeatmapSet)); - hasBeatmap = databasedSet?.DeletePending == false; - } + hasBeatmap = databasedBeatmap?.BeatmapSet?.DeletePending == false; } protected override void Update() From 962c95dc0158bfddf43ad8128dc4e1db2a131cb6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Jan 2021 19:06:00 +0900 Subject: [PATCH 050/107] Fix ModSelection making unsafe advances of ModSection --- osu.Game/Overlays/Mods/ModSection.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index 0107f94dcf..d00a365dde 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -130,7 +130,7 @@ namespace osu.Game.Overlays.Mods /// Select one or more mods in this section and deselects all other ones. /// /// The types of s which should be selected. - public void SelectTypes(IEnumerable modTypes) + public void SelectTypes(IEnumerable modTypes) => Schedule(() => { foreach (var button in buttons) { @@ -141,7 +141,7 @@ namespace osu.Game.Overlays.Mods else button.Deselect(); } - } + }); protected ModSection() { From a3e4e2f6c394544efae9df90228690fbdd3660c4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Jan 2021 18:24:21 +0900 Subject: [PATCH 051/107] Switch ResultsScreen and SongSelect inheritance and remove local implementation --- osu.Game/Screens/Ranking/ResultsScreen.cs | 4 +--- osu.Game/Screens/Select/SongSelect.cs | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index 528a1842af..98794627fe 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -25,7 +25,7 @@ using osuTK; namespace osu.Game.Screens.Ranking { - public abstract class ResultsScreen : OsuScreen, IKeyBindingHandler + public abstract class ResultsScreen : ScreenWithBeatmapBackground, IKeyBindingHandler { protected const float BACKGROUND_BLUR = 20; private static readonly float screen_height = 768 - TwoLayerButton.SIZE_EXTENDED.Y; @@ -35,8 +35,6 @@ namespace osu.Game.Screens.Ranking // Temporary for now to stop dual transitions. Should respect the current toolbar mode, but there's no way to do so currently. public override bool HideOverlaysOnEnter => true; - protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); - public readonly Bindable SelectedScore = new Bindable(); public readonly ScoreInfo Score; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index a5252fdc96..50a1dd6edf 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -41,7 +41,7 @@ using System.Diagnostics; namespace osu.Game.Screens.Select { - public abstract class SongSelect : OsuScreen, IKeyBindingHandler + public abstract class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler { public static readonly float WEDGE_HEIGHT = 245; @@ -76,8 +76,6 @@ namespace osu.Game.Screens.Select [Resolved] private Bindable> selectedMods { get; set; } - protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); - protected BeatmapCarousel Carousel { get; private set; } private BeatmapInfoWedge beatmapInfoWedge; From b3f08b29ca60b99f6c3aa2f3a5d3dec679452a06 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Jan 2021 18:32:23 +0900 Subject: [PATCH 052/107] Ensure that all changes to screen backgrounds are on the correct thread --- .../Background/TestSceneUserDimBackgrounds.cs | 55 ++++++++++++------- osu.Game/Rulesets/Mods/ModCinema.cs | 2 +- osu.Game/Screens/BackgroundScreen.cs | 2 + osu.Game/Screens/Edit/Editor.cs | 13 +++-- osu.Game/Screens/Menu/MainMenu.cs | 6 +- osu.Game/Screens/OsuScreen.cs | 21 +++++-- osu.Game/Screens/Play/EpilepsyWarning.cs | 21 ++++++- osu.Game/Screens/Play/Player.cs | 17 ++++-- osu.Game/Screens/Play/PlayerLoader.cs | 32 +++++++---- .../Play/ScreenWithBeatmapBackground.cs | 3 +- osu.Game/Screens/Ranking/ResultsScreen.cs | 14 +++-- osu.Game/Screens/Select/SongSelect.cs | 6 +- 12 files changed, 132 insertions(+), 60 deletions(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs index 5323f58a66..b5df3285f0 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs @@ -82,7 +82,7 @@ namespace osu.Game.Tests.Visual.Background }); AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); AddStep("Stop background preview", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); - AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect()); + AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.CheckBackgroundBlur(playerLoader.ExpectedBackgroundBlur)); } /// @@ -106,6 +106,7 @@ namespace osu.Game.Tests.Visual.Background public void TestStoryboardBackgroundVisibility() { performFullSetup(); + AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent()); createFakeStoryboard(); AddStep("Enable Storyboard", () => { @@ -198,8 +199,9 @@ namespace osu.Game.Tests.Visual.Background }))); AddUntilStep("Wait for results is current", () => results.IsCurrentScreen()); + AddUntilStep("Screen is undimmed, original background retained", () => - songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && results.IsBlurCorrect()); + songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && songSelect.CheckBackgroundBlur(results.ExpectedBackgroundBlur)); } /// @@ -224,7 +226,7 @@ namespace osu.Game.Tests.Visual.Background AddStep("Resume PlayerLoader", () => player.Restart()); AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); - AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect()); + AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.CheckBackgroundBlur(playerLoader.ExpectedBackgroundBlur)); } private void createFakeStoryboard() => AddStep("Create storyboard", () => @@ -274,9 +276,11 @@ namespace osu.Game.Tests.Visual.Background private class DummySongSelect : PlaySongSelect { + private FadeAccessibleBackground background; + protected override BackgroundScreen CreateBackground() { - FadeAccessibleBackground background = new FadeAccessibleBackground(Beatmap.Value); + background = new FadeAccessibleBackground(Beatmap.Value); DimEnabled.BindTo(background.EnableUserDim); return background; } @@ -294,42 +298,54 @@ namespace osu.Game.Tests.Visual.Background config.BindWith(OsuSetting.BlurLevel, BlurLevel); } - public bool IsBackgroundDimmed() => ((FadeAccessibleBackground)Background).CurrentColour == OsuColour.Gray(1f - ((FadeAccessibleBackground)Background).CurrentDim); + public bool IsBackgroundDimmed() => background.CurrentColour == OsuColour.Gray(1f - background.CurrentDim); - public bool IsBackgroundUndimmed() => ((FadeAccessibleBackground)Background).CurrentColour == Color4.White; + public bool IsBackgroundUndimmed() => background.CurrentColour == Color4.White; - public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR); + public bool IsUserBlurApplied() => background.CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR); - public bool IsUserBlurDisabled() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(0); + public bool IsUserBlurDisabled() => background.CurrentBlur == new Vector2(0); - public bool IsBackgroundInvisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 0; + public bool IsBackgroundInvisible() => background.CurrentAlpha == 0; - public bool IsBackgroundVisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 1; + public bool IsBackgroundVisible() => background.CurrentAlpha == 1; - public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR); + public bool IsBlurCorrect() => background.CurrentBlur == new Vector2(BACKGROUND_BLUR); + + public bool CheckBackgroundBlur(Vector2 expected) => background.CurrentBlur == expected; /// /// Make sure every time a screen gets pushed, the background doesn't get replaced /// /// Whether or not the original background (The one created in DummySongSelect) is still the current background - public bool IsBackgroundCurrent() => ((FadeAccessibleBackground)Background).IsCurrentScreen(); + public bool IsBackgroundCurrent() => background?.IsCurrentScreen() == true; } private class FadeAccessibleResults : ResultsScreen { + private FadeAccessibleBackground background; + public FadeAccessibleResults(ScoreInfo score) : base(score, true) { } - protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); + protected override BackgroundScreen CreateBackground() => background = new FadeAccessibleBackground(Beatmap.Value); - public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR); + public Vector2 ExpectedBackgroundBlur => new Vector2(BACKGROUND_BLUR); } private class LoadBlockingTestPlayer : TestPlayer { - protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); + protected override BackgroundScreen CreateBackground() => + new FadeAccessibleBackground(Beatmap.Value); + + public override void OnEntering(IScreen last) + { + base.OnEntering(last); + + ApplyToBackground(b => ReplacesBackground.BindTo(b.StoryboardReplacesBackground)); + } public new DimmableStoryboard DimmableStoryboard => base.DimmableStoryboard; @@ -354,15 +370,16 @@ namespace osu.Game.Tests.Visual.Background Thread.Sleep(1); StoryboardEnabled = config.GetBindable(OsuSetting.ShowStoryboard); - ReplacesBackground.BindTo(Background.StoryboardReplacesBackground); DrawableRuleset.IsPaused.BindTo(IsPaused); } } private class TestPlayerLoader : PlayerLoader { + private FadeAccessibleBackground background; + public VisualSettings VisualSettingsPos => VisualSettings; - public BackgroundScreen ScreenPos => Background; + public BackgroundScreen ScreenPos => background; public TestPlayerLoader(Player player) : base(() => player) @@ -371,9 +388,9 @@ namespace osu.Game.Tests.Visual.Background public void TriggerOnHover() => OnHover(new HoverEvent(new InputState())); - public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR); + public Vector2 ExpectedBackgroundBlur => new Vector2(BACKGROUND_BLUR); - protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); + protected override BackgroundScreen CreateBackground() => background = new FadeAccessibleBackground(Beatmap.Value); } private class FadeAccessibleBackground : BackgroundScreenBeatmap diff --git a/osu.Game/Rulesets/Mods/ModCinema.cs b/osu.Game/Rulesets/Mods/ModCinema.cs index cf8128301c..bee9e56edd 100644 --- a/osu.Game/Rulesets/Mods/ModCinema.cs +++ b/osu.Game/Rulesets/Mods/ModCinema.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Mods public void ApplyToPlayer(Player player) { - player.Background.EnableUserDim.Value = false; + player.ApplyToBackground(b => b.EnableUserDim.Value = false); player.DimmableStoryboard.IgnoreUserSettings.Value = true; diff --git a/osu.Game/Screens/BackgroundScreen.cs b/osu.Game/Screens/BackgroundScreen.cs index 0f3615b7a9..ea220c2f82 100644 --- a/osu.Game/Screens/BackgroundScreen.cs +++ b/osu.Game/Screens/BackgroundScreen.cs @@ -34,6 +34,8 @@ namespace osu.Game.Screens return false; } + public void ApplyToBackground(Action action) => Schedule(() => action.Invoke(this)); + protected override void Update() { base.Update(); diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 223c678fba..8c34cb2e08 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -444,11 +444,14 @@ namespace osu.Game.Screens.Edit { base.OnEntering(last); - // todo: temporary. we want to be applying dim using the UserDimContainer eventually. - Background.FadeColour(Color4.DarkGray, 500); + ApplyToBackground(b => + { + // todo: temporary. we want to be applying dim using the UserDimContainer eventually. + b.FadeColour(Color4.DarkGray, 500); - Background.EnableUserDim.Value = false; - Background.BlurAmount.Value = 0; + b.EnableUserDim.Value = false; + b.BlurAmount.Value = 0; + }); resetTrack(true); } @@ -480,7 +483,7 @@ namespace osu.Game.Screens.Edit } } - Background.FadeColour(Color4.White, 500); + ApplyToBackground(b => b.FadeColour(Color4.White, 500)); resetTrack(); return base.OnExiting(next); diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 9d5720ff34..97fd58318b 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -127,11 +127,11 @@ namespace osu.Game.Screens.Menu { case ButtonSystemState.Initial: case ButtonSystemState.Exit: - Background.FadeColour(Color4.White, 500, Easing.OutSine); + ApplyToBackground(b => b.FadeColour(Color4.White, 500, Easing.OutSine)); break; default: - Background.FadeColour(OsuColour.Gray(0.8f), 500, Easing.OutSine); + ApplyToBackground(b => b.FadeColour(OsuColour.Gray(0.8f), 500, Easing.OutSine)); break; } }; @@ -256,7 +256,7 @@ namespace osu.Game.Screens.Menu { base.OnResuming(last); - (Background as BackgroundScreenDefault)?.Next(); + ApplyToBackground(b => (b as BackgroundScreenDefault)?.Next()); // we may have consumed our preloaded instance, so let's make another. preloadSongSelect(); diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 851aedd84f..c97c0aef2b 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -114,9 +114,14 @@ namespace osu.Game.Screens Mods = screenDependencies.Mods; } - protected BackgroundScreen Background => backgroundStack?.CurrentScreen as BackgroundScreen; + public void ApplyToBackground(Action action) => background.ApplyToBackground(action); - private BackgroundScreen localBackground; + /// + /// The background created and owned by this screen. May be null if the background didn't change. + /// + private BackgroundScreen ownedBackground; + + private BackgroundScreen background; [Resolved(canBeNull: true)] private BackgroundScreenStack backgroundStack { get; set; } @@ -160,7 +165,15 @@ namespace osu.Game.Screens { applyArrivingDefaults(false); - backgroundStack?.Push(localBackground = CreateBackground()); + backgroundStack?.Push(ownedBackground = CreateBackground()); + + background = backgroundStack?.CurrentScreen as BackgroundScreen; + + if (background != ownedBackground) + { + // background may have not been replaced, at which point we don't want to track the background lifetime. + ownedBackground = null; + } base.OnEntering(last); } @@ -173,7 +186,7 @@ namespace osu.Game.Screens if (base.OnExiting(next)) return true; - if (localBackground != null && backgroundStack?.CurrentScreen == localBackground) + if (ownedBackground != null && backgroundStack?.CurrentScreen == ownedBackground) backgroundStack?.Exit(); return false; diff --git a/osu.Game/Screens/Play/EpilepsyWarning.cs b/osu.Game/Screens/Play/EpilepsyWarning.cs index dc42427fbf..89e25d849f 100644 --- a/osu.Game/Screens/Play/EpilepsyWarning.cs +++ b/osu.Game/Screens/Play/EpilepsyWarning.cs @@ -24,7 +24,19 @@ namespace osu.Game.Screens.Play Alpha = 0f; } - public BackgroundScreenBeatmap DimmableBackground { get; set; } + private BackgroundScreenBeatmap dimmableBackground; + + public BackgroundScreenBeatmap DimmableBackground + { + get => dimmableBackground; + set + { + dimmableBackground = value; + + if (IsLoaded) + updateBackgroundFade(); + } + } [BackgroundDependencyLoader] private void load(OsuColour colours, IBindable beatmap) @@ -75,11 +87,16 @@ namespace osu.Game.Screens.Play protected override void PopIn() { - DimmableBackground?.FadeColour(OsuColour.Gray(0.5f), FADE_DURATION, Easing.OutQuint); + updateBackgroundFade(); this.FadeIn(FADE_DURATION, Easing.OutQuint); } + private void updateBackgroundFade() + { + DimmableBackground?.FadeColour(OsuColour.Gray(0.5f), FADE_DURATION, Easing.OutQuint); + } + protected override void PopOut() => this.FadeOut(FADE_DURATION); } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index bf2e6f5379..1fcbed7ef7 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -721,15 +721,20 @@ namespace osu.Game.Screens.Play .Delay(250) .FadeIn(250); - Background.EnableUserDim.Value = true; - Background.BlurAmount.Value = 0; + ApplyToBackground(b => + { + b.EnableUserDim.Value = true; + b.BlurAmount.Value = 0; + + // bind component bindables. + b.IsBreakTime.BindTo(breakTracker.IsBreakTime); + + b.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground); + }); - // bind component bindables. - Background.IsBreakTime.BindTo(breakTracker.IsBreakTime); HUDOverlay.IsBreakTime.BindTo(breakTracker.IsBreakTime); DimmableStoryboard.IsBreakTime.BindTo(breakTracker.IsBreakTime); - Background.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground); DimmableStoryboard.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground); storyboardReplacesBackground.Value = Beatmap.Value.Storyboard.ReplacesBackground && Beatmap.Value.Storyboard.HasDrawable; @@ -875,7 +880,7 @@ namespace osu.Game.Screens.Play float fadeOutDuration = instant ? 0 : 250; this.FadeOut(fadeOutDuration); - Background.EnableUserDim.Value = false; + ApplyToBackground(b => b.EnableUserDim.Value = false); storyboardReplacesBackground.Value = false; } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index f59b36bc42..5b4bd11216 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -67,7 +67,7 @@ namespace osu.Game.Screens.Play backgroundBrightnessReduction = value; - Background.FadeColour(OsuColour.Gray(backgroundBrightnessReduction ? 0.8f : 1), 200); + ApplyToBackground(b => b.FadeColour(OsuColour.Gray(backgroundBrightnessReduction ? 0.8f : 1), 200)); } } @@ -176,12 +176,17 @@ namespace osu.Game.Screens.Play { base.OnEntering(last); - if (epilepsyWarning != null) - epilepsyWarning.DimmableBackground = Background; + ApplyToBackground(b => + { + if (epilepsyWarning != null) + epilepsyWarning.DimmableBackground = b; + + b?.FadeColour(Color4.White, 800, Easing.OutQuint); + }); + Beatmap.Value.Track.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment); content.ScaleTo(0.7f); - Background?.FadeColour(Color4.White, 800, Easing.OutQuint); contentIn(); @@ -225,7 +230,8 @@ namespace osu.Game.Screens.Play content.ScaleTo(0.7f, 150, Easing.InQuint); this.FadeOut(150); - Background.EnableUserDim.Value = false; + ApplyToBackground(b => b.EnableUserDim.Value = false); + BackgroundBrightnessReduction = false; Beatmap.Value.Track.RemoveAdjustment(AdjustableProperty.Volume, volumeAdjustment); @@ -270,16 +276,22 @@ namespace osu.Game.Screens.Play if (inputManager.HoveredDrawables.Contains(VisualSettings)) { // Preview user-defined background dim and blur when hovered on the visual settings panel. - Background.EnableUserDim.Value = true; - Background.BlurAmount.Value = 0; + ApplyToBackground(b => + { + b.EnableUserDim.Value = true; + b.BlurAmount.Value = 0; + }); BackgroundBrightnessReduction = false; } else { - // Returns background dim and blur to the values specified by PlayerLoader. - Background.EnableUserDim.Value = false; - Background.BlurAmount.Value = BACKGROUND_BLUR; + ApplyToBackground(b => + { + // Returns background dim and blur to the values specified by PlayerLoader. + b.EnableUserDim.Value = false; + b.BlurAmount.Value = BACKGROUND_BLUR; + }); BackgroundBrightnessReduction = true; } diff --git a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs index 8eb253608b..88dab88d42 100644 --- a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs +++ b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Game.Screens.Backgrounds; namespace osu.Game.Screens.Play @@ -9,6 +10,6 @@ namespace osu.Game.Screens.Play { protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); - public new BackgroundScreenBeatmap Background => (BackgroundScreenBeatmap)base.Background; + public void ApplyToBackground(Action action) => base.ApplyToBackground(b => action.Invoke((BackgroundScreenBeatmap)b)); } } diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index 98794627fe..c1f5d92d17 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -18,7 +18,6 @@ using osu.Game.Input.Bindings; using osu.Game.Online.API; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; -using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking.Statistics; using osuTK; @@ -235,15 +234,18 @@ namespace osu.Game.Screens.Ranking { base.OnEntering(last); - ((BackgroundScreenBeatmap)Background).BlurAmount.Value = BACKGROUND_BLUR; + ApplyToBackground(b => + { + b.BlurAmount.Value = BACKGROUND_BLUR; + b.FadeTo(0.5f, 250); + }); - Background.FadeTo(0.5f, 250); bottomPanel.FadeTo(1, 250); } public override bool OnExiting(IScreen next) { - Background.FadeTo(1, 250); + ApplyToBackground(b => b.FadeTo(1, 250)); return base.OnExiting(next); } @@ -293,7 +295,7 @@ namespace osu.Game.Screens.Ranking ScorePanelList.HandleInput = false; // Dim background. - Background.FadeTo(0.1f, 150); + ApplyToBackground(b => b.FadeTo(0.1f, 150)); detachedPanel = expandedPanel; } @@ -317,7 +319,7 @@ namespace osu.Game.Screens.Ranking ScorePanelList.HandleInput = true; // Un-dim background. - Background.FadeTo(0.5f, 150); + ApplyToBackground(b => b.FadeTo(0.5f, 150)); detachedPanel = null; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 50a1dd6edf..3c255011c9 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -19,7 +19,6 @@ using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; using osu.Game.Screens.Menu; using osu.Game.Screens.Select.Options; @@ -38,6 +37,7 @@ using osu.Game.Collections; using osu.Game.Graphics.UserInterface; using osu.Game.Scoring; using System.Diagnostics; +using osu.Game.Screens.Play; namespace osu.Game.Screens.Select { @@ -682,12 +682,12 @@ namespace osu.Game.Screens.Select /// The working beatmap. private void updateComponentFromBeatmap(WorkingBeatmap beatmap) { - if (Background is BackgroundScreenBeatmap backgroundModeBeatmap) + ApplyToBackground(backgroundModeBeatmap => { backgroundModeBeatmap.Beatmap = beatmap; backgroundModeBeatmap.BlurAmount.Value = BACKGROUND_BLUR; backgroundModeBeatmap.FadeColour(Color4.White, 250); - } + }); beatmapInfoWedge.Beatmap = beatmap; From 5904e426ebf666ce8191ec5902389adc9f25b1b7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 16:00:25 +0900 Subject: [PATCH 053/107] Remove unused variable --- .../Visual/Background/TestSceneUserDimBackgrounds.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs index b5df3285f0..7ade7725d9 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs @@ -323,14 +323,12 @@ namespace osu.Game.Tests.Visual.Background private class FadeAccessibleResults : ResultsScreen { - private FadeAccessibleBackground background; - public FadeAccessibleResults(ScoreInfo score) : base(score, true) { } - protected override BackgroundScreen CreateBackground() => background = new FadeAccessibleBackground(Beatmap.Value); + protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); public Vector2 ExpectedBackgroundBlur => new Vector2(BACKGROUND_BLUR); } From 57a8cd74615765e54d60a425f904a4034045b1a0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 16:17:55 +0900 Subject: [PATCH 054/107] Schedule deselection operations for safety --- osu.Game/Overlays/Mods/ModSection.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index d00a365dde..47b101c2b0 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -104,7 +104,7 @@ namespace osu.Game.Overlays.Mods /// /// The types of s which should be deselected. /// Set to true to bypass animations and update selections immediately. - public void DeselectTypes(IEnumerable modTypes, bool immediate = false) + public void DeselectTypes(IEnumerable modTypes, bool immediate = false) => Schedule(() => { int delay = 0; @@ -124,7 +124,7 @@ namespace osu.Game.Overlays.Mods } } } - } + }); /// /// Select one or more mods in this section and deselects all other ones. From 9bac791a576a0b16860f3addb3ef3a451d166d1c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 16:17:42 +0900 Subject: [PATCH 055/107] Fix deselection of autoplay mod failing --- osu.Game/Screens/Select/PlaySongSelect.cs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 50a61ed4c2..e61d5cce85 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -9,6 +9,7 @@ using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; +using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; @@ -42,6 +43,8 @@ namespace osu.Game.Screens.Select protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); + private ModAutoplay getAutoplayMod() => Ruleset.Value.CreateInstance().GetAutoplayMod(); + public override void OnResuming(IScreen last) { base.OnResuming(last); @@ -50,10 +53,10 @@ namespace osu.Game.Screens.Select if (removeAutoModOnResume) { - var autoType = Ruleset.Value.CreateInstance().GetAutoplayMod()?.GetType(); + var autoType = getAutoplayMod()?.GetType(); if (autoType != null) - ModSelect.DeselectTypes(new[] { autoType }, true); + Mods.Value = Mods.Value.Where(m => m.GetType() != autoType).ToArray(); removeAutoModOnResume = false; } @@ -81,12 +84,9 @@ namespace osu.Game.Screens.Select // Ctrl+Enter should start map with autoplay enabled. if (GetContainingInputManager().CurrentState?.Keyboard.ControlPressed == true) { - var auto = Ruleset.Value.CreateInstance().GetAutoplayMod(); - var autoType = auto?.GetType(); + var autoplayMod = getAutoplayMod(); - var mods = Mods.Value; - - if (autoType == null) + if (autoplayMod == null) { notifications?.Post(new SimpleNotification { @@ -95,9 +95,11 @@ namespace osu.Game.Screens.Select return false; } - if (mods.All(m => m.GetType() != autoType)) + var mods = Mods.Value; + + if (mods.All(m => m.GetType() != autoplayMod.GetType())) { - Mods.Value = mods.Append(auto).ToArray(); + Mods.Value = mods.Append(autoplayMod).ToArray(); removeAutoModOnResume = true; } } From 4d6c13f169cc7c09c4db61bbfdfd780c5b44fef5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 16:18:13 +0900 Subject: [PATCH 056/107] Privatise ModSelectOverlay methods that may be unsafe to be called externally --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 34f5c70adb..491052fa2c 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -249,7 +249,7 @@ namespace osu.Game.Overlays.Mods { Width = 180, Text = "Deselect All", - Action = DeselectAll, + Action = deselectAll, Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, }, @@ -318,7 +318,7 @@ namespace osu.Game.Overlays.Mods sampleOff = audio.Samples.Get(@"UI/check-off"); } - public void DeselectAll() + private void deselectAll() { foreach (var section in ModSectionsContainer.Children) section.DeselectAll(); @@ -331,7 +331,7 @@ namespace osu.Game.Overlays.Mods /// /// The types of s which should be deselected. /// Set to true to bypass animations and update selections immediately. - public void DeselectTypes(Type[] modTypes, bool immediate = false) + private void deselectTypes(Type[] modTypes, bool immediate = false) { if (modTypes.Length == 0) return; @@ -438,7 +438,7 @@ namespace osu.Game.Overlays.Mods { if (State.Value == Visibility.Visible) sampleOn?.Play(); - DeselectTypes(selectedMod.IncompatibleMods, true); + deselectTypes(selectedMod.IncompatibleMods, true); if (selectedMod.RequiresConfiguration) ModSettingsContainer.Show(); } From 5d8c153c1e21949156a0dbf54b9cf8d71bca4c4d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 16:41:03 +0900 Subject: [PATCH 057/107] Move schedule logic to buttons rather than section It turns out there's some quite convoluted scheduling / order of execution requirements of ModSelectOverlay and ModSection. Applying scheduling causes a runaway condition ending in zero frames after many mod button changes. I wanted to avoid rewriting the whole component, so have just moved the schedule to guard against the part where drawables are actually changed. --- osu.Game/Overlays/Mods/ModButton.cs | 62 +++++++++++++++------------- osu.Game/Overlays/Mods/ModSection.cs | 8 ++-- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index e574828cd2..51c8bcf9a9 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -64,41 +64,45 @@ namespace osu.Game.Overlays.Mods if (newIndex >= 0 && !Mods[newIndex].HasImplementation) return false; - selectedIndex = newIndex; - Mod modAfter = SelectedMod ?? Mods[0]; - - if (beforeSelected != Selected) + Schedule(() => { - iconsContainer.RotateTo(Selected ? 5f : 0f, 300, Easing.OutElastic); - iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, Easing.OutElastic); - } + selectedIndex = newIndex; + Mod modAfter = SelectedMod ?? Mods[0]; - if (modBefore != modAfter) - { - const float rotate_angle = 16; - - foregroundIcon.RotateTo(rotate_angle * direction, mod_switch_duration, mod_switch_easing); - backgroundIcon.RotateTo(-rotate_angle * direction, mod_switch_duration, mod_switch_easing); - - backgroundIcon.Mod = modAfter; - - using (BeginDelayedSequence(mod_switch_duration, true)) + if (beforeSelected != Selected) { - foregroundIcon - .RotateTo(-rotate_angle * direction) - .RotateTo(0f, mod_switch_duration, mod_switch_easing); - - backgroundIcon - .RotateTo(rotate_angle * direction) - .RotateTo(0f, mod_switch_duration, mod_switch_easing); - - Schedule(() => displayMod(modAfter)); + iconsContainer.RotateTo(Selected ? 5f : 0f, 300, Easing.OutElastic); + iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, Easing.OutElastic); } - } - foregroundIcon.Selected.Value = Selected; + if (modBefore != modAfter) + { + const float rotate_angle = 16; + + foregroundIcon.RotateTo(rotate_angle * direction, mod_switch_duration, mod_switch_easing); + backgroundIcon.RotateTo(-rotate_angle * direction, mod_switch_duration, mod_switch_easing); + + backgroundIcon.Mod = modAfter; + + using (BeginDelayedSequence(mod_switch_duration, true)) + { + foregroundIcon + .RotateTo(-rotate_angle * direction) + .RotateTo(0f, mod_switch_duration, mod_switch_easing); + + backgroundIcon + .RotateTo(rotate_angle * direction) + .RotateTo(0f, mod_switch_duration, mod_switch_easing); + + Schedule(() => displayMod(modAfter)); + } + } + + foregroundIcon.Selected.Value = Selected; + + SelectionChanged?.Invoke(SelectedMod); + }); - SelectionChanged?.Invoke(SelectedMod); return true; } diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index 47b101c2b0..0107f94dcf 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -104,7 +104,7 @@ namespace osu.Game.Overlays.Mods /// /// The types of s which should be deselected. /// Set to true to bypass animations and update selections immediately. - public void DeselectTypes(IEnumerable modTypes, bool immediate = false) => Schedule(() => + public void DeselectTypes(IEnumerable modTypes, bool immediate = false) { int delay = 0; @@ -124,13 +124,13 @@ namespace osu.Game.Overlays.Mods } } } - }); + } /// /// Select one or more mods in this section and deselects all other ones. /// /// The types of s which should be selected. - public void SelectTypes(IEnumerable modTypes) => Schedule(() => + public void SelectTypes(IEnumerable modTypes) { foreach (var button in buttons) { @@ -141,7 +141,7 @@ namespace osu.Game.Overlays.Mods else button.Deselect(); } - }); + } protected ModSection() { From 54982dcdd7e46ee8081f176ebc07b9037e0bfd5c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 4 Jan 2021 22:42:39 +0900 Subject: [PATCH 058/107] Refactor LoadingLayer to avoid applying effects to external drawables In theory this seemed like a good idea (and an optimisation in some cases, due to lower fill rate), but in practice this leads to weird edge cases. This aims to do away with the operations on external drawables by applying a dim to the area behind the `LoadingLayer` when required. I went over each usage and ensured they look as good or better than previously. The specific bad usage here was the restoration of the colour on dispose (if the `LoadingLayer` was disposed in a still-visible state). I'm aware that the `BeatmapListingOverlay` will now dim completely during load. I think this is fine for the time being. --- .../UserInterface/TestSceneLoadingLayer.cs | 10 +- .../Graphics/UserInterface/LoadingLayer.cs | 29 +- .../Overlays/AccountCreation/ScreenEntry.cs | 2 +- osu.Game/Overlays/BeatmapListingOverlay.cs | 8 +- .../BeatmapSet/Buttons/FavouriteButton.cs | 2 +- .../BeatmapSet/Scores/ScoresContainer.cs | 10 +- .../Dashboard/Friends/FriendDisplay.cs | 2 +- osu.Game/Overlays/DashboardOverlay.cs | 2 +- osu.Game/Overlays/NewsOverlay.cs | 2 +- .../Overlays/Rankings/SpotlightsLayout.cs | 3 +- osu.Game/Overlays/RankingsOverlay.cs | 6 +- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 2 +- .../Match/MultiplayerMatchSettingsOverlay.cs | 279 ++++++------ .../Multiplayer/MultiplayerMatchSongSelect.cs | 2 +- .../Multiplayer/MultiplayerPlayer.cs | 2 +- .../PlaylistsMatchSettingsOverlay.cs | 409 +++++++++--------- .../Screens/Play/BeatmapMetadataDisplay.cs | 2 +- osu.Game/Screens/Select/BeatmapDetails.cs | 6 +- 18 files changed, 389 insertions(+), 389 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs index 1be191fc29..a694595115 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -14,11 +15,12 @@ namespace osu.Game.Tests.Visual.UserInterface { public class TestSceneLoadingLayer : OsuTestScene { - private Drawable dimContent; private LoadingLayer overlay; private Container content; + private Drawable dimContent => overlay.Children.OfType().First(); + [SetUp] public void SetUp() => Schedule(() => { @@ -29,14 +31,14 @@ namespace osu.Game.Tests.Visual.UserInterface Size = new Vector2(300), Anchor = Anchor.Centre, Origin = Anchor.Centre, - Children = new[] + Children = new Drawable[] { new Box { Colour = Color4.SlateGray, RelativeSizeAxes = Axes.Both, }, - dimContent = new FillFlowContainer + new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -51,7 +53,7 @@ namespace osu.Game.Tests.Visual.UserInterface new TriangleButton { Text = "puush me", Width = 200, Action = () => { } }, } }, - overlay = new LoadingLayer(dimContent), + overlay = new LoadingLayer(true), } }, }; diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index c8c4424bee..6aca30328a 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osuTK; using osuTK.Graphics; @@ -17,22 +18,31 @@ namespace osu.Game.Graphics.UserInterface /// public class LoadingLayer : LoadingSpinner { - private readonly Drawable dimTarget; + private readonly Box backgroundDimLayer; /// - /// Constuct a new loading spinner. + /// Construct a new loading spinner. /// - /// An optional target to dim when displayed. + /// Whether the full background area should be dimmed while loading. /// Whether the spinner should have a surrounding black box for visibility. - public LoadingLayer(Drawable dimTarget = null, bool withBox = true) + public LoadingLayer(bool dimBackground = false, bool withBox = true) : base(withBox) { RelativeSizeAxes = Axes.Both; Size = new Vector2(1); - this.dimTarget = dimTarget; - MainContents.RelativeSizeAxes = Axes.None; + + if (dimBackground) + { + AddInternal(backgroundDimLayer = new Box + { + Depth = float.MaxValue, + Colour = Color4.Black, + Alpha = 0, + RelativeSizeAxes = Axes.Both, + }); + } } public override bool HandleNonPositionalInput => false; @@ -56,19 +66,20 @@ namespace osu.Game.Graphics.UserInterface protected override void PopIn() { - dimTarget?.FadeColour(OsuColour.Gray(0.5f), TRANSITION_DURATION, Easing.OutQuint); + backgroundDimLayer?.FadeTo(0.5f, TRANSITION_DURATION * 2, Easing.OutQuint); base.PopIn(); } protected override void PopOut() { - dimTarget?.FadeColour(Color4.White, TRANSITION_DURATION, Easing.OutQuint); + backgroundDimLayer?.FadeOut(TRANSITION_DURATION, Easing.OutQuint); base.PopOut(); } protected override void Update() { base.Update(); + MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 30, 100)); } @@ -79,7 +90,7 @@ namespace osu.Game.Graphics.UserInterface if (State.Value == Visibility.Visible) { // ensure we don't leave the target in a bad state. - dimTarget?.FadeColour(Color4.White, TRANSITION_DURATION, Easing.OutQuint); + // dimTarget?.FadeColour(Color4.White, TRANSITION_DURATION, Easing.OutQuint); } } } diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs index a0b1b27ebf..0d5538155a 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs @@ -124,7 +124,7 @@ namespace osu.Game.Overlays.AccountCreation }, }, }, - loadingLayer = new LoadingLayer(mainContent) + loadingLayer = new LoadingLayer(true) }; textboxes = new[] { usernameTextBox, emailTextBox, passwordTextBox }; diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 1e29e713af..0c9c995dd6 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -92,14 +92,14 @@ namespace osu.Game.Overlays { foundContent = new FillFlowContainer(), notFoundContent = new NotFoundDrawable(), - loadingLayer = new LoadingLayer(panelTarget) } } - } + }, }, } - } - } + }, + }, + loadingLayer = new LoadingLayer(true) }; } diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs index c983b337b5..7ad6906cea 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs @@ -53,7 +53,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons Size = new Vector2(18), Shadow = false, }, - loading = new LoadingLayer(icon, false), + loading = new LoadingLayer(true, false), }); Action = () => diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 9a2dcd014a..b598b7d97f 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -157,11 +157,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } } }, - loading = new LoadingLayer() } } - } - } + }, + }, + loading = new LoadingLayer() }); } @@ -228,7 +228,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { Scores = null; notSupporterPlaceholder.Show(); + loading.Hide(); + loading.FinishTransforms(); return; } @@ -241,6 +243,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores getScoresRequest.Success += scores => { loading.Hide(); + loading.FinishTransforms(); + Scores = scores; if (!scores.Scores.Any()) diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs index cc26a11da1..e6fe6ac749 100644 --- a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs +++ b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs @@ -128,7 +128,7 @@ namespace osu.Game.Overlays.Dashboard.Friends AutoSizeAxes = Axes.Y, Padding = new MarginPadding { Horizontal = 50 } }, - loading = new LoadingLayer(itemsPlaceholder) + loading = new LoadingLayer(true) } } } diff --git a/osu.Game/Overlays/DashboardOverlay.cs b/osu.Game/Overlays/DashboardOverlay.cs index 04defce636..03c320debe 100644 --- a/osu.Game/Overlays/DashboardOverlay.cs +++ b/osu.Game/Overlays/DashboardOverlay.cs @@ -68,7 +68,7 @@ namespace osu.Game.Overlays } } }, - loading = new LoadingLayer(content), + loading = new LoadingLayer(true), }; } diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index c8c1db012f..5820d405d4 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -59,7 +59,7 @@ namespace osu.Game.Overlays }, }, }, - loading = new LoadingLayer(content), + loading = new LoadingLayer(true), }; } diff --git a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs index 61339df76f..b16e0a4908 100644 --- a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs +++ b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs @@ -45,6 +45,7 @@ namespace osu.Game.Overlays.Rankings { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; + InternalChild = new ReverseChildIDFillFlowContainer { RelativeSizeAxes = Axes.X, @@ -68,7 +69,7 @@ namespace osu.Game.Overlays.Rankings AutoSizeAxes = Axes.Y, Margin = new MarginPadding { Vertical = 10 } }, - loading = new LoadingLayer(content) + loading = new LoadingLayer(true) } } } diff --git a/osu.Game/Overlays/RankingsOverlay.cs b/osu.Game/Overlays/RankingsOverlay.cs index ae6d49960a..25350e310a 100644 --- a/osu.Game/Overlays/RankingsOverlay.cs +++ b/osu.Game/Overlays/RankingsOverlay.cs @@ -42,6 +42,8 @@ namespace osu.Game.Overlays Depth = -float.MaxValue }) { + loading = new LoadingLayer(true); + Children = new Drawable[] { background = new Box @@ -74,12 +76,12 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.X, Margin = new MarginPadding { Bottom = 10 } }, - loading = new LoadingLayer(contentContainer), } } } } - } + }, + loading }; } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 79f5dfdee1..0f06188dc2 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -65,7 +65,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge Padding = new MarginPadding(10), Child = roomsContainer = new RoomsContainer { JoinRequested = joinRequested } }, - loadingLayer = new LoadingLayer(roomsContainer), + loadingLayer = new LoadingLayer(true), } }, new RoomInspector diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index ae03d384f6..67c6aa7add 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -71,201 +71,192 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match [BackgroundDependencyLoader] private void load(OsuColour colours) { - Container dimContent; - InternalChildren = new Drawable[] { - dimContent = new Container + new Box { RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + Colour = Color4Extensions.FromHex(@"28242d"), + }, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] { - new Box + new Dimension(GridSizeMode.Distributed), + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"28242d"), - }, - new GridContainer - { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] + new OsuScrollContainer { - new Dimension(GridSizeMode.Distributed), - new Dimension(GridSizeMode.AutoSize), - }, - Content = new[] - { - new Drawable[] + Padding = new MarginPadding { - new OsuScrollContainer + Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING, + Vertical = 10 + }, + RelativeSizeAxes = Axes.Both, + Children = new[] + { + new FillFlowContainer { - Padding = new MarginPadding + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 10), + Children = new Drawable[] { - Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING, - Vertical = 10 - }, - RelativeSizeAxes = Axes.Both, - Children = new[] - { - new FillFlowContainer + new Container { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 10), Children = new Drawable[] { - new Container + new SectionContainer { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING }, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] + Padding = new MarginPadding { Right = FIELD_PADDING / 2 }, + Children = new[] { - new SectionContainer + new Section("Room name") { - Padding = new MarginPadding { Right = FIELD_PADDING / 2 }, - Children = new[] + Child = NameField = new SettingsTextBox { - new Section("Room name") + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + }, + }, + new Section("Room visibility") + { + Alpha = disabled_alpha, + Child = AvailabilityPicker = new RoomAvailabilityPicker + { + Enabled = { Value = false } + }, + }, + new Section("Game type") + { + Alpha = disabled_alpha, + Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Spacing = new Vector2(7), + Children = new Drawable[] { - Child = NameField = new SettingsTextBox + TypePicker = new GameTypePicker { RelativeSizeAxes = Axes.X, - TabbableContentContainer = this, - }, - }, - new Section("Room visibility") - { - Alpha = disabled_alpha, - Child = AvailabilityPicker = new RoomAvailabilityPicker - { Enabled = { Value = false } }, - }, - new Section("Game type") - { - Alpha = disabled_alpha, - Child = new FillFlowContainer + typeLabel = new OsuSpriteText { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, - Spacing = new Vector2(7), - Children = new Drawable[] - { - TypePicker = new GameTypePicker - { - RelativeSizeAxes = Axes.X, - Enabled = { Value = false } - }, - typeLabel = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 14), - Colour = colours.Yellow - }, - }, + Font = OsuFont.GetFont(size: 14), + Colour = colours.Yellow }, }, }, }, - new SectionContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Padding = new MarginPadding { Left = FIELD_PADDING / 2 }, - Children = new[] - { - new Section("Max participants") - { - Alpha = disabled_alpha, - Child = MaxParticipantsField = new SettingsNumberTextBox - { - RelativeSizeAxes = Axes.X, - TabbableContentContainer = this, - ReadOnly = true, - }, - }, - new Section("Password (optional)") - { - Alpha = disabled_alpha, - Child = new SettingsPasswordTextBox - { - RelativeSizeAxes = Axes.X, - TabbableContentContainer = this, - ReadOnly = true, - }, - }, - } - } }, }, - initialBeatmapControl = new BeatmapSelectionControl + new SectionContainer { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - Width = 0.5f + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Padding = new MarginPadding { Left = FIELD_PADDING / 2 }, + Children = new[] + { + new Section("Max participants") + { + Alpha = disabled_alpha, + Child = MaxParticipantsField = new SettingsNumberTextBox + { + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + ReadOnly = true, + }, + }, + new Section("Password (optional)") + { + Alpha = disabled_alpha, + Child = new SettingsPasswordTextBox + { + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + ReadOnly = true, + }, + }, + } } - } + }, + }, + initialBeatmapControl = new BeatmapSelectionControl + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + Width = 0.5f } - }, - }, + } + } }, - new Drawable[] + }, + }, + new Drawable[] + { + new Container + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Y = 2, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] { - new Container + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"28242d").Darken(0.5f).Opacity(1f), + }, + new FillFlowContainer { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Y = 2, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Margin = new MarginPadding { Vertical = 20 }, + Padding = new MarginPadding { Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING }, Children = new Drawable[] { - new Box + ApplyButton = new CreateOrUpdateButton { - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"28242d").Darken(0.5f).Opacity(1f), + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Size = new Vector2(230, 55), + Enabled = { Value = false }, + Action = apply, }, - new FillFlowContainer + ErrorText = new OsuSpriteText { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 20), - Margin = new MarginPadding { Vertical = 20 }, - Padding = new MarginPadding { Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING }, - Children = new Drawable[] - { - ApplyButton = new CreateOrUpdateButton - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Size = new Vector2(230, 55), - Enabled = { Value = false }, - Action = apply, - }, - ErrorText = new OsuSpriteText - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Alpha = 0, - Depth = 1, - Colour = colours.RedDark - } - } + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Alpha = 0, + Depth = 1, + Colour = colours.RedDark } } } } } - }, + } } }, - loadingLayer = new LoadingLayer(dimContent) + loadingLayer = new LoadingLayer(true) }; TypePicker.Current.BindValueChanged(type => typeLabel.Text = type.NewValue?.Name ?? string.Empty, true); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 72539a2e3a..36dbb9e792 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -47,7 +47,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [BackgroundDependencyLoader] private void load() { - AddInternal(loadingLayer = new LoadingLayer(Carousel)); + AddInternal(loadingLayer = new LoadingLayer(true)); initialBeatmap = Beatmap.Value; initialRuleset = Ruleset.Value; initialMods = Mods.Value.ToList(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 4247e954bd..4bee502e2e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -62,7 +62,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer // todo: this should be implemented via a custom HUD implementation, and correctly masked to the main content area. LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(ScoreProcessor, userIds), HUDOverlay.Add); - HUDOverlay.Add(loadingDisplay = new LoadingLayer(DrawableRuleset) { Depth = float.MaxValue }); + HUDOverlay.Add(loadingDisplay = new LoadingLayer(true) { Depth = float.MaxValue }); if (Token == null) return; // Todo: Somehow handle token retrieval failure. diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs index 6b92526f35..01f9920609 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs @@ -64,243 +64,234 @@ namespace osu.Game.Screens.OnlinePlay.Playlists [BackgroundDependencyLoader] private void load(OsuColour colours) { - Container dimContent; - InternalChildren = new Drawable[] { - dimContent = new Container + new Box { RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + Colour = Color4Extensions.FromHex(@"28242d"), + }, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] { - new Box + new Dimension(GridSizeMode.Distributed), + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"28242d"), - }, - new GridContainer - { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] + new OsuScrollContainer { - new Dimension(GridSizeMode.Distributed), - new Dimension(GridSizeMode.AutoSize), - }, - Content = new[] - { - new Drawable[] + Padding = new MarginPadding { - new OsuScrollContainer - { - Padding = new MarginPadding - { - Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING, - Vertical = 10 - }, - RelativeSizeAxes = Axes.Both, - Children = new[] - { - new Container - { - Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING }, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new SectionContainer - { - Padding = new MarginPadding { Right = FIELD_PADDING / 2 }, - Children = new[] - { - new Section("Room name") - { - Child = NameField = new SettingsTextBox - { - RelativeSizeAxes = Axes.X, - TabbableContentContainer = this, - LengthLimit = 100 - }, - }, - new Section("Duration") - { - Child = DurationField = new DurationDropdown - { - RelativeSizeAxes = Axes.X, - Items = new[] - { - TimeSpan.FromMinutes(30), - TimeSpan.FromHours(1), - TimeSpan.FromHours(2), - TimeSpan.FromHours(4), - TimeSpan.FromHours(8), - TimeSpan.FromHours(12), - //TimeSpan.FromHours(16), - TimeSpan.FromHours(24), - TimeSpan.FromDays(3), - TimeSpan.FromDays(7) - } - } - }, - new Section("Room visibility") - { - Alpha = disabled_alpha, - Child = AvailabilityPicker = new RoomAvailabilityPicker - { - Enabled = { Value = false } - }, - }, - new Section("Game type") - { - Alpha = disabled_alpha, - Child = new FillFlowContainer - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, - Spacing = new Vector2(7), - Children = new Drawable[] - { - TypePicker = new GameTypePicker - { - RelativeSizeAxes = Axes.X, - Enabled = { Value = false } - }, - typeLabel = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 14), - Colour = colours.Yellow - }, - }, - }, - }, - new Section("Max participants") - { - Alpha = disabled_alpha, - Child = MaxParticipantsField = new SettingsNumberTextBox - { - RelativeSizeAxes = Axes.X, - TabbableContentContainer = this, - ReadOnly = true, - }, - }, - new Section("Password (optional)") - { - Alpha = disabled_alpha, - Child = new SettingsPasswordTextBox - { - RelativeSizeAxes = Axes.X, - TabbableContentContainer = this, - ReadOnly = true, - }, - }, - }, - }, - new SectionContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Padding = new MarginPadding { Left = FIELD_PADDING / 2 }, - Children = new[] - { - new Section("Playlist") - { - Child = new GridContainer - { - RelativeSizeAxes = Axes.X, - Height = 300, - Content = new[] - { - new Drawable[] - { - playlist = new DrawableRoomPlaylist(true, true) { RelativeSizeAxes = Axes.Both } - }, - new Drawable[] - { - playlistLength = new OsuSpriteText - { - Margin = new MarginPadding { Vertical = 5 }, - Colour = colours.Yellow, - Font = OsuFont.GetFont(size: 12), - } - }, - new Drawable[] - { - new PurpleTriangleButton - { - RelativeSizeAxes = Axes.X, - Height = 40, - Text = "Edit playlist", - Action = () => EditPlaylist?.Invoke() - } - } - }, - RowDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize), - } - } - }, - }, - }, - }, - } - }, - }, + Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING, + Vertical = 10 }, - new Drawable[] + RelativeSizeAxes = Axes.Both, + Children = new[] { new Container { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Y = 2, + Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Children = new Drawable[] { - new Box + new SectionContainer { - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"28242d").Darken(0.5f).Opacity(1f), - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 20), - Margin = new MarginPadding { Vertical = 20 }, - Padding = new MarginPadding { Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING }, - Children = new Drawable[] + Padding = new MarginPadding { Right = FIELD_PADDING / 2 }, + Children = new[] { - ApplyButton = new CreateRoomButton + new Section("Room name") { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Size = new Vector2(230, 55), - Enabled = { Value = false }, - Action = apply, + Child = NameField = new SettingsTextBox + { + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + LengthLimit = 100 + }, }, - ErrorText = new OsuSpriteText + new Section("Duration") { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Alpha = 0, - Depth = 1, - Colour = colours.RedDark - } - } + Child = DurationField = new DurationDropdown + { + RelativeSizeAxes = Axes.X, + Items = new[] + { + TimeSpan.FromMinutes(30), + TimeSpan.FromHours(1), + TimeSpan.FromHours(2), + TimeSpan.FromHours(4), + TimeSpan.FromHours(8), + TimeSpan.FromHours(12), + //TimeSpan.FromHours(16), + TimeSpan.FromHours(24), + TimeSpan.FromDays(3), + TimeSpan.FromDays(7) + } + } + }, + new Section("Room visibility") + { + Alpha = disabled_alpha, + Child = AvailabilityPicker = new RoomAvailabilityPicker + { + Enabled = { Value = false } + }, + }, + new Section("Game type") + { + Alpha = disabled_alpha, + Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Spacing = new Vector2(7), + Children = new Drawable[] + { + TypePicker = new GameTypePicker + { + RelativeSizeAxes = Axes.X, + Enabled = { Value = false } + }, + typeLabel = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 14), + Colour = colours.Yellow + }, + }, + }, + }, + new Section("Max participants") + { + Alpha = disabled_alpha, + Child = MaxParticipantsField = new SettingsNumberTextBox + { + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + ReadOnly = true, + }, + }, + new Section("Password (optional)") + { + Alpha = disabled_alpha, + Child = new SettingsPasswordTextBox + { + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + ReadOnly = true, + }, + }, + }, + }, + new SectionContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Padding = new MarginPadding { Left = FIELD_PADDING / 2 }, + Children = new[] + { + new Section("Playlist") + { + Child = new GridContainer + { + RelativeSizeAxes = Axes.X, + Height = 300, + Content = new[] + { + new Drawable[] + { + playlist = new DrawableRoomPlaylist(true, true) { RelativeSizeAxes = Axes.Both } + }, + new Drawable[] + { + playlistLength = new OsuSpriteText + { + Margin = new MarginPadding { Vertical = 5 }, + Colour = colours.Yellow, + Font = OsuFont.GetFont(size: 12), + } + }, + new Drawable[] + { + new PurpleTriangleButton + { + RelativeSizeAxes = Axes.X, + Height = 40, + Text = "Edit playlist", + Action = () => EditPlaylist?.Invoke() + } + } + }, + RowDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + } + } + }, + }, + }, + }, + } + }, + }, + }, + new Drawable[] + { + new Container + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Y = 2, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"28242d").Darken(0.5f).Opacity(1f), + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Margin = new MarginPadding { Vertical = 20 }, + Padding = new MarginPadding { Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING }, + Children = new Drawable[] + { + ApplyButton = new CreateRoomButton + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Size = new Vector2(230, 55), + Enabled = { Value = false }, + Action = apply, + }, + ErrorText = new OsuSpriteText + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Alpha = 0, + Depth = 1, + Colour = colours.RedDark } } } } } - }, + } } }, - loadingLayer = new LoadingLayer(dimContent) + loadingLayer = new LoadingLayer(true) }; TypePicker.Current.BindValueChanged(type => typeLabel.Text = type.NewValue?.Name ?? string.Empty, true); diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs index 5530b4beac..00176e9127 100644 --- a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -131,7 +131,7 @@ namespace osu.Game.Screens.Play Anchor = Anchor.Centre, FillMode = FillMode.Fill, }, - loading = new LoadingLayer(backgroundSprite) + loading = new LoadingLayer(true) } }, new OsuSpriteText diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 71f78c5c95..8a1c291fca 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -63,8 +63,6 @@ namespace osu.Game.Screens.Select public BeatmapDetails() { - Container content; - Children = new Drawable[] { new Box @@ -72,7 +70,7 @@ namespace osu.Game.Screens.Select RelativeSizeAxes = Axes.Both, Colour = Color4.Black.Opacity(0.5f), }, - content = new Container + new Container { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Horizontal = spacing }, @@ -159,7 +157,7 @@ namespace osu.Game.Screens.Select }, }, }, - loading = new LoadingLayer(content), + loading = new LoadingLayer(true), }; } From 0b1ee2e267f3daea22a437d445edf4336bd048f2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 17:42:19 +0900 Subject: [PATCH 059/107] Remove unused dispose logic --- osu.Game/Graphics/UserInterface/LoadingLayer.cs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index 6aca30328a..a4905156a9 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -3,7 +3,6 @@ using System; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osuTK; @@ -82,16 +81,5 @@ namespace osu.Game.Graphics.UserInterface MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 30, 100)); } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - if (State.Value == Visibility.Visible) - { - // ensure we don't leave the target in a bad state. - // dimTarget?.FadeColour(Color4.White, TRANSITION_DURATION, Easing.OutQuint); - } - } } } From 0639429a23bb706d84b56dea98b7f23d3f4563b3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 18:10:39 +0900 Subject: [PATCH 060/107] Fix test (and remove no longer valid test) --- .../UserInterface/TestSceneLoadingLayer.cs | 36 ++++++++----------- .../Graphics/UserInterface/LoadingLayer.cs | 8 ++--- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs index a694595115..d426723f0b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs @@ -1,11 +1,11 @@ // 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.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Utils; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osuTK; @@ -15,12 +15,10 @@ namespace osu.Game.Tests.Visual.UserInterface { public class TestSceneLoadingLayer : OsuTestScene { - private LoadingLayer overlay; + private TestLoadingLayer overlay; private Container content; - private Drawable dimContent => overlay.Children.OfType().First(); - [SetUp] public void SetUp() => Schedule(() => { @@ -53,7 +51,7 @@ namespace osu.Game.Tests.Visual.UserInterface new TriangleButton { Text = "puush me", Width = 200, Action = () => { } }, } }, - overlay = new LoadingLayer(true), + overlay = new TestLoadingLayer(true), } }, }; @@ -66,25 +64,11 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("show", () => overlay.Show()); - AddUntilStep("wait for content dim", () => dimContent.Colour != Color4.White); + AddUntilStep("wait for content dim", () => overlay.BackgroundDimLayer.Alpha > 0); AddStep("hide", () => overlay.Hide()); - AddUntilStep("wait for content restore", () => dimContent.Colour == Color4.White); - } - - [Test] - public void TestContentRestoreOnDispose() - { - AddAssert("not visible", () => !overlay.IsPresent); - - AddStep("show", () => overlay.Show()); - - AddUntilStep("wait for content dim", () => dimContent.Colour != Color4.White); - - AddStep("expire", () => overlay.Expire()); - - AddUntilStep("wait for content restore", () => dimContent.Colour == Color4.White); + AddUntilStep("wait for content restore", () => Precision.AlmostEquals(overlay.BackgroundDimLayer.Alpha, 0)); } [Test] @@ -100,5 +84,15 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("hide", () => overlay.Hide()); } + + private class TestLoadingLayer : LoadingLayer + { + public new Box BackgroundDimLayer => base.BackgroundDimLayer; + + public TestLoadingLayer(bool dimBackground = false, bool withBox = true) + : base(dimBackground, withBox) + { + } + } } } diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index a4905156a9..3e3fd32d65 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Graphics.UserInterface /// public class LoadingLayer : LoadingSpinner { - private readonly Box backgroundDimLayer; + protected Box BackgroundDimLayer { get; private set; } /// /// Construct a new loading spinner. @@ -34,7 +34,7 @@ namespace osu.Game.Graphics.UserInterface if (dimBackground) { - AddInternal(backgroundDimLayer = new Box + AddInternal(BackgroundDimLayer = new Box { Depth = float.MaxValue, Colour = Color4.Black, @@ -65,13 +65,13 @@ namespace osu.Game.Graphics.UserInterface protected override void PopIn() { - backgroundDimLayer?.FadeTo(0.5f, TRANSITION_DURATION * 2, Easing.OutQuint); + BackgroundDimLayer?.FadeTo(0.5f, TRANSITION_DURATION * 2, Easing.OutQuint); base.PopIn(); } protected override void PopOut() { - backgroundDimLayer?.FadeOut(TRANSITION_DURATION, Easing.OutQuint); + BackgroundDimLayer?.FadeOut(TRANSITION_DURATION, Easing.OutQuint); base.PopOut(); } From d0d2e41b28df281507e16d5de19f4ec0c5e8a8b7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 18:19:28 +0900 Subject: [PATCH 061/107] Fix display settings binding to configuration bindables in async load --- .../Settings/Sections/Graphics/LayoutSettings.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 3d3b543d70..e815e2f68b 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -133,6 +133,15 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics }, }; + scalingSettings.ForEach(s => bindPreviewEvent(s.Current)); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + windowModeDropdown.Current.ValueChanged += _ => updateResolutionDropdown(); + windowModes.BindCollectionChanged((sender, args) => { if (windowModes.Count > 1) @@ -141,8 +150,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics windowModeDropdown.Hide(); }, true); - windowModeDropdown.Current.ValueChanged += _ => updateResolutionDropdown(); - currentDisplay.BindValueChanged(display => Schedule(() => { resolutions.RemoveRange(1, resolutions.Count - 1); @@ -159,8 +166,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics updateResolutionDropdown(); }), true); - scalingSettings.ForEach(s => bindPreviewEvent(s.Current)); - scalingMode.BindValueChanged(mode => { scalingSettings.ClearTransforms(); From 83dbba3cbfb3a02297ae8bc801a11bf2028f3cb6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 18:41:45 +0900 Subject: [PATCH 062/107] Fix carousel beatmap set panels applying transforms to difficulties while they are loading --- .../Carousel/DrawableCarouselBeatmapSet.cs | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index b3c5d458d6..17fa66447d 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -40,6 +41,8 @@ namespace osu.Game.Screens.Select.Carousel private BeatmapSetInfo beatmapSet; + private Task beatmapsLoadTask; + [Resolved] private BeatmapManager manager { get; set; } @@ -85,7 +88,9 @@ namespace osu.Game.Screens.Select.Carousel base.UpdateItem(); Content.Clear(); + beatmapContainer = null; + beatmapsLoadTask = null; if (Item == null) return; @@ -122,11 +127,7 @@ namespace osu.Game.Screens.Select.Carousel MovementContainer.MoveToX(0, 500, Easing.OutExpo); - if (beatmapContainer != null) - { - foreach (var beatmap in beatmapContainer) - beatmap.MoveToY(0, 800, Easing.OutQuint); - } + updateBeatmapYPositions(); } protected override void Selected() @@ -163,7 +164,7 @@ namespace osu.Game.Screens.Select.Carousel ChildrenEnumerable = visibleBeatmaps.Select(c => c.CreateDrawableRepresentation()) }; - LoadComponentAsync(beatmapContainer, loaded => + beatmapsLoadTask = LoadComponentAsync(beatmapContainer, loaded => { // make sure the pooled target hasn't changed. if (beatmapContainer != loaded) @@ -173,16 +174,26 @@ namespace osu.Game.Screens.Select.Carousel updateBeatmapYPositions(); }); } + } - void updateBeatmapYPositions() + private void updateBeatmapYPositions() + { + if (beatmapsLoadTask == null || !beatmapsLoadTask.IsCompleted) + return; + + float yPos = DrawableCarouselBeatmap.CAROUSEL_BEATMAP_SPACING; + + bool isSelected = Item.State.Value == CarouselItemState.Selected; + + foreach (var panel in beatmapContainer.Children) { - float yPos = DrawableCarouselBeatmap.CAROUSEL_BEATMAP_SPACING; - - foreach (var panel in beatmapContainer.Children) + if (isSelected) { panel.MoveToY(yPos, 800, Easing.OutQuint); yPos += panel.Item.TotalHeight; } + else + panel.MoveToY(0, 800, Easing.OutQuint); } } From 4b539b01c1862bfb0a29ad69dc6b400f3719e99b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 5 Jan 2021 20:38:58 +0900 Subject: [PATCH 063/107] Match code between updateSelectedBeatmap/Ruleset --- osu.Game/Screens/Select/SongSelect.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index e3036c662b..7e217ca7a4 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -435,13 +435,15 @@ namespace osu.Game.Screens.Select return; beatmapNoDebounce = beatmap; - performUpdateSelected(); } private void updateSelectedRuleset(RulesetInfo ruleset) { - if (ruleset == null || ruleset.Equals(rulesetNoDebounce)) + if (ruleset == null && rulesetNoDebounce == null) + return; + + if (ruleset?.Equals(rulesetNoDebounce) == true) return; rulesetNoDebounce = ruleset; From 2b253f6d01426901994e95b03ead4233f7cb67dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 5 Jan 2021 22:39:59 +0100 Subject: [PATCH 064/107] Remove now-unused fields & locals --- osu.Game/Overlays/AccountCreation/ScreenEntry.cs | 4 +--- osu.Game/Screens/Play/BeatmapMetadataDisplay.cs | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs index 0d5538155a..bcb3d4b635 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs @@ -48,11 +48,9 @@ namespace osu.Game.Overlays.AccountCreation [BackgroundDependencyLoader] private void load(OsuColour colours) { - FillFlowContainer mainContent; - InternalChildren = new Drawable[] { - mainContent = new FillFlowContainer + new FillFlowContainer { RelativeSizeAxes = Axes.Both, Direction = FillDirection.Vertical, diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs index 00176e9127..b53141e8fb 100644 --- a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -53,7 +53,6 @@ namespace osu.Game.Screens.Play private readonly Bindable> mods; private readonly Drawable facade; private LoadingSpinner loading; - private Sprite backgroundSprite; public IBindable> Mods => mods; @@ -123,7 +122,7 @@ namespace osu.Game.Screens.Play Masking = true, Children = new Drawable[] { - backgroundSprite = new Sprite + new Sprite { RelativeSizeAxes = Axes.Both, Texture = beatmap?.Background, From ac1d6d444430296d2ab08ac3f5e89f5a965655ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 5 Jan 2021 22:40:16 +0100 Subject: [PATCH 065/107] Make auto-property get-only --- osu.Game/Graphics/UserInterface/LoadingLayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index 3e3fd32d65..d86ea9e4ea 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Graphics.UserInterface /// public class LoadingLayer : LoadingSpinner { - protected Box BackgroundDimLayer { get; private set; } + protected Box BackgroundDimLayer { get; } /// /// Construct a new loading spinner. From 0880e76da8d58d02ffe4ad95c173d9373e3d50b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 5 Jan 2021 22:47:57 +0100 Subject: [PATCH 066/107] Mark background dim layer as possibly-null --- osu.Game/Graphics/UserInterface/LoadingLayer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index d86ea9e4ea..47ba5fce4d 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using JetBrains.Annotations; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; @@ -17,6 +18,7 @@ namespace osu.Game.Graphics.UserInterface /// public class LoadingLayer : LoadingSpinner { + [CanBeNull] protected Box BackgroundDimLayer { get; } /// From 15dd7a87a62d73d0ba6e85fea034f1d7cb9656c1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jan 2021 15:19:12 +0900 Subject: [PATCH 067/107] Move gameplay preview event binding to LoadComplete --- .../Settings/Sections/Graphics/LayoutSettings.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index e815e2f68b..7acbf038d8 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -132,14 +132,14 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics } }, }; - - scalingSettings.ForEach(s => bindPreviewEvent(s.Current)); } protected override void LoadComplete() { base.LoadComplete(); + scalingSettings.ForEach(s => bindPreviewEvent(s.Current)); + windowModeDropdown.Current.ValueChanged += _ => updateResolutionDropdown(); windowModes.BindCollectionChanged((sender, args) => @@ -186,11 +186,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics } } - /// - /// Create a delayed bindable which only updates when a condition is met. - /// - /// The config bindable. - /// A bindable which will propagate updates with a delay. private void bindPreviewEvent(Bindable bindable) { bindable.ValueChanged += _ => From 11a0c637bc07812e01125df31251791cf9a24694 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jan 2021 15:25:53 +0900 Subject: [PATCH 068/107] Mark background properties as nullable --- osu.Game/Screens/OsuScreen.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index c97c0aef2b..d1cdb9f1de 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -119,8 +120,10 @@ namespace osu.Game.Screens /// /// The background created and owned by this screen. May be null if the background didn't change. /// + [CanBeNull] private BackgroundScreen ownedBackground; + [CanBeNull] private BackgroundScreen background; [Resolved(canBeNull: true)] From e9d4e4d1d5bb5c6df13474c867c81b4d516cd61d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jan 2021 15:26:13 +0900 Subject: [PATCH 069/107] Add xmldoc and throw a local exception on null background --- osu.Game/Screens/BackgroundScreen.cs | 4 ++++ osu.Game/Screens/OsuScreen.cs | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/BackgroundScreen.cs b/osu.Game/Screens/BackgroundScreen.cs index ea220c2f82..c81362eebe 100644 --- a/osu.Game/Screens/BackgroundScreen.cs +++ b/osu.Game/Screens/BackgroundScreen.cs @@ -34,6 +34,10 @@ namespace osu.Game.Screens return false; } + /// + /// Apply arbitrary changes to this background in a thread safe manner. + /// + /// The operation to perform. public void ApplyToBackground(Action action) => Schedule(() => action.Invoke(this)); protected override void Update() diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index d1cdb9f1de..11467db6c8 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -115,8 +115,6 @@ namespace osu.Game.Screens Mods = screenDependencies.Mods; } - public void ApplyToBackground(Action action) => background.ApplyToBackground(action); - /// /// The background created and owned by this screen. May be null if the background didn't change. /// @@ -148,6 +146,18 @@ namespace osu.Game.Screens Activity.Value ??= InitialActivity; } + /// + /// Apply arbitrary changes to the current background screen in a thread safe manner. + /// + /// The operation to perform. + public void ApplyToBackground(Action action) + { + if (background == null) + throw new InvalidOperationException("Attempted to apply to background before screen is pushed"); + + background.ApplyToBackground(action); + } + public override void OnResuming(IScreen last) { if (PlayResumeSound) From 550ef3f13307f3d8592a0bc1ecd103f67af046e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jan 2021 15:28:01 +0900 Subject: [PATCH 070/107] Aggressively dispose ownedBackground if it was not used, because we can --- osu.Game/Screens/OsuScreen.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 11467db6c8..fb26739a44 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -185,6 +185,7 @@ namespace osu.Game.Screens if (background != ownedBackground) { // background may have not been replaced, at which point we don't want to track the background lifetime. + ownedBackground?.Dispose(); ownedBackground = null; } From 07cff7038728545a5ce399c3b727b1d03c68813c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jan 2021 18:19:03 +0900 Subject: [PATCH 071/107] Add specific messaging for when there's no background stack available --- osu.Game/Screens/OsuScreen.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index fb26739a44..e1a29946f4 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -125,6 +125,7 @@ namespace osu.Game.Screens private BackgroundScreen background; [Resolved(canBeNull: true)] + [CanBeNull] private BackgroundScreenStack backgroundStack { get; set; } [Resolved(canBeNull: true)] @@ -152,8 +153,11 @@ namespace osu.Game.Screens /// The operation to perform. public void ApplyToBackground(Action action) { + if (backgroundStack == null) + throw new InvalidOperationException("Attempted to apply to background without a background stack being available."); + if (background == null) - throw new InvalidOperationException("Attempted to apply to background before screen is pushed"); + throw new InvalidOperationException("Attempted to apply to background before screen is pushed."); background.ApplyToBackground(action); } From 99701a6d9b22e2fbc4864556a14f9f44311b5236 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jan 2021 21:06:33 +0900 Subject: [PATCH 072/107] Add null check on beatmapContainer for safety --- osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 17fa66447d..c0415384c8 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -178,6 +178,9 @@ namespace osu.Game.Screens.Select.Carousel private void updateBeatmapYPositions() { + if (beatmapContainer == null) + return; + if (beatmapsLoadTask == null || !beatmapsLoadTask.IsCompleted) return; From 43b9fde45731fdbd5da77f119eaedc5e0afa0f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 6 Jan 2021 13:15:15 +0100 Subject: [PATCH 073/107] Add some nullability annotations for good measure --- osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index c0415384c8..d7e901b71e 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -37,10 +38,12 @@ namespace osu.Game.Screens.Select.Carousel public IEnumerable DrawableBeatmaps => beatmapContainer?.Children ?? Enumerable.Empty(); + [CanBeNull] private Container beatmapContainer; private BeatmapSetInfo beatmapSet; + [CanBeNull] private Task beatmapsLoadTask; [Resolved] From 32accc8eab227aebcc40cc026897324119c0e589 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jan 2021 22:56:10 +0900 Subject: [PATCH 074/107] Remove "osu!direct" button --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 2 +- osu.Game/Screens/Menu/ButtonSystem.cs | 1 - osu.Game/Screens/Menu/Disclaimer.cs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 1270df5374..fa3f70735a 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -112,7 +112,7 @@ namespace osu.Game.Input.Bindings [Description("Toggle settings")] ToggleSettings, - [Description("Toggle osu!direct")] + [Description("Toggle beatmap listing")] ToggleDirect, [Description("Increase volume")] diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index fd4d74dc6b..0c47ef3b1e 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -130,7 +130,6 @@ namespace osu.Game.Screens.Menu buttonsTopLevel.Add(new Button(@"play", @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P)); buttonsTopLevel.Add(new Button(@"osu!editor", @"button-generic-select", OsuIcon.EditCircle, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E)); - buttonsTopLevel.Add(new Button(@"osu!direct", @"button-direct-select", OsuIcon.ChevronDownCircle, new Color4(165, 204, 0, 255), () => OnBeatmapListing?.Invoke(), 0, Key.D)); if (host.CanExit) buttonsTopLevel.Add(new Button(@"exit", string.Empty, OsuIcon.CrossCircle, new Color4(238, 51, 153, 255), () => OnExit?.Invoke(), 0, Key.Q)); diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 46fddabb26..72eb9c7c0c 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -201,7 +201,7 @@ namespace osu.Game.Screens.Menu "New features are coming online every update. Make sure to stay up-to-date!", "If you find the UI too large or small, try adjusting UI scale in settings!", "Try adjusting the \"Screen Scaling\" mode to change your gameplay or UI area, even in fullscreen!", - "For now, osu!direct is available to all users on lazer. You can access it anywhere using Ctrl-D!", + "For now, what used to be \"osu!direct\" is available to all users on lazer. You can access it anywhere using Ctrl-D!", "Seeking in replays is available by dragging on the difficulty bar at the bottom of the screen!", "Multithreading support means that even with low \"FPS\" your input and judgements will be accurate!", "Try scrolling down in the mod select panel to find a bunch of new fun mods!", From 59025e9d50a6866b71f2571919460c94a155222c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jan 2021 23:09:58 +0900 Subject: [PATCH 075/107] Remove related events --- osu.Game/Screens/Menu/ButtonSystem.cs | 1 - osu.Game/Screens/Menu/MainMenu.cs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 0c47ef3b1e..8417858878 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -39,7 +39,6 @@ namespace osu.Game.Screens.Menu public Action OnEdit; public Action OnExit; - public Action OnBeatmapListing; public Action OnSolo; public Action OnSettings; public Action OnMultiplayer; diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 97fd58318b..ef45a656fa 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -71,7 +71,7 @@ namespace osu.Game.Screens.Menu private SongTicker songTicker; [BackgroundDependencyLoader(true)] - private void load(BeatmapListingOverlay beatmapListing, SettingsOverlay settings, RankingsOverlay rankings, OsuConfigManager config, SessionStatics statics) + private void load(SettingsOverlay settings, OsuConfigManager config, SessionStatics statics) { holdDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); loginDisplayed = statics.GetBindable(Static.LoginOverlayDisplayed); @@ -137,7 +137,6 @@ namespace osu.Game.Screens.Menu }; buttons.OnSettings = () => settings?.ToggleVisibility(); - buttons.OnBeatmapListing = () => beatmapListing?.ToggleVisibility(); LoadComponentAsync(background = new BackgroundScreenDefault()); preloadSongSelect(); From 283c69a68f3f4a1a29ea6d676fdaabdad67000aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jan 2021 23:12:56 +0900 Subject: [PATCH 076/107] Update enum name in line with changes --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 4 ++-- osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index fa3f70735a..b8c2fa201f 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -34,7 +34,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings), new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar), new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings), - new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleDirect), + new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleBeatmapListing), new KeyBinding(new[] { InputKey.Control, InputKey.N }, GlobalAction.ToggleNotifications), new KeyBinding(InputKey.Escape, GlobalAction.Back), @@ -113,7 +113,7 @@ namespace osu.Game.Input.Bindings ToggleSettings, [Description("Toggle beatmap listing")] - ToggleDirect, + ToggleBeatmapListing, [Description("Increase volume")] IncreaseVolume, diff --git a/osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs b/osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs index c495d673ce..bfe36a6a0f 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Toolbar public ToolbarBeatmapListingButton() { - Hotkey = GlobalAction.ToggleDirect; + Hotkey = GlobalAction.ToggleBeatmapListing; } [BackgroundDependencyLoader(true)] From cf3043fc08fa723dde4f6c4a7ea4a060a4e72c50 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jan 2021 23:20:26 +0900 Subject: [PATCH 077/107] Only show "development build" footer on debug releases --- osu.Desktop/Overlays/VersionManager.cs | 39 ++++++++++++++++---------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs index 8c759f8487..59d0f9635d 100644 --- a/osu.Desktop/Overlays/VersionManager.cs +++ b/osu.Desktop/Overlays/VersionManager.cs @@ -26,9 +26,11 @@ namespace osu.Desktop.Overlays Alpha = 0; + FillFlowContainer mainFill; + Children = new Drawable[] { - new FillFlowContainer + mainFill = new FillFlowContainer { AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, @@ -55,23 +57,30 @@ namespace osu.Desktop.Overlays }, } }, - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Font = OsuFont.Numeric.With(size: 12), - Colour = colours.Yellow, - Text = @"Development Build" - }, - new Sprite - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Texture = textures.Get(@"Menu/dev-build-footer"), - }, } } }; + + if (DebugUtils.IsDebugBuild) + { + mainFill.AddRange(new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Font = OsuFont.Numeric.With(size: 12), + Colour = colours.Yellow, + Text = @"Development Build" + }, + new Sprite + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Texture = textures.Get(@"Menu/dev-build-footer"), + }, + }); + } } protected override void PopIn() From cfbfb8d58bd2768bf83be25c2e2da1cd26a1d4ce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jan 2021 23:21:46 +0900 Subject: [PATCH 078/107] Revert "Remove related events" This reverts commit 59025e9d50a6866b71f2571919460c94a155222c. --- osu.Game/Screens/Menu/ButtonSystem.cs | 1 + osu.Game/Screens/Menu/MainMenu.cs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 8417858878..0c47ef3b1e 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -39,6 +39,7 @@ namespace osu.Game.Screens.Menu public Action OnEdit; public Action OnExit; + public Action OnBeatmapListing; public Action OnSolo; public Action OnSettings; public Action OnMultiplayer; diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index ef45a656fa..97fd58318b 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -71,7 +71,7 @@ namespace osu.Game.Screens.Menu private SongTicker songTicker; [BackgroundDependencyLoader(true)] - private void load(SettingsOverlay settings, OsuConfigManager config, SessionStatics statics) + private void load(BeatmapListingOverlay beatmapListing, SettingsOverlay settings, RankingsOverlay rankings, OsuConfigManager config, SessionStatics statics) { holdDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); loginDisplayed = statics.GetBindable(Static.LoginOverlayDisplayed); @@ -137,6 +137,7 @@ namespace osu.Game.Screens.Menu }; buttons.OnSettings = () => settings?.ToggleVisibility(); + buttons.OnBeatmapListing = () => beatmapListing?.ToggleVisibility(); LoadComponentAsync(background = new BackgroundScreenDefault()); preloadSongSelect(); From 35be7ec0e1477c9d904538c4dd726e50b6f2e827 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jan 2021 23:28:14 +0900 Subject: [PATCH 079/107] Add back button but rename to "browse" --- osu.Game/Screens/Menu/ButtonSystem.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 0c47ef3b1e..f400b2114b 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -129,7 +129,8 @@ namespace osu.Game.Screens.Menu buttonsPlay.ForEach(b => b.VisibleState = ButtonSystemState.Play); buttonsTopLevel.Add(new Button(@"play", @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P)); - buttonsTopLevel.Add(new Button(@"osu!editor", @"button-generic-select", OsuIcon.EditCircle, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E)); + buttonsTopLevel.Add(new Button(@"edit", @"button-generic-select", OsuIcon.EditCircle, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E)); + buttonsTopLevel.Add(new Button(@"browse", @"button-direct-select", OsuIcon.ChevronDownCircle, new Color4(165, 204, 0, 255), () => OnBeatmapListing?.Invoke(), 0, Key.D)); if (host.CanExit) buttonsTopLevel.Add(new Button(@"exit", string.Empty, OsuIcon.CrossCircle, new Color4(238, 51, 153, 255), () => OnExit?.Invoke(), 0, Key.Q)); From d056e6575e1cd711890ffee0592b173b6eccb960 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Jan 2021 23:30:54 +0900 Subject: [PATCH 080/107] Use IsDeployedBuild instead of IsDebugBuild for footer display conditional --- osu.Desktop/Overlays/VersionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs index 59d0f9635d..e4a3451651 100644 --- a/osu.Desktop/Overlays/VersionManager.cs +++ b/osu.Desktop/Overlays/VersionManager.cs @@ -61,7 +61,7 @@ namespace osu.Desktop.Overlays } }; - if (DebugUtils.IsDebugBuild) + if (!game.IsDeployedBuild) { mainFill.AddRange(new Drawable[] { From a8530fde9d3dea6f4a0064e8371c2debbcdd2471 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Jan 2021 00:05:12 +0900 Subject: [PATCH 081/107] Tidy up variables and spacing --- osu.Desktop/DiscordRichPresence.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 172db324cb..63b12fb84b 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -31,7 +31,8 @@ namespace osu.Desktop private readonly IBindable status = new Bindable(); private readonly IBindable activity = new Bindable(); - private readonly Bindable mode = new Bindable(); + + private readonly Bindable privacyMode = new Bindable(); private readonly RichPresence presence = new RichPresence { @@ -53,7 +54,8 @@ namespace osu.Desktop client.OnError += (_, e) => Logger.Log($"An error occurred with Discord RPC Client: {e.Code} {e.Message}", LoggingTarget.Network); - config.BindWith(OsuSetting.DiscordRichPresence, mode); + config.BindWith(OsuSetting.DiscordRichPresence, privacyMode); + (user = provider.LocalUser.GetBoundCopy()).BindValueChanged(u => { status.UnbindBindings(); @@ -66,7 +68,7 @@ namespace osu.Desktop ruleset.BindValueChanged(_ => updateStatus()); status.BindValueChanged(_ => updateStatus()); activity.BindValueChanged(_ => updateStatus()); - mode.BindValueChanged(_ => updateStatus()); + privacyMode.BindValueChanged(_ => updateStatus()); client.Initialize(); } @@ -82,7 +84,7 @@ namespace osu.Desktop if (!client.IsInitialized) return; - if (status.Value is UserStatusOffline || mode.Value == DiscordRichPresenceMode.Off) + if (status.Value is UserStatusOffline || privacyMode.Value == DiscordRichPresenceMode.Off) { client.ClearPresence(); return; @@ -100,7 +102,7 @@ namespace osu.Desktop } // update user information - if (mode.Value == DiscordRichPresenceMode.Limited) + if (privacyMode.Value == DiscordRichPresenceMode.Limited) presence.Assets.LargeImageText = string.Empty; else presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.Ranks.Global > 0 ? $" (rank #{user.Value.Statistics.Ranks.Global:N0})" : string.Empty); @@ -144,7 +146,7 @@ namespace osu.Desktop return edit.Beatmap.ToString(); case UserActivity.InLobby lobby: - return mode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value; + return privacyMode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value; } return string.Empty; From fb057857e707349ead9bf7aa539d5e61c3a42cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 6 Jan 2021 17:40:29 +0100 Subject: [PATCH 082/107] Update references to current year --- Directory.Build.props | 4 ++-- LICENCE | 2 +- osu.Desktop/osu.nuspec | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 9ec442aafa..049db816a8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -40,7 +40,7 @@ https://github.com/ppy/osu Automated release. ppy Pty Ltd - Copyright (c) 2020 ppy Pty Ltd + Copyright (c) 2021 ppy Pty Ltd osu game - \ No newline at end of file + diff --git a/LICENCE b/LICENCE index 2435c23545..b5962ad3b2 100644 --- a/LICENCE +++ b/LICENCE @@ -1,4 +1,4 @@ -Copyright (c) 2020 ppy Pty Ltd . +Copyright (c) 2021 ppy Pty Ltd . Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/osu.Desktop/osu.nuspec b/osu.Desktop/osu.nuspec index 2fc6009183..fa182f8e70 100644 --- a/osu.Desktop/osu.nuspec +++ b/osu.Desktop/osu.nuspec @@ -11,7 +11,7 @@ false A free-to-win rhythm game. Rhythm is just a *click* away! testing - Copyright (c) 2020 ppy Pty Ltd + Copyright (c) 2021 ppy Pty Ltd en-AU From 09742998cdeaeaae7fda4c77309e45cd14b69b18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 6 Jan 2021 17:40:46 +0100 Subject: [PATCH 083/107] Fix mistaken obsoletion notice It was added in c9f38f7bb6af116fa7ec813ceb3f100dcad30adb, which specified 2021 in another place (and was committed in October of 2020 anyway). Update the year so that it doesn't get culled prematurely. --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index da6da0ea97..e5eaf5db88 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -750,7 +750,7 @@ namespace osu.Game.Rulesets.Objects.Drawables if (Result.Type != originalType) { Logger.Log($"{GetType().ReadableName()} applied an invalid hit result ({originalType}) when {nameof(HitResult.IgnoreMiss)} or {nameof(HitResult.IgnoreHit)} is expected.\n" - + $"This has been automatically adjusted to {Result.Type}, and support will be removed from 2020-03-28 onwards.", level: LogLevel.Important); + + $"This has been automatically adjusted to {Result.Type}, and support will be removed from 2021-03-28 onwards.", level: LogLevel.Important); } } From 539785e422accca0ccd360b4b02969ccf7a70a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 6 Jan 2021 17:46:44 +0100 Subject: [PATCH 084/107] Remove obsoleted IHasCurve --- .../Rulesets/Objects/Legacy/ConvertSlider.cs | 5 +- osu.Game/Rulesets/Objects/Types/IHasCurve.cs | 55 ------------------- 2 files changed, 1 insertion(+), 59 deletions(-) delete mode 100644 osu.Game/Rulesets/Objects/Types/IHasCurve.cs diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index 36b421586e..df569b91c1 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -10,10 +10,7 @@ using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Rulesets.Objects.Legacy { - internal abstract class ConvertSlider : ConvertHitObject, IHasPathWithRepeats, IHasLegacyLastTickOffset, -#pragma warning disable 618 - IHasCurve -#pragma warning restore 618 + internal abstract class ConvertSlider : ConvertHitObject, IHasPathWithRepeats, IHasLegacyLastTickOffset { /// /// Scoring distance with a speed-adjusted beat length of 1 second. diff --git a/osu.Game/Rulesets/Objects/Types/IHasCurve.cs b/osu.Game/Rulesets/Objects/Types/IHasCurve.cs deleted file mode 100644 index 26f50ffa31..0000000000 --- a/osu.Game/Rulesets/Objects/Types/IHasCurve.cs +++ /dev/null @@ -1,55 +0,0 @@ -// 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 osuTK; - -namespace osu.Game.Rulesets.Objects.Types -{ - [Obsolete("Use IHasPathWithRepeats instead.")] // can be removed 20201126 - public interface IHasCurve : IHasDistance, IHasRepeats - { - /// - /// The curve. - /// - SliderPath Path { get; } - } - -#pragma warning disable 618 - [Obsolete("Use IHasPathWithRepeats instead.")] // can be removed 20201126 - public static class HasCurveExtensions - { - /// - /// Computes the position on the curve relative to how much of the has been completed. - /// - /// The curve. - /// [0, 1] where 0 is the start time of the and 1 is the end time of the . - /// The position on the curve. - public static Vector2 CurvePositionAt(this IHasCurve obj, double progress) - => obj.Path.PositionAt(obj.ProgressAt(progress)); - - /// - /// Computes the progress along the curve relative to how much of the has been completed. - /// - /// The curve. - /// [0, 1] where 0 is the start time of the and 1 is the end time of the . - /// [0, 1] where 0 is the beginning of the curve and 1 is the end of the curve. - public static double ProgressAt(this IHasCurve obj, double progress) - { - double p = progress * obj.SpanCount() % 1; - if (obj.SpanAt(progress) % 2 == 1) - p = 1 - p; - return p; - } - - /// - /// Determines which span of the curve the progress point is on. - /// - /// The curve. - /// [0, 1] where 0 is the beginning of the curve and 1 is the end of the curve. - /// [0, SpanCount) where 0 is the first run. - public static int SpanAt(this IHasCurve obj, double progress) - => (int)(progress * obj.SpanCount()); - } -#pragma warning restore 618 -} From 9cc63e8dce8e65feba008ffb02195928f8ea8a46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 6 Jan 2021 17:48:46 +0100 Subject: [PATCH 085/107] Remove obsoleted IHasEndTime --- .../Rulesets/Objects/Types/IHasDuration.cs | 16 +++--------- .../Rulesets/Objects/Types/IHasEndTime.cs | 26 ------------------- 2 files changed, 3 insertions(+), 39 deletions(-) delete mode 100644 osu.Game/Rulesets/Objects/Types/IHasEndTime.cs diff --git a/osu.Game/Rulesets/Objects/Types/IHasDuration.cs b/osu.Game/Rulesets/Objects/Types/IHasDuration.cs index b558273650..ca734da5ad 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasDuration.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasDuration.cs @@ -6,26 +6,16 @@ namespace osu.Game.Rulesets.Objects.Types /// /// A HitObject that ends at a different time than its start time. /// -#pragma warning disable 618 - public interface IHasDuration : IHasEndTime -#pragma warning restore 618 + public interface IHasDuration { - double IHasEndTime.EndTime - { - get => EndTime; - set => Duration = (Duration - EndTime) + value; - } - - double IHasEndTime.Duration => Duration; - /// /// The time at which the HitObject ends. /// - new double EndTime { get; } + double EndTime { get; } /// /// The duration of the HitObject. /// - new double Duration { get; set; } + double Duration { get; set; } } } diff --git a/osu.Game/Rulesets/Objects/Types/IHasEndTime.cs b/osu.Game/Rulesets/Objects/Types/IHasEndTime.cs deleted file mode 100644 index c3769c5909..0000000000 --- a/osu.Game/Rulesets/Objects/Types/IHasEndTime.cs +++ /dev/null @@ -1,26 +0,0 @@ -// 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 Newtonsoft.Json; - -namespace osu.Game.Rulesets.Objects.Types -{ - /// - /// A HitObject that ends at a different time than its start time. - /// - [Obsolete("Use IHasDuration instead.")] // can be removed 20201126 - public interface IHasEndTime - { - /// - /// The time at which the HitObject ends. - /// - [JsonIgnore] - double EndTime { get; set; } - - /// - /// The duration of the HitObject. - /// - double Duration { get; } - } -} From 68352782db59f2db881ba5f443bf352cf8a9c03b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 6 Jan 2021 18:11:47 +0100 Subject: [PATCH 086/107] Change .StartsWith() to .Equals() In line with planned-but-delayed breaking change. --- osu.Game/Rulesets/RulesetStore.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index d422bca087..deabea57ef 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -100,9 +100,7 @@ namespace osu.Game.Rulesets foreach (var r in instances.Where(r => !(r is ILegacyRuleset))) { - // todo: StartsWith can be changed to Equals on 2020-11-08 - // This is to give users enough time to have their database use new abbreviated info). - if (existingRulesets.FirstOrDefault(ri => ri.InstantiationInfo.StartsWith(r.RulesetInfo.InstantiationInfo, StringComparison.Ordinal)) == null) + if (existingRulesets.FirstOrDefault(ri => ri.InstantiationInfo.Equals(r.RulesetInfo.InstantiationInfo, StringComparison.Ordinal)) == null) context.RulesetInfo.Add(r.RulesetInfo); } From 4998aaaa987b75de4d017f09067f44dd05caeec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 6 Jan 2021 18:13:30 +0100 Subject: [PATCH 087/107] Remove outdated warning disable Does not trigger any more on Rider 2020.3.2. --- osu.Game/Screens/Select/BeatmapCarousel.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 36f8fbedb3..7ba6e400bf 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -936,7 +936,6 @@ namespace osu.Game.Screens.Select Masking = false; } - // ReSharper disable once OptionalParameterHierarchyMismatch 2020.3 EAP4 bug. (https://youtrack.jetbrains.com/issue/RSRP-481535?p=RIDER-51910) protected override void OnUserScroll(float value, bool animated = true, double? distanceDecay = default) { UserScrolling = true; From 9984c80c87c428316d622523f805a4d7a4a4f196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 6 Jan 2021 20:40:47 +0100 Subject: [PATCH 088/107] Make useless existing test actually fail --- .../Mods/TestSceneOsuModDifficultyAdjust.cs | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs index 49c1fe8540..db8546c71b 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs @@ -1,13 +1,17 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Framework.Utils; +using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Tests.Mods @@ -18,8 +22,23 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods public void TestNoAdjustment() => CreateModTest(new ModTestData { Mod = new OsuModDifficultyAdjust(), + Beatmap = new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + BaseDifficulty = new BeatmapDifficulty + { + CircleSize = 8 + } + }, + HitObjects = new List + { + new HitCircle { StartTime = 1000 }, + new HitCircle { StartTime = 2000 } + } + }, Autoplay = true, - PassCondition = checkSomeHit + PassCondition = () => checkSomeHit() && checkObjectsScale(0.29f) }); [Test] From 303cc62ee7c8eec32cb9cd4522202bb3cbdf512d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 6 Jan 2021 21:57:54 +0100 Subject: [PATCH 089/107] Transfer flags indicating if settings were changed --- .../Mods/CatchModDifficultyAdjust.cs | 4 ++-- .../Mods/OsuModDifficultyAdjust.cs | 4 ++-- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 18 +++++++++++++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs index acdd0a420c..438d17dbc5 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs @@ -59,8 +59,8 @@ namespace osu.Game.Rulesets.Catch.Mods { base.ApplySettings(difficulty); - difficulty.CircleSize = CircleSize.Value; - difficulty.ApproachRate = ApproachRate.Value; + ApplySetting(CircleSize, cs => difficulty.CircleSize = cs); + ApplySetting(ApproachRate, ar => difficulty.ApproachRate = ar); } } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs index ff995e38ce..a638234dbd 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs @@ -59,8 +59,8 @@ namespace osu.Game.Rulesets.Osu.Mods { base.ApplySettings(difficulty); - difficulty.CircleSize = CircleSize.Value; - difficulty.ApproachRate = ApproachRate.Value; + ApplySetting(CircleSize, cs => difficulty.CircleSize = cs); + ApplySetting(ApproachRate, ar => difficulty.ApproachRate = ar); } } } diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index 72a4bb297f..a531e885db 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -116,18 +116,30 @@ namespace osu.Game.Rulesets.Mods internal override void CopyAdjustedSetting(IBindable target, object source) { - userChangedSettings[target] = true; + // if the value is non-bindable, it's presumably coming from an external source (like the API) - therefore presume it is not default. + // if the value is bindable, defer to the source's IsDefault to be able to tell. + userChangedSettings[target] = !(source is IBindable bindableSource) || !bindableSource.IsDefault; base.CopyAdjustedSetting(target, source); } + /// + /// Applies a setting from a configuration bindable using , if it has been changed by the user. + /// + protected void ApplySetting(BindableNumber setting, Action applyFunc) + where T : struct, IComparable, IConvertible, IEquatable + { + if (userChangedSettings.TryGetValue(setting, out bool userChangedSetting) && userChangedSetting) + applyFunc.Invoke(setting.Value); + } + /// /// Apply all custom settings to the provided beatmap. /// /// The beatmap to have settings applied. protected virtual void ApplySettings(BeatmapDifficulty difficulty) { - difficulty.DrainRate = DrainRate.Value; - difficulty.OverallDifficulty = OverallDifficulty.Value; + ApplySetting(DrainRate, dr => difficulty.DrainRate = dr); + ApplySetting(OverallDifficulty, od => difficulty.OverallDifficulty = od); } } } From 6620eadec3f1c7fe5fac7b98d52683d1a05aba4a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Jan 2021 18:47:03 +0900 Subject: [PATCH 090/107] Reduce default hover sound debounce interval --- osu.Game/Graphics/UserInterface/HoverSounds.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index 40899e7e95..22d59e70f7 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -24,7 +24,7 @@ namespace osu.Game.Graphics.UserInterface /// /// Length of debounce for hover sound playback, in milliseconds. Default is 50ms. /// - public double HoverDebounceTime { get; } = 50; + public double HoverDebounceTime { get; } = 20; protected readonly HoverSampleSet SampleSet; From 8f52a83b297d277bf07bbda9e9e2efd2d0684092 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Jan 2021 18:47:20 +0900 Subject: [PATCH 091/107] Share hover sound debounce across all instances via SessionStatics --- osu.Game/Configuration/SessionStatics.cs | 9 ++++++ .../Graphics/UserInterface/HoverSounds.cs | 29 +++++++++++-------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index 03bc434aac..f28ee707b9 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -1,7 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; namespace osu.Game.Configuration { @@ -14,6 +16,7 @@ namespace osu.Game.Configuration { Set(Static.LoginOverlayDisplayed, false); Set(Static.MutedAudioNotificationShownOnce, false); + Set(Static.LastHoverSoundPlaybackTime, 0.0); Set(Static.SeasonalBackgrounds, null); } } @@ -28,5 +31,11 @@ namespace osu.Game.Configuration /// Value under this lookup can be null if there are no backgrounds available (or API is not reachable). /// SeasonalBackgrounds, + + /// + /// The last playback time in milliseconds of a hover sample (from ). + /// Used to debounce hover sounds game-wide to avoid volume saturation, especially in scrolling views with many UI controls like . + /// + LastHoverSoundPlaybackTime } } diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index 22d59e70f7..efd55c892c 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -5,11 +5,12 @@ using System.ComponentModel; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; -using osu.Framework.Threading; +using osu.Game.Configuration; namespace osu.Game.Graphics.UserInterface { @@ -28,31 +29,35 @@ namespace osu.Game.Graphics.UserInterface protected readonly HoverSampleSet SampleSet; + private Bindable lastPlaybackTime; + public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal) { SampleSet = sampleSet; RelativeSizeAxes = Axes.Both; } - private ScheduledDelegate playDelegate; + [BackgroundDependencyLoader] + private void load(AudioManager audio, SessionStatics statics) + { + lastPlaybackTime = statics.GetBindable(Static.LastHoverSoundPlaybackTime); + + sampleHover = audio.Samples.Get($@"UI/generic-hover{SampleSet.GetDescription()}"); + } protected override bool OnHover(HoverEvent e) { - playDelegate?.Cancel(); + bool requiresDebounce = HoverDebounceTime <= 0; + bool enoughTimePassedSinceLastPlayback = lastPlaybackTime.Value == 0 || Time.Current - lastPlaybackTime.Value > HoverDebounceTime; - if (HoverDebounceTime <= 0) + if (!requiresDebounce || enoughTimePassedSinceLastPlayback) + { sampleHover?.Play(); - else - playDelegate = Scheduler.AddDelayed(() => sampleHover?.Play(), HoverDebounceTime); + lastPlaybackTime.Value = Time.Current; + } return base.OnHover(e); } - - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - sampleHover = audio.Samples.Get($@"UI/generic-hover{SampleSet.GetDescription()}"); - } } public enum HoverSampleSet From 69ac22dd7fdd477943ce041cb42072de318c15e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Jan 2021 19:06:10 +0900 Subject: [PATCH 092/107] Fix incorrectly copy pasted xmldoc --- osu.Game/Beatmaps/ControlPoints/ControlPoint.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs index 090675473d..e8dc623ddb 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs @@ -30,8 +30,7 @@ namespace osu.Game.Beatmaps.ControlPoints public abstract bool IsRedundant(ControlPoint existing); /// - /// Create a copy of this room without online information. - /// Should be used to create a local copy of a room for submitting in the future. + /// Create an unbound copy of this control point. /// public ControlPoint CreateCopy() { From 00dc98e3ab0fef1b568969a5086d9ede48ec8003 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Jan 2021 19:06:52 +0900 Subject: [PATCH 093/107] Make legacy control point's BpmMultiplier setter private again --- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index a06ad35b89..069a25b83d 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -164,7 +164,7 @@ namespace osu.Game.Beatmaps.Formats /// Legacy BPM multiplier that introduces floating-point errors for rulesets that depend on it. /// DO NOT USE THIS UNLESS 100% SURE. /// - public float BpmMultiplier { get; set; } + public float BpmMultiplier { get; private set; } public LegacyDifficultyControlPoint(double beatLength) : this() From 42643fbaf69e321f8ae1d52e70ddbc17ac985a42 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Jan 2021 19:10:19 +0900 Subject: [PATCH 094/107] Use already resolved EditorBeatmap rather than resolving a second time locally --- osu.Game/Screens/Edit/Setup/DifficultySection.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/DifficultySection.cs b/osu.Game/Screens/Edit/Setup/DifficultySection.cs index f180d7e63e..36fb0191b0 100644 --- a/osu.Game/Screens/Edit/Setup/DifficultySection.cs +++ b/osu.Game/Screens/Edit/Setup/DifficultySection.cs @@ -13,9 +13,6 @@ namespace osu.Game.Screens.Edit.Setup { internal class DifficultySection : SetupSection { - [Resolved] - private EditorBeatmap editorBeatmap { get; set; } - private LabelledSliderBar circleSizeSlider; private LabelledSliderBar healthDrainSlider; private LabelledSliderBar approachRateSlider; @@ -93,7 +90,7 @@ namespace osu.Game.Screens.Edit.Setup Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate = approachRateSlider.Current.Value; Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty = overallDifficultySlider.Current.Value; - editorBeatmap.UpdateAllHitObjects(); + Beatmap.UpdateAllHitObjects(); } } } From 77b55212a3c9870a0e42cd90e77e3ae4a552e273 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Jan 2021 19:11:51 +0900 Subject: [PATCH 095/107] Change access of beatmap to use working for consistency in file --- osu.Game/Screens/Edit/Setup/ResourcesSection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index b3bceceea3..010d7c2797 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -73,7 +73,7 @@ namespace osu.Game.Screens.Edit.Setup audioTrackTextBox = new FileChooserLabelledTextBox { Label = "Audio Track", - Current = { Value = Beatmap.Metadata.AudioFile ?? "Click to select a track" }, + Current = { Value = working.Value.Metadata.AudioFile ?? "Click to select a track" }, Target = audioTrackFileChooserContainer, TabbableContentContainer = this }, From 3c3e860dbc34d37855b79786a1abb754af1667e8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Jan 2021 23:52:04 +0900 Subject: [PATCH 096/107] Move ControlPointInfo copying to base Beatmap.Clone method (and remove setter) --- osu.Game/Beatmaps/Beatmap.cs | 10 +++++++++- osu.Game/Beatmaps/IBeatmap.cs | 2 +- osu.Game/Beatmaps/WorkingBeatmap.cs | 2 -- osu.Game/Screens/Edit/EditorBeatmap.cs | 6 +----- osu.Game/Screens/Play/GameplayBeatmap.cs | 6 +----- 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 5435e86dfd..be2006e67a 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -50,7 +50,15 @@ namespace osu.Game.Beatmaps IBeatmap IBeatmap.Clone() => Clone(); - public Beatmap Clone() => (Beatmap)MemberwiseClone(); + public Beatmap Clone() + { + var clone = (Beatmap)MemberwiseClone(); + + clone.ControlPointInfo = ControlPointInfo.CreateCopy(); + // todo: deep clone other elements as required. + + return clone; + } } public class Beatmap : Beatmap diff --git a/osu.Game/Beatmaps/IBeatmap.cs b/osu.Game/Beatmaps/IBeatmap.cs index 7dd85e1232..8f27e0b0e9 100644 --- a/osu.Game/Beatmaps/IBeatmap.cs +++ b/osu.Game/Beatmaps/IBeatmap.cs @@ -24,7 +24,7 @@ namespace osu.Game.Beatmaps /// /// The control points in this beatmap. /// - ControlPointInfo ControlPointInfo { get; set; } + ControlPointInfo ControlPointInfo { get; } /// /// The breaks in this beatmap. diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index d25adca92b..30382c444f 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -111,8 +111,6 @@ namespace osu.Game.Beatmaps // Convert IBeatmap converted = converter.Convert(cancellationSource.Token); - converted.ControlPointInfo = converted.ControlPointInfo.CreateCopy(); - // Apply conversion mods to the result foreach (var mod in mods.OfType()) { diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index a54a95f59d..165d2ba278 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -74,11 +74,7 @@ namespace osu.Game.Screens.Edit public BeatmapMetadata Metadata => PlayableBeatmap.Metadata; - public ControlPointInfo ControlPointInfo - { - get => PlayableBeatmap.ControlPointInfo; - set => PlayableBeatmap.ControlPointInfo = value; - } + public ControlPointInfo ControlPointInfo => PlayableBeatmap.ControlPointInfo; public List Breaks => PlayableBeatmap.Breaks; diff --git a/osu.Game/Screens/Play/GameplayBeatmap.cs b/osu.Game/Screens/Play/GameplayBeatmap.cs index 565595656f..64894544f4 100644 --- a/osu.Game/Screens/Play/GameplayBeatmap.cs +++ b/osu.Game/Screens/Play/GameplayBeatmap.cs @@ -29,11 +29,7 @@ namespace osu.Game.Screens.Play public BeatmapMetadata Metadata => PlayableBeatmap.Metadata; - public ControlPointInfo ControlPointInfo - { - get => PlayableBeatmap.ControlPointInfo; - set => PlayableBeatmap.ControlPointInfo = value; - } + public ControlPointInfo ControlPointInfo => PlayableBeatmap.ControlPointInfo; public List Breaks => PlayableBeatmap.Breaks; From 11801d61c1b3701356b253c9feb3a23eaa0d1dcf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jan 2021 14:05:22 +0900 Subject: [PATCH 097/107] Use nullable doubule to better represent initial playback case --- osu.Game/Configuration/SessionStatics.cs | 2 +- osu.Game/Graphics/UserInterface/HoverSounds.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index f28ee707b9..382eab751b 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -16,7 +16,7 @@ namespace osu.Game.Configuration { Set(Static.LoginOverlayDisplayed, false); Set(Static.MutedAudioNotificationShownOnce, false); - Set(Static.LastHoverSoundPlaybackTime, 0.0); + Set(Static.LastHoverSoundPlaybackTime, (double?)0.0); Set(Static.SeasonalBackgrounds, null); } } diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index efd55c892c..29b4bf5704 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -29,7 +29,7 @@ namespace osu.Game.Graphics.UserInterface protected readonly HoverSampleSet SampleSet; - private Bindable lastPlaybackTime; + private Bindable lastPlaybackTime; public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal) { @@ -40,7 +40,7 @@ namespace osu.Game.Graphics.UserInterface [BackgroundDependencyLoader] private void load(AudioManager audio, SessionStatics statics) { - lastPlaybackTime = statics.GetBindable(Static.LastHoverSoundPlaybackTime); + lastPlaybackTime = statics.GetBindable(Static.LastHoverSoundPlaybackTime); sampleHover = audio.Samples.Get($@"UI/generic-hover{SampleSet.GetDescription()}"); } @@ -48,7 +48,7 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnHover(HoverEvent e) { bool requiresDebounce = HoverDebounceTime <= 0; - bool enoughTimePassedSinceLastPlayback = lastPlaybackTime.Value == 0 || Time.Current - lastPlaybackTime.Value > HoverDebounceTime; + bool enoughTimePassedSinceLastPlayback = !lastPlaybackTime.Value.HasValue || Time.Current - lastPlaybackTime.Value >= HoverDebounceTime; if (!requiresDebounce || enoughTimePassedSinceLastPlayback) { From e156bcdcae175f46a5c78fb9eb7c4ed5d0dbf5d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jan 2021 14:05:34 +0900 Subject: [PATCH 098/107] Remove unnecessary (and broken) requiresDebounce check --- osu.Game/Graphics/UserInterface/HoverSounds.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index 29b4bf5704..4d30d61ff0 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -47,10 +47,9 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnHover(HoverEvent e) { - bool requiresDebounce = HoverDebounceTime <= 0; bool enoughTimePassedSinceLastPlayback = !lastPlaybackTime.Value.HasValue || Time.Current - lastPlaybackTime.Value >= HoverDebounceTime; - if (!requiresDebounce || enoughTimePassedSinceLastPlayback) + if (enoughTimePassedSinceLastPlayback) { sampleHover?.Play(); lastPlaybackTime.Value = Time.Current; From c208800150494eceb06472e45310eecc8859b29b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jan 2021 14:17:14 +0900 Subject: [PATCH 099/107] Fix auto selection scenario regressing due to scheduling too much --- osu.Game/Overlays/Mods/ModButton.cs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 51c8bcf9a9..b58e70cae6 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -52,9 +52,10 @@ namespace osu.Game.Overlays.Mods if (newIndex == selectedIndex) return false; int direction = newIndex < selectedIndex ? -1 : 1; + bool beforeSelected = Selected; - Mod modBefore = SelectedMod ?? Mods[0]; + Mod previousSelection = SelectedMod ?? Mods[0]; if (newIndex >= Mods.Length) newIndex = -1; @@ -64,25 +65,26 @@ namespace osu.Game.Overlays.Mods if (newIndex >= 0 && !Mods[newIndex].HasImplementation) return false; + selectedIndex = newIndex; + + Mod newSelection = SelectedMod ?? Mods[0]; + Schedule(() => { - selectedIndex = newIndex; - Mod modAfter = SelectedMod ?? Mods[0]; - if (beforeSelected != Selected) { iconsContainer.RotateTo(Selected ? 5f : 0f, 300, Easing.OutElastic); iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, Easing.OutElastic); } - if (modBefore != modAfter) + if (previousSelection != newSelection) { const float rotate_angle = 16; foregroundIcon.RotateTo(rotate_angle * direction, mod_switch_duration, mod_switch_easing); backgroundIcon.RotateTo(-rotate_angle * direction, mod_switch_duration, mod_switch_easing); - backgroundIcon.Mod = modAfter; + backgroundIcon.Mod = newSelection; using (BeginDelayedSequence(mod_switch_duration, true)) { @@ -94,15 +96,15 @@ namespace osu.Game.Overlays.Mods .RotateTo(rotate_angle * direction) .RotateTo(0f, mod_switch_duration, mod_switch_easing); - Schedule(() => displayMod(modAfter)); + Schedule(() => displayMod(newSelection)); } } foregroundIcon.Selected.Value = Selected; - - SelectionChanged?.Invoke(SelectedMod); }); + SelectionChanged?.Invoke(newSelection); + return true; } From a6766e64de95cdd23dfa17e029275be3e7ea3c15 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jan 2021 17:08:01 +0900 Subject: [PATCH 100/107] Add custom handling of Point serialization to fix startup crashes of tournament client SixLabors moved their data types around in a recent update (see https://github.com/ppy/osu-framework/pull/4025) and it was deemed that we should prefer `System.Drawing` primitives where possible. This was applied to the tournament client via https://github.com/ppy/osu/pull/11072 without correct consideration given to the fact that we serialize these types. `System.Drawing.Point` serializes into a comma separated string, which seems to be less correct than what we had, so I've switched back to the old format for the time being. We can reasses this in the future; the main goal here is to restore usability to the tournament client. Closes #11443. --- osu.Game.Tournament/JsonPointConverter.cs | 67 +++++++++++++++++++++++ osu.Game.Tournament/TournamentGameBase.cs | 7 ++- 2 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 osu.Game.Tournament/JsonPointConverter.cs diff --git a/osu.Game.Tournament/JsonPointConverter.cs b/osu.Game.Tournament/JsonPointConverter.cs new file mode 100644 index 0000000000..57b91958d8 --- /dev/null +++ b/osu.Game.Tournament/JsonPointConverter.cs @@ -0,0 +1,67 @@ +// 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.Diagnostics; +using System.Drawing; +using Newtonsoft.Json; + +namespace osu.Game.Tournament +{ + /// + /// We made a change from using SixLabors.ImageSharp.Point to System.Drawing.Point at some stage. + /// This handles converting to a standardised format on json serialize/deserialize operations. + /// + internal class JsonPointConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, Point value, JsonSerializer serializer) + { + // use the format of LaborSharp's Point since it is nicer. + serializer.Serialize(writer, new SixLabors.ImageSharp.Point(value.X, value.Y)); + } + + public override Point ReadJson(JsonReader reader, Type objectType, Point existingValue, bool hasExistingValue, JsonSerializer serializer) + { + if (reader.TokenType != JsonToken.StartObject) + { + // if there's no object present then this is using string representation (System.Drawing.Point serializes to "x,y") + string str = (string)reader.Value; + + Debug.Assert(str != null); + + var split = str.Split(','); + + return new Point(int.Parse(split[0]), int.Parse(split[1])); + } + + var point = new Point(); + + while (reader.Read()) + { + if (reader.TokenType == JsonToken.EndObject) break; + + if (reader.TokenType == JsonToken.PropertyName) + { + var name = reader.Value?.ToString(); + int? val = reader.ReadAsInt32(); + + if (val == null) + continue; + + switch (name) + { + case "X": + point.X = val.Value; + break; + + case "Y": + point.Y = val.Value; + break; + } + } + } + + return point; + } + } +} diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index dbda6aa023..bc36f27e5b 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -8,12 +8,12 @@ using Newtonsoft.Json; using osu.Framework.Allocation; using osu.Framework.Graphics.Textures; using osu.Framework.Input; -using osu.Framework.Platform; using osu.Framework.IO.Stores; +using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Online.API.Requests; -using osu.Game.Tournament.IPC; using osu.Game.Tournament.IO; +using osu.Game.Tournament.IPC; using osu.Game.Tournament.Models; using osu.Game.Users; using osuTK.Input; @@ -60,7 +60,7 @@ namespace osu.Game.Tournament { using (Stream stream = storage.GetStream(bracket_filename, FileAccess.Read, FileMode.Open)) using (var sr = new StreamReader(stream)) - ladder = JsonConvert.DeserializeObject(sr.ReadToEnd()); + ladder = JsonConvert.DeserializeObject(sr.ReadToEnd(), new JsonPointConverter()); } ladder ??= new LadderInfo(); @@ -251,6 +251,7 @@ namespace osu.Game.Tournament Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore, + Converters = new JsonConverter[] { new JsonPointConverter() } })); } } From 924f91ed9b91445d4cba0bd819441a0959021faa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 8 Jan 2021 15:56:35 +0100 Subject: [PATCH 101/107] Fix song select test doing the completely wrong thing --- .../Visual/SongSelect/TestSceneAdvancedStats.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs index 3d3517ada4..40b2f66d74 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs @@ -11,6 +11,7 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.Select.Details; using osuTK.Graphics; @@ -141,16 +142,12 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("select changed Difficulty Adjust mod", () => { var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance(); - var difficultyAdjustMod = ruleset.GetAllMods().OfType().Single(); + var difficultyAdjustMod = ruleset.GetAllMods().OfType().Single(); var originalDifficulty = advancedStats.Beatmap.BaseDifficulty; - var adjustedDifficulty = new BeatmapDifficulty - { - CircleSize = originalDifficulty.CircleSize, - DrainRate = originalDifficulty.DrainRate - 0.5f, - OverallDifficulty = originalDifficulty.OverallDifficulty, - ApproachRate = originalDifficulty.ApproachRate + 2.2f, - }; - difficultyAdjustMod.ReadFromDifficulty(adjustedDifficulty); + + difficultyAdjustMod.ReadFromDifficulty(originalDifficulty); + difficultyAdjustMod.DrainRate.Value = originalDifficulty.DrainRate - 0.5f; + difficultyAdjustMod.ApproachRate.Value = originalDifficulty.ApproachRate + 2.2f; SelectedMods.Value = new[] { difficultyAdjustMod }; }); From 9182f5dafb224baf6e6534edc7c727026231a1b2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 9 Jan 2021 00:38:38 +0900 Subject: [PATCH 102/107] Switch to using an anonymous type for serialisation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game.Tournament/JsonPointConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tournament/JsonPointConverter.cs b/osu.Game.Tournament/JsonPointConverter.cs index 57b91958d8..7ad972f3e7 100644 --- a/osu.Game.Tournament/JsonPointConverter.cs +++ b/osu.Game.Tournament/JsonPointConverter.cs @@ -17,7 +17,7 @@ namespace osu.Game.Tournament public override void WriteJson(JsonWriter writer, Point value, JsonSerializer serializer) { // use the format of LaborSharp's Point since it is nicer. - serializer.Serialize(writer, new SixLabors.ImageSharp.Point(value.X, value.Y)); + serializer.Serialize(writer, new { value.X, value.Y }); } public override Point ReadJson(JsonReader reader, Type objectType, Point existingValue, bool hasExistingValue, JsonSerializer serializer) From 82725b59c030d27abd3159ee3397a4b77e834b1a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 9 Jan 2021 00:56:54 +0900 Subject: [PATCH 103/107] Use PointConverter --- osu.Game.Tournament/JsonPointConverter.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Tournament/JsonPointConverter.cs b/osu.Game.Tournament/JsonPointConverter.cs index 7ad972f3e7..9c82f8ac06 100644 --- a/osu.Game.Tournament/JsonPointConverter.cs +++ b/osu.Game.Tournament/JsonPointConverter.cs @@ -29,9 +29,7 @@ namespace osu.Game.Tournament Debug.Assert(str != null); - var split = str.Split(','); - - return new Point(int.Parse(split[0]), int.Parse(split[1])); + return new PointConverter().ConvertFromString(str) as Point? ?? new Point(); } var point = new Point(); From 0cf5be3ef432a718d23bab4fc951f04182375ebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 8 Jan 2021 17:02:57 +0100 Subject: [PATCH 104/107] Fix selection change event being invoked with wrong mod --- osu.Game/Overlays/Mods/ModButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index b58e70cae6..ab8efdabcc 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -103,7 +103,7 @@ namespace osu.Game.Overlays.Mods foregroundIcon.Selected.Value = Selected; }); - SelectionChanged?.Invoke(newSelection); + SelectionChanged?.Invoke(SelectedMod); return true; } From 8feaf3fb6ad084885f8b69b997caea7faf92bb50 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 9 Jan 2021 01:24:18 +0900 Subject: [PATCH 105/107] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 611f0d05f4..492c88c7e4 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6c220a5c21..f28a55e016 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -26,7 +26,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 5445adb3fb..93be3645ee 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -88,7 +88,7 @@ - + From d507a08951b33618a00fcce8e3c61ab289ee9172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 8 Jan 2021 18:16:03 +0100 Subject: [PATCH 106/107] Start with null last hover playback time --- osu.Game/Configuration/SessionStatics.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index 382eab751b..fd401119ff 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -16,7 +16,7 @@ namespace osu.Game.Configuration { Set(Static.LoginOverlayDisplayed, false); Set(Static.MutedAudioNotificationShownOnce, false); - Set(Static.LastHoverSoundPlaybackTime, (double?)0.0); + Set(Static.LastHoverSoundPlaybackTime, (double?)null); Set(Static.SeasonalBackgrounds, null); } } From 49c6abcb5c1a8eaa3baa8d0c3b94b2799b3e82cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 8 Jan 2021 18:25:51 +0100 Subject: [PATCH 107/107] Remove mention of default value in xmldoc Just bound to get outdated with every change anyway. Look at the actual default value declaration to see what the default is. --- osu.Game/Graphics/UserInterface/HoverSounds.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index 4d30d61ff0..a1d06711db 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -23,7 +23,7 @@ namespace osu.Game.Graphics.UserInterface private SampleChannel sampleHover; /// - /// Length of debounce for hover sound playback, in milliseconds. Default is 50ms. + /// Length of debounce for hover sound playback, in milliseconds. /// public double HoverDebounceTime { get; } = 20;