From 0551c75c6bb435a7d8f64deff52d38fd6b2b57d9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 16:21:50 +0900 Subject: [PATCH 1/5] Adjust API disconnection text to be usable in more scenarios --- osu.Game/Localisation/NotificationsStrings.cs | 4 ++-- osu.Game/Online/OnlineStatusNotifier.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index 0d22d98eb1..91d2615e47 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -146,9 +146,9 @@ Click to see what's new!", version); public static LocalisableString FriendOffline(string info) => new TranslatableString(getKey(@"friend_offline"), @"Offline: {0}", info); /// - /// "Connection to API was lost. Can't continue with online play." + /// "Connection to online services was interrupted. osu! will be operating with limited functionality." /// - public static LocalisableString APIDisconnect => new TranslatableString(getKey(@"api_disconnect"), @"Connection to API was lost. Can't continue with online play."); + public static LocalisableString APIConnectionInterrupted => new TranslatableString(getKey(@"api_connection_interrupted"), @"Connection to online services was interrupted. osu! will be operating with limited functionality."); /// /// "Connection to the multiplayer server was lost. Exiting multiplayer." diff --git a/osu.Game/Online/OnlineStatusNotifier.cs b/osu.Game/Online/OnlineStatusNotifier.cs index da58dc3d46..0c4f6df96a 100644 --- a/osu.Game/Online/OnlineStatusNotifier.cs +++ b/osu.Game/Online/OnlineStatusNotifier.cs @@ -89,7 +89,7 @@ namespace osu.Game.Online notificationOverlay?.Post(new SimpleErrorNotification { Icon = FontAwesome.Solid.ExclamationCircle, - Text = NotificationsStrings.APIDisconnect, + Text = NotificationsStrings.APIConnectionInterrupted, }); } }); From 15cb3b7a278ad12a9dff6550f5948cb73b162e02 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 16:32:06 +0900 Subject: [PATCH 2/5] Use same message for multiplayer disconnects to simplify things further --- osu.Game/Localisation/NotificationsStrings.cs | 5 ----- osu.Game/Online/OnlineStatusNotifier.cs | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index 91d2615e47..1d6b69a007 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -150,11 +150,6 @@ Click to see what's new!", version); /// public static LocalisableString APIConnectionInterrupted => new TranslatableString(getKey(@"api_connection_interrupted"), @"Connection to online services was interrupted. osu! will be operating with limited functionality."); - /// - /// "Connection to the multiplayer server was lost. Exiting multiplayer." - /// - public static LocalisableString MultiplayerDisconnect => new TranslatableString(getKey(@"multiplayer_disconnect"), @"Connection to the multiplayer server was lost. Exiting multiplayer."); - /// /// "You have been logged out on this device due to a login to your account on another device." /// diff --git a/osu.Game/Online/OnlineStatusNotifier.cs b/osu.Game/Online/OnlineStatusNotifier.cs index 0c4f6df96a..70020f4b84 100644 --- a/osu.Game/Online/OnlineStatusNotifier.cs +++ b/osu.Game/Online/OnlineStatusNotifier.cs @@ -110,7 +110,7 @@ namespace osu.Game.Online notificationOverlay?.Post(new SimpleErrorNotification { Icon = FontAwesome.Solid.ExclamationCircle, - Text = NotificationsStrings.MultiplayerDisconnect, + Text = NotificationsStrings.APIConnectionInterrupted, }); } })); From c646b4e5ec55bae66abf1bd8fd44a430082d0fa1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 17:11:29 +0900 Subject: [PATCH 3/5] Alert when spectator server disconnects during gameplay This can cause issues liek loss of replays, so it's worth notifying the user and keeping things visible. --- osu.Game/Online/OnlineStatusNotifier.cs | 57 ++++++++++++++----------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/osu.Game/Online/OnlineStatusNotifier.cs b/osu.Game/Online/OnlineStatusNotifier.cs index 70020f4b84..66282e48fd 100644 --- a/osu.Game/Online/OnlineStatusNotifier.cs +++ b/osu.Game/Online/OnlineStatusNotifier.cs @@ -17,6 +17,7 @@ using osu.Game.Online.Spectator; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osu.Game.Screens.OnlinePlay; +using osu.Game.Screens.Play; namespace osu.Game.Online { @@ -75,22 +76,16 @@ namespace osu.Game.Online apiState.BindValueChanged(state => { - if (state.NewValue == APIState.Online) + switch (state.NewValue) { - userNotified = false; - return; - } + case APIState.Online: + userNotified = false; + return; - if (userNotified) return; - - if (state.NewValue == APIState.Offline && getCurrentScreen() is OnlinePlayScreen) - { - userNotified = true; - notificationOverlay?.Post(new SimpleErrorNotification - { - Icon = FontAwesome.Solid.ExclamationCircle, - Text = NotificationsStrings.APIConnectionInterrupted, - }); + case APIState.Offline: + if (getCurrentScreen() is OnlinePlayScreen) + notifyApiDisconnection(); + break; } }); @@ -102,22 +97,32 @@ namespace osu.Game.Online return; } - if (userNotified) return; - if (multiplayerClient.Room != null) - { - userNotified = true; - notificationOverlay?.Post(new SimpleErrorNotification - { - Icon = FontAwesome.Solid.ExclamationCircle, - Text = NotificationsStrings.APIConnectionInterrupted, - }); - } + notifyApiDisconnection(); })); - spectatorState.BindValueChanged(_ => + spectatorState.BindValueChanged(connected => Schedule(() => { - // TODO: handle spectator server failure somehow? + if (connected.NewValue) + { + userNotified = false; + return; + } + + if (getCurrentScreen() is Player) + notifyApiDisconnection(); + })); + } + + private void notifyApiDisconnection() + { + if (userNotified) return; + + userNotified = true; + notificationOverlay?.Post(new SimpleErrorNotification + { + Icon = FontAwesome.Solid.ExclamationCircle, + Text = NotificationsStrings.APIConnectionInterrupted, }); } From e8154080b3423de67d98e5885fe9992227524383 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 17:31:42 +0900 Subject: [PATCH 4/5] Stop websocket handshake failures from being shown to users --- .../Multiplayer/MultiplayerClientExtensions.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClientExtensions.cs b/osu.Game/Online/Multiplayer/MultiplayerClientExtensions.cs index 1cc5a8e70a..61824914b5 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClientExtensions.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClientExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using System.Net.WebSockets; using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR; using osu.Framework.Extensions.ExceptionExtensions; @@ -20,13 +21,23 @@ namespace osu.Game.Online.Multiplayer Debug.Assert(t.Exception != null); Exception exception = t.Exception.AsSingular(); + onError?.Invoke(exception); + + if (exception is WebSocketException wse && wse.Message == @"The remote party closed the WebSocket connection without completing the close handshake.") + { + // OnlineStatusNotifier is already letting users know about interruptions to connections. + // Silence these because it gets very spammy otherwise. + return; + } + if (exception.GetHubExceptionMessage() is string message) + { // Hub exceptions generally contain something we can show the user directly. Logger.Log(message, level: LogLevel.Important); - else - Logger.Error(exception, $"Unobserved exception occurred via {nameof(FireAndForget)} call: {exception.Message}"); + return; + } - onError?.Invoke(exception); + Logger.Error(exception, $"Unobserved exception occurred via {nameof(FireAndForget)} call: {exception.Message}"); } else { From 13138833948d8e07751c40e49948656cc00400ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Jan 2026 18:08:41 +0900 Subject: [PATCH 5/5] Scope player handling to specific screens which have issues --- osu.Game/Online/OnlineStatusNotifier.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/OnlineStatusNotifier.cs b/osu.Game/Online/OnlineStatusNotifier.cs index 66282e48fd..f4c33c67aa 100644 --- a/osu.Game/Online/OnlineStatusNotifier.cs +++ b/osu.Game/Online/OnlineStatusNotifier.cs @@ -109,8 +109,13 @@ namespace osu.Game.Online return; } - if (getCurrentScreen() is Player) - notifyApiDisconnection(); + switch (getCurrentScreen()) + { + case SpectatorPlayer: // obvious issues + case SubmittingPlayer: // replay sending issues + notifyApiDisconnection(); + break; + } })); }