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 01/37] 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 02/37] 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 d2301068b6c2a04961986570075ef5075c2cf168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 28 Dec 2020 16:35:33 +0100 Subject: [PATCH 03/37] Fix changelog header staying dimmed after build show --- .../Overlays/Changelog/ChangelogUpdateStreamControl.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs index 6bbff045b5..aa36a5c8fd 100644 --- a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs @@ -7,12 +7,11 @@ namespace osu.Game.Overlays.Changelog { public class ChangelogUpdateStreamControl : OverlayStreamControl { - protected override OverlayStreamItem CreateStreamItem(APIUpdateStream value) => new ChangelogUpdateStreamItem(value); - - protected override void LoadComplete() + public ChangelogUpdateStreamControl() { - // suppress base logic of immediately selecting first item if one exists - // (we always want to start with no stream selected). + SelectFirstTabByDefault = false; } + + protected override OverlayStreamItem CreateStreamItem(APIUpdateStream value) => new ChangelogUpdateStreamItem(value); } } 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 04/37] 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 45c578b85780f81051035dee3094efeef995fff9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 Dec 2020 15:10:08 +0900 Subject: [PATCH 05/37] Remove selection polling from multiplayer Looks like this was just copy-paste without any thought into whether it should exist. It really shouldn't exist. This is a thing for the playlists system because the *whole system* there relies on polling the web API to get updated information. In the case of mutliplayer, we hand off all communications to the realtime server at the point of joining the rooms. The argument that this was there to do faster polling on the selection isn't valid since the polling times were the same for both cases. Closes #11348. --- .../OnlinePlay/Multiplayer/Multiplayer.cs | 5 +--- .../Multiplayer/MultiplayerRoomManager.cs | 28 +------------------ 2 files changed, 2 insertions(+), 31 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs index 76f5c74433..310617a0bc 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs @@ -33,7 +33,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer if (!this.IsCurrentScreen()) { multiplayerRoomManager.TimeBetweenListingPolls.Value = 0; - multiplayerRoomManager.TimeBetweenSelectionPolls.Value = 0; } else { @@ -41,18 +40,16 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { case LoungeSubScreen _: multiplayerRoomManager.TimeBetweenListingPolls.Value = isIdle ? 120000 : 15000; - multiplayerRoomManager.TimeBetweenSelectionPolls.Value = isIdle ? 120000 : 15000; break; // Don't poll inside the match or anywhere else. default: multiplayerRoomManager.TimeBetweenListingPolls.Value = 0; - multiplayerRoomManager.TimeBetweenSelectionPolls.Value = 0; break; } } - Logger.Log($"Polling adjusted (listing: {multiplayerRoomManager.TimeBetweenListingPolls.Value}, selection: {multiplayerRoomManager.TimeBetweenSelectionPolls.Value})"); + Logger.Log($"Polling adjusted (listing: {multiplayerRoomManager.TimeBetweenListingPolls.Value})"); } protected override Room CreateNewRoom() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs index 3cb263298f..5c327266a3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private StatefulMultiplayerClient multiplayerClient { get; set; } public readonly Bindable TimeBetweenListingPolls = new Bindable(); - public readonly Bindable TimeBetweenSelectionPolls = new Bindable(); + private readonly IBindable isConnected = new Bindable(); private readonly Bindable allowPolling = new Bindable(); @@ -119,11 +119,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer TimeBetweenPolls = { BindTarget = TimeBetweenListingPolls }, AllowPolling = { BindTarget = allowPolling } }, - new MultiplayerSelectionPollingComponent - { - TimeBetweenPolls = { BindTarget = TimeBetweenSelectionPolls }, - AllowPolling = { BindTarget = allowPolling } - } }; private class MultiplayerListingPollingComponent : ListingPollingComponent @@ -146,26 +141,5 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override Task Poll() => !AllowPolling.Value ? Task.CompletedTask : base.Poll(); } - - private class MultiplayerSelectionPollingComponent : SelectionPollingComponent - { - public readonly IBindable AllowPolling = new Bindable(); - - protected override void LoadComplete() - { - base.LoadComplete(); - - AllowPolling.BindValueChanged(allowPolling => - { - if (!allowPolling.NewValue) - return; - - if (IsLoaded) - PollImmediately(); - }); - } - - protected override Task Poll() => !AllowPolling.Value ? Task.CompletedTask : base.Poll(); - } } } From 2cb84c5111b9e244d98492e4b7fe43e3ef553492 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 Dec 2020 15:19:52 +0900 Subject: [PATCH 06/37] Fix error message being shown to user on multiplayer disconnection when not in room --- osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs index 39d119b2a4..dc80488d39 100644 --- a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs @@ -84,7 +84,7 @@ namespace osu.Game.Online.Multiplayer IsConnected.BindValueChanged(connected => { // clean up local room state on server disconnect. - if (!connected.NewValue) + if (!connected.NewValue && Room != null) { Logger.Log("Connection to multiplayer server was lost.", LoggingTarget.Runtime, LogLevel.Important); LeaveRoom().CatchUnobservedExceptions(); From 03b78d1c4b2de871626068a454b163448f216e09 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 Dec 2020 15:27:22 +0900 Subject: [PATCH 07/37] Handle SocketExceptions and HttpRequestExceptions more silently These can occur when a network connection is completely unavailable (ie. host resolution failures are occurring). Currently these would appear as important errors which spammed the notification overlay every retry forever, while no network connection is available. I also took this opportunity to remove a lot of `bool` passing which was no longer in use (previously the fail count / retry process was different to what we have today). --- osu.Game/Online/API/APIAccess.cs | 46 ++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 133ba22406..2aaea22155 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Net; using System.Net.Http; +using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json.Linq; @@ -293,8 +294,21 @@ namespace osu.Game.Online.API failureCount = 0; return true; } + catch (HttpRequestException re) + { + log.Add($"{nameof(HttpRequestException)} while performing request {req}: {re.Message}"); + handleFailure(); + return false; + } + catch (SocketException se) + { + log.Add($"{nameof(SocketException)} while performing request {req}: {se.Message}"); + handleFailure(); + return false; + } catch (WebException we) { + log.Add($"{nameof(WebException)} while performing request {req}: {we.Message}"); handleWebException(we); return false; } @@ -312,7 +326,7 @@ namespace osu.Game.Online.API /// public IBindable State => state; - private bool handleWebException(WebException we) + private void handleWebException(WebException we) { HttpStatusCode statusCode = (we.Response as HttpWebResponse)?.StatusCode ?? (we.Status == WebExceptionStatus.UnknownError ? HttpStatusCode.NotAcceptable : HttpStatusCode.RequestTimeout); @@ -330,26 +344,24 @@ namespace osu.Game.Online.API { case HttpStatusCode.Unauthorized: Logout(); - return true; + break; case HttpStatusCode.RequestTimeout: - failureCount++; - log.Add($@"API failure count is now {failureCount}"); - - if (failureCount < 3) - // we might try again at an api level. - return false; - - if (State.Value == APIState.Online) - { - state.Value = APIState.Failing; - flushQueue(); - } - - return true; + handleFailure(); + break; } + } - return true; + private void handleFailure() + { + failureCount++; + log.Add($@"API failure count is now {failureCount}"); + + if (failureCount >= 3 && State.Value == APIState.Online) + { + state.Value = APIState.Failing; + flushQueue(); + } } public bool IsLoggedIn => localUser.Value.Id > 1; From 4d04e0dee7c73eaab08ecb4a47cee7822221972a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 Dec 2020 16:25:51 +0900 Subject: [PATCH 08/37] Disallow entering the playlists/multiplayer screens if API is failing --- osu.Game/Screens/Menu/ButtonSystem.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 474cbde192..65a16f2fcb 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -156,7 +156,7 @@ namespace osu.Game.Screens.Menu private void onMultiplayer() { - if (!api.IsLoggedIn) + if (!api.IsLoggedIn || api.State.Value != APIState.Online) { notifications?.Post(new SimpleNotification { @@ -177,11 +177,11 @@ namespace osu.Game.Screens.Menu private void onPlaylists() { - if (!api.IsLoggedIn) + if (!api.IsLoggedIn || api.State.Value != APIState.Online) { notifications?.Post(new SimpleNotification { - Text = "You gotta be logged in to multi 'yo!", + Text = "You gotta be logged in to view playlists 'yo!", Icon = FontAwesome.Solid.Globe, Activated = () => { From 906a9b79b5b62a6d25c304549a6308451127079b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 Dec 2020 16:47:36 +0900 Subject: [PATCH 09/37] Show an error when forcefully exiting online play due to API failure --- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 4074dd1573..75612516a9 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics.Containers; @@ -165,7 +166,10 @@ namespace osu.Game.Screens.OnlinePlay private void onlineStateChanged(ValueChangedEvent state) => Schedule(() => { if (state.NewValue != APIState.Online) + { + Logger.Log("API connection was lost, can't continue with online play", LoggingTarget.Network, LogLevel.Important); Schedule(forcefullyExit); + } }); protected override void LoadComplete() From 6bbd0ecfac9fc77ae680064ec61b29f2409380e8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 Dec 2020 17:39:00 +0900 Subject: [PATCH 10/37] Remove unused lock object --- osu.Game/Online/Multiplayer/MultiplayerRoom.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs index 2134e50d72..99f0eae2b3 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs @@ -42,8 +42,6 @@ namespace osu.Game.Online.Multiplayer /// public MultiplayerRoomUser? Host { get; set; } - private object writeLock = new object(); - [JsonConstructor] public MultiplayerRoom(in long roomId) { From 5d2319923324b48fa749474c11686db3f82b41d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 29 Dec 2020 10:56:29 +0100 Subject: [PATCH 11/37] Trim redundant IsLoggedIn checks --- osu.Game/Screens/Menu/ButtonSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 65a16f2fcb..3ac9bb6c24 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -156,7 +156,7 @@ namespace osu.Game.Screens.Menu private void onMultiplayer() { - if (!api.IsLoggedIn || api.State.Value != APIState.Online) + if (api.State.Value != APIState.Online) { notifications?.Post(new SimpleNotification { @@ -177,7 +177,7 @@ namespace osu.Game.Screens.Menu private void onPlaylists() { - if (!api.IsLoggedIn || api.State.Value != APIState.Online) + if (api.State.Value != APIState.Online) { notifications?.Post(new SimpleNotification { From 361d215ab4def9965856c4e998a6373c504bfc0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 29 Dec 2020 10:56:59 +0100 Subject: [PATCH 12/37] Reword notification messages to match new logic --- osu.Game/Screens/Menu/ButtonSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 3ac9bb6c24..fd4d74dc6b 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -160,7 +160,7 @@ namespace osu.Game.Screens.Menu { notifications?.Post(new SimpleNotification { - Text = "You gotta be logged in to multi 'yo!", + Text = "You gotta be online to multi 'yo!", Icon = FontAwesome.Solid.Globe, Activated = () => { @@ -181,7 +181,7 @@ namespace osu.Game.Screens.Menu { notifications?.Post(new SimpleNotification { - Text = "You gotta be logged in to view playlists 'yo!", + Text = "You gotta be online to view playlists 'yo!", Icon = FontAwesome.Solid.Globe, Activated = () => { From f2163a471a83eee0c0d41486f256a9b607113e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 29 Dec 2020 11:53:42 +0100 Subject: [PATCH 13/37] Trim missed reference to deleted member --- .../Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs index 7a3845cbf3..80d1acd145 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs @@ -143,7 +143,6 @@ namespace osu.Game.Tests.Visual.Multiplayer RoomManager = { TimeBetweenListingPolls = { Value = 1 }, - TimeBetweenSelectionPolls = { Value = 1 } } }; From 3552034ffe0044dc5edff9195e6e609504336c84 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Dec 2020 00:55:27 +0900 Subject: [PATCH 14/37] 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 cd2ce58c55..611f0d05f4 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 3e1b56c29c..93aa2bc701 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 85ba0590ea..5445adb3fb 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -88,7 +88,7 @@ - + From 497d644a19f04ad19d990bbe7a042f1a556265f1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Dec 2020 20:24:50 +0900 Subject: [PATCH 15/37] Move thread safety / locking logic from MultiplayerRoom --- .../Online/Multiplayer/MultiplayerRoom.cs | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs index 99f0eae2b3..12fcf25ace 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs @@ -5,9 +5,7 @@ using System; using System.Collections.Generic; -using System.Threading; using Newtonsoft.Json; -using osu.Framework.Allocation; namespace osu.Game.Online.Multiplayer { @@ -48,27 +46,6 @@ namespace osu.Game.Online.Multiplayer RoomID = roomId; } - private object updateLock = new object(); - - private ManualResetEventSlim freeForWrite = new ManualResetEventSlim(true); - - /// - /// Request a lock on this room to perform a thread-safe update. - /// - public IDisposable LockForUpdate() - { - // ReSharper disable once InconsistentlySynchronizedField - freeForWrite.Wait(); - - lock (updateLock) - { - freeForWrite.Wait(); - freeForWrite.Reset(); - - return new ValueInvokeOnDisposal(this, r => freeForWrite.Set()); - } - } - public override string ToString() => $"RoomID:{RoomID} Host:{Host?.UserID} Users:{Users.Count} State:{State} Settings: [{Settings}]"; } } 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 16/37] 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 f9196ae9767653c75dc2d9ff6a0a273671a4466c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 31 Dec 2020 16:36:20 +0900 Subject: [PATCH 17/37] Fix PerformFromMenuRunner failing if CurrentScreen is null --- osu.Game/PerformFromMenuRunner.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/PerformFromMenuRunner.cs b/osu.Game/PerformFromMenuRunner.cs index e2d4fc6051..9222a64023 100644 --- a/osu.Game/PerformFromMenuRunner.cs +++ b/osu.Game/PerformFromMenuRunner.cs @@ -73,13 +73,16 @@ namespace osu.Game // find closest valid target IScreen current = getCurrentScreen(); + if (current == null) + return; + // a dialog may be blocking the execution for now. if (checkForDialog(current)) return; game?.CloseAllOverlays(false); // we may already be at the target screen type. - if (validScreens.Contains(getCurrentScreen().GetType()) && !beatmap.Disabled) + if (validScreens.Contains(current.GetType()) && !beatmap.Disabled) { complete(); return; From 00c6703c51df3cd05788d1c41d84b64d88de1ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 31 Dec 2020 10:27:42 +0100 Subject: [PATCH 18/37] Inline complete method as well For better guarantees that `finalAction` is actually called on the same screen that `checkCanComplete()` was (uses result of one `getCurrentScreen()` call throughout instead of calling multiple times). --- osu.Game/PerformFromMenuRunner.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game/PerformFromMenuRunner.cs b/osu.Game/PerformFromMenuRunner.cs index 9222a64023..7999023998 100644 --- a/osu.Game/PerformFromMenuRunner.cs +++ b/osu.Game/PerformFromMenuRunner.cs @@ -84,7 +84,8 @@ namespace osu.Game // we may already be at the target screen type. if (validScreens.Contains(current.GetType()) && !beatmap.Disabled) { - complete(); + finalAction(current); + Cancel(); return; } @@ -138,11 +139,5 @@ namespace osu.Game lastEncounteredDialogScreen = current; return true; } - - private void complete() - { - finalAction(getCurrentScreen()); - Cancel(); - } } } 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 19/37] 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 17abe90c27ff837d39e97ec3678dad33bad3e6c9 Mon Sep 17 00:00:00 2001 From: mcendu Date: Thu, 31 Dec 2020 20:23:13 +0800 Subject: [PATCH 20/37] move SkinnableHealthDisplay Similar components are in osu.Game.Screens.Play.HUD while this is not --- .../Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs | 2 +- osu.Game/Screens/Play/{ => HUD}/SkinnableHealthDisplay.cs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) rename osu.Game/Screens/Play/{ => HUD}/SkinnableHealthDisplay.cs (95%) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs index e1b0820662..5bac8582d7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Judgements; -using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD; namespace osu.Game.Tests.Visual.Gameplay { diff --git a/osu.Game/Screens/Play/SkinnableHealthDisplay.cs b/osu.Game/Screens/Play/HUD/SkinnableHealthDisplay.cs similarity index 95% rename from osu.Game/Screens/Play/SkinnableHealthDisplay.cs rename to osu.Game/Screens/Play/HUD/SkinnableHealthDisplay.cs index d35d15d665..1f91f5e50f 100644 --- a/osu.Game/Screens/Play/SkinnableHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/SkinnableHealthDisplay.cs @@ -5,10 +5,9 @@ using System; using osu.Framework.Bindables; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; -using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; -namespace osu.Game.Screens.Play +namespace osu.Game.Screens.Play.HUD { public class SkinnableHealthDisplay : SkinnableDrawable, IHealthDisplay { From 7441cfd94ee93e764102eead7839bb2c862ce541 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 17:53:29 +0000 Subject: [PATCH 21/37] Bump Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson Bumps [Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson](https://github.com/aspnet/AspNetCore) from 3.1.9 to 3.1.10. - [Release notes](https://github.com/aspnet/AspNetCore/releases) - [Commits](https://github.com/aspnet/AspNetCore/compare/v3.1.9...v3.1.10) Signed-off-by: dependabot-preview[bot] --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 93aa2bc701..4c57eb6d00 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -22,7 +22,7 @@ - + From 0fd2e368c1c73e0d2e4932a620f2f4c6021633c7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 17:53:41 +0000 Subject: [PATCH 22/37] Bump Microsoft.NET.Test.Sdk from 16.8.0 to 16.8.3 Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.8.0 to 16.8.3. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.8.0...v16.8.3) Signed-off-by: dependabot-preview[bot] --- .../osu.Game.Rulesets.Catch.Tests.csproj | 2 +- .../osu.Game.Rulesets.Mania.Tests.csproj | 2 +- osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj | 2 +- .../osu.Game.Rulesets.Taiko.Tests.csproj | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 61ecd79e3d..51d2032795 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -2,7 +2,7 @@ - + diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index fa7bfd7169..3261f632f2 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -2,7 +2,7 @@ - + diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index d6a03da807..32243e0bc3 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -2,7 +2,7 @@ - + diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index a89645d881..210f81d111 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -2,7 +2,7 @@ - + diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 83d7b4135a..9049b67f90 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -3,7 +3,7 @@ - + diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj index bc6b994988..dc4f22788d 100644 --- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj +++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj @@ -5,7 +5,7 @@ - + From 652b0ccd8fe5c47dbde90e41f15d8d11baea76f7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 17:54:11 +0000 Subject: [PATCH 23/37] Bump Microsoft.AspNetCore.SignalR.Client from 3.1.9 to 3.1.10 Bumps [Microsoft.AspNetCore.SignalR.Client](https://github.com/aspnet/AspNetCore) from 3.1.9 to 3.1.10. - [Release notes](https://github.com/aspnet/AspNetCore/releases) - [Commits](https://github.com/aspnet/AspNetCore/compare/v3.1.9...v3.1.10) Signed-off-by: dependabot-preview[bot] --- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 93aa2bc701..3c8df17ee5 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -21,7 +21,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 5445adb3fb..f5c133263b 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -78,7 +78,7 @@ $(NoWarn);NU1605 - + From 6cd838fd4b8e510739891e64019c192122e08f2f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 17:55:04 +0000 Subject: [PATCH 24/37] Bump Microsoft.CodeAnalysis.BannedApiAnalyzers from 3.3.1 to 3.3.2 Bumps [Microsoft.CodeAnalysis.BannedApiAnalyzers](https://github.com/dotnet/roslyn-analyzers) from 3.3.1 to 3.3.2. - [Release notes](https://github.com/dotnet/roslyn-analyzers/releases) - [Changelog](https://github.com/dotnet/roslyn-analyzers/blob/master/PostReleaseActivities.md) - [Commits](https://github.com/dotnet/roslyn-analyzers/compare/v3.3.1...v3.3.2) Signed-off-by: dependabot-preview[bot] --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 551cb75077..9ec442aafa 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -16,7 +16,7 @@ - + From fa73d0172e01492f6f22c8c457751c0ea37fb659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 2 Jan 2021 00:11:21 +0100 Subject: [PATCH 25/37] Keep SignalR at last working version on iOS --- osu.iOS.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.iOS.props b/osu.iOS.props index f5c133263b..5445adb3fb 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -78,7 +78,7 @@ $(NoWarn);NU1605 - + From 72a6ca77559c409bc0a5671663510d1fbcbaffb6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 2 Jan 2021 16:47:00 +0900 Subject: [PATCH 26/37] Allow signalr to retry connecting when connection is closed without an exception --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 24ea6abc4a..7cd1ef78f7 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -88,11 +88,12 @@ namespace osu.Game.Online.Multiplayer { isConnected.Value = false; - if (ex != null) - { - Logger.Log($"Multiplayer client lost connection: {ex}", LoggingTarget.Network); + Logger.Log(ex != null + ? $"Multiplayer client lost connection: {ex}" + : "Multiplayer client disconnected", LoggingTarget.Network); + + if (connection != null) await tryUntilConnected(); - } }; await tryUntilConnected(); From 66bd847b4507cb575549c01496dbabf819c6164b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 2 Jan 2021 11:53:06 +0100 Subject: [PATCH 27/37] Bump InspectCode tool to 2020.3.2 --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index dd53eefd23..58c24181d3 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "jetbrains.resharper.globaltools": { - "version": "2020.2.4", + "version": "2020.3.2", "commands": [ "jb" ] From 18ac97ca563e9a02d56c469e5c084ccfa4b1e978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 2 Jan 2021 12:21:53 +0100 Subject: [PATCH 28/37] Disable "merge sequential patterns" suggestions As they were considered to be detrimental to code readability. --- osu.sln.DotSettings | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 22ea73858e..aa8f8739c1 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -106,6 +106,7 @@ HINT WARNING WARNING + DO_NOT_SHOW WARNING WARNING WARNING From 924af58f5b1ba2b5fcdaa00a79db21ce6c19bceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 2 Jan 2021 12:25:16 +0100 Subject: [PATCH 29/37] Replace using static with explicit nested reference This seems to be an inspectcode bug, as the code is correct and compiles, but let's just work around it for now. --- .../Visual/Components/TestScenePreviewTrackManager.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs index a3db20ce83..9a999a4931 100644 --- a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs +++ b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs @@ -8,7 +8,6 @@ using osu.Framework.Audio.Track; using osu.Framework.Graphics.Containers; using osu.Game.Audio; using osu.Game.Beatmaps; -using static osu.Game.Tests.Visual.Components.TestScenePreviewTrackManager.TestPreviewTrackManager; namespace osu.Game.Tests.Visual.Components { @@ -100,7 +99,7 @@ namespace osu.Game.Tests.Visual.Components [Test] public void TestNonPresentTrack() { - TestPreviewTrack track = null; + TestPreviewTrackManager.TestPreviewTrack track = null; AddStep("get non-present track", () => { @@ -182,9 +181,9 @@ namespace osu.Game.Tests.Visual.Components AddAssert("track stopped", () => !track.IsRunning); } - private TestPreviewTrack getTrack() => (TestPreviewTrack)trackManager.Get(null); + private TestPreviewTrackManager.TestPreviewTrack getTrack() => (TestPreviewTrackManager.TestPreviewTrack)trackManager.Get(null); - private TestPreviewTrack getOwnedTrack() + private TestPreviewTrackManager.TestPreviewTrack getOwnedTrack() { var track = getTrack(); From 1a443381247492b9233ae9c01ebf1a44510359ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 3 Jan 2021 15:38:28 +0900 Subject: [PATCH 30/37] 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 31/37] 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 32/37] 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 33/37] 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 34/37] 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 2501707d7d86c9927fda5f3ece0d75c14e769bb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 3 Jan 2021 20:44:57 +0900 Subject: [PATCH 35/37] 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 36/37] 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 37/37] 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); }