1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-13 20:33:35 +08:00

Add better support for handling disconnection at the ranked play queue screen (#37658)

Until now the queue screen basically did nothing to let the user knowing
they were disconnected from the server. Now the various components will
correctly clear state and show a roughly competent "i'm trying to
reconnect" state.



https://github.com/user-attachments/assets/bff1b241-a6a2-445a-9ffa-b5682f2a3656




---

Can be tested using the following patch (hit `F7` to reconnect, with a 5
second delay to show the disconnected state too):

```diff
diff --git a/osu.Game/Online/PersistentEndpointClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs
index 7064906be4..ae539aba8d 100644
--- a/osu.Game/Online/PersistentEndpointClientConnector.cs
+++ b/osu.Game/Online/PersistentEndpointClientConnector.cs
@@ -99,6 +99,8 @@ private async Task connect()
                     // this will also create a new cancellation token source.
                     await disconnect(false).ConfigureAwait(false);
 
+                    await Task.Delay(5000).ConfigureAwait(false);
+
                     // this token will be valid for the scope of this connection.
                     // if cancelled, we can be sure that a disconnect or reconnect is handled elsewhere.
                     var cancellationToken = connectCancelSource.Token;
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index 703444a92f..fb467472d3 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -22,6 +22,7 @@
 using osu.Framework.Graphics.Containers;
 using osu.Framework.Graphics.Textures;
 using osu.Framework.Input;
+using osu.Framework.Input.Events;
 using osu.Framework.Input.Handlers;
 using osu.Framework.Input.Handlers.Joystick;
 using osu.Framework.Input.Handlers.Midi;
@@ -65,6 +66,7 @@
 using osu.Game.Scoring;
 using osu.Game.Skinning;
 using osu.Game.Utils;
+using osuTK.Input;
 using RuntimeInfo = osu.Framework.RuntimeInfo;
 
 namespace osu.Game
@@ -104,7 +106,7 @@ public partial class OsuGameBase : Framework.Game, ICanAcceptFiles, IBeatSyncPro
         /// </summary>
         private const double global_track_volume_adjust = 0.8;
 
-        public virtual bool UseDevelopmentServer => DebugUtils.IsDebugBuild;
+        public virtual bool UseDevelopmentServer => false;
 
         public virtual EndpointConfiguration CreateEndpoints() =>
             UseDevelopmentServer ? new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration();
@@ -466,6 +468,20 @@ private void addFilesWarning()
             }
         }
 
+        protected override bool OnKeyDown(KeyDownEvent e)
+        {
+            if (e.Key == Key.F7)
+            {
+                Logger.Log("Forcing reconnect!", level: LogLevel.Important);
+
+                ((IStatefulUserHubClient)MultiplayerClient).ServerShuttingDown();
+                ((IStatefulUserHubClient)SpectatorClient).ServerShuttingDown();
+                ((IStatefulUserHubClient)metadataClient).ServerShuttingDown();
+            }
+
+            return base.OnKeyDown(e);
+        }
+
         private void onTrackChanged(WorkingBeatmap beatmap, TrackChangeDirection direction) => beatmapClock.ChangeSource(beatmap.Track);
 
         protected virtual void InitialiseFonts()

```
This commit is contained in:
Dean Herbert
2026-05-07 16:55:15 +09:00
committed by GitHub
Unverified
parent 3f5c113394
commit 7f385c7873
3 changed files with 81 additions and 38 deletions
@@ -34,7 +34,13 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
set
{
users = value;
if (IsLoaded)
refresh();
}
}
private void refresh()
{
foreach (var u in usersContainer)
u.Delay(RNG.Next(0, 1000)).FadeOut(500).Expire();
@@ -49,7 +55,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
usersContainer.AddRange(avatars);
});
}
}
protected override void LoadComplete()
{
@@ -64,6 +69,8 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
RelativeSizeAxes = Axes.X,
},
};
refresh();
}
public partial class MovingAvatar : MatchmakingAvatar
@@ -24,25 +24,36 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
{
private const float icon_size = 34;
public readonly Bindable<MatchmakingPool[]> AvailablePools = new Bindable<MatchmakingPool[]>([]);
public readonly Bindable<MatchmakingPool[]?> AvailablePools = new Bindable<MatchmakingPool[]?>([]);
public readonly Bindable<MatchmakingPool?> SelectedPool = new Bindable<MatchmakingPool?>();
private FillFlowContainer<SelectorButton> poolFlow = null!;
private LoadingSpinner loading = null!;
public PoolSelector()
{
AutoSizeAxes = Axes.Both;
AutoSizeAxes = Axes.X;
Height = SelectorButton.SIZE.Y + 10;
}
[BackgroundDependencyLoader]
private void load()
{
InternalChild = poolFlow = new FillFlowContainer<SelectorButton>
InternalChildren = new Drawable[]
{
poolFlow = new FillFlowContainer<SelectorButton>
{
AutoSizeAxes = Axes.X,
Height = SelectorButton.SIZE.Y + 10,
RelativeSizeAxes = Axes.Y,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(5),
},
loading = new LoadingSpinner(withBox: true)
{
Size = new Vector2(50),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
};
}
@@ -54,6 +65,14 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
{
poolFlow.Clear();
if (pools.NewValue == null)
{
loading.Show();
return;
}
loading.Hide();
foreach (var p in pools.NewValue)
{
poolFlow.Add(new SelectorButton(p)
@@ -80,7 +80,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
private readonly IBindable<MatchmakingScreenState> currentState = new Bindable<MatchmakingScreenState>();
private readonly Bindable<MatchmakingPool[]> availablePools = new Bindable<MatchmakingPool[]>([]);
private readonly Bindable<MatchmakingPool[]?> availablePools = new Bindable<MatchmakingPool[]?>();
private readonly Bindable<MatchmakingPool?> selectedPool = new Bindable<MatchmakingPool?>();
private readonly MatchmakingPoolType poolType;
@@ -99,6 +99,8 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
private GridContainer mainGrid = null!;
private IBindable<bool> isConnected = null!;
public ScreenQueue(MatchmakingPoolType poolType)
{
this.poolType = poolType;
@@ -339,9 +341,22 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
currentState.BindValueChanged(s => SetState(s.NewValue));
selectedPool.BindTo(queue.SelectedPool);
selectedPool.BindValueChanged(onSelectedPoolChanged, true);
selectedPool.BindValueChanged(e => refreshLobbyData());
isConnected = client.IsConnected.GetBoundCopy();
isConnected.BindValueChanged(connected => Schedule(() =>
{
if (connected.NewValue)
{
populateAvailablePools().FireAndForget();
refreshLobbyData();
}
else
{
availablePools.Value = null;
clearLobbyData();
}
}), true);
}
private async Task populateAvailablePools()
@@ -367,7 +382,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
{
APIUser?[] users = result.GetResultSafely();
if (!cancellation.IsCancellationRequested)
Users = users.OfType<APIUser>().ToArray();
cloud.Users = users.OfType<APIUser>().ToArray();
}), cancellation.Token);
// Global (incremental) updates will not contain the user rating, so keep the one we already received from initial status data.
@@ -402,15 +417,11 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
});
}
private void onSelectedPoolChanged(ValueChangedEvent<MatchmakingPool?> e)
private void refreshLobbyData()
{
userRating = null;
ratingGraph.SetData([], null);
clearLobbyData();
resultPanelContainer.Clear();
resultPanelContainer.LayoutDuration = 0;
if (e.NewValue == null)
if (selectedPool.Value == null)
{
client.MatchmakingLeaveLobby().FireAndForget();
return;
@@ -418,10 +429,20 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
client.MatchmakingJoinLobbyWithParams(new MatchmakingJoinLobbyRequest
{
PoolId = e.NewValue.Id
PoolId = selectedPool.Value.Id
}).FireAndForget();
}
private void clearLobbyData()
{
resultPanelContainer.Clear();
resultPanelContainer.LayoutDuration = 0;
userRating = null;
ratingGraph.SetData([], null);
cloud.Users = Array.Empty<APIUser>();
}
public override void OnEntering(ScreenTransitionEvent e)
{
base.OnEntering(e);
@@ -470,11 +491,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
}
}
public APIUser[] Users
{
set => cloud.Users = value;
}
public void SetState(MatchmakingScreenState newState)
{
mainContent.FadeInFromZero(500, Easing.OutQuint);
@@ -515,6 +531,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Width = 200,
Enabled = { BindTarget = isConnected },
SelectedPool = { BindTarget = selectedPool },
Action = () =>
{