diff --git a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs
index 75bb578a29..5cbf3be8ca 100644
--- a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs
+++ b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs
@@ -130,7 +130,11 @@ namespace osu.Game.Online.RealtimeMultiplayer
public override async Task LeaveRoom()
{
if (!isConnected.Value)
+ {
+ // even if not connected, make sure the local room state can be cleaned up.
+ await base.LeaveRoom();
return;
+ }
if (Room == null)
return;
diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs
index 4ebd648689..79d82a8d02 100644
--- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs
+++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs
@@ -11,6 +11,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
+using osu.Framework.Logging;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Online.API;
@@ -75,6 +76,19 @@ namespace osu.Game.Online.RealtimeMultiplayer
// Todo: This is temporary, until the multiplayer server returns the item id on match start or otherwise.
private int playlistItemId;
+ protected StatefulMultiplayerClient()
+ {
+ IsConnected.BindValueChanged(connected =>
+ {
+ // clean up local room state on server disconnect.
+ if (!connected.NewValue)
+ {
+ Logger.Log("Connection to multiplayer server was lost.", LoggingTarget.Runtime, LogLevel.Important);
+ LeaveRoom();
+ }
+ });
+ }
+
///
/// Joins the for a given API .
///
diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs
index 44c893363b..6b08745dd7 100644
--- a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs
+++ b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs
@@ -184,7 +184,7 @@ namespace osu.Game.Screens.Multi.Lounge
///
/// Push a room as a new subscreen.
///
- public void Open(Room room)
+ public virtual void Open(Room room)
{
// Handles the case where a room is clicked 3 times in quick succession
if (!this.IsCurrentScreen())
diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs
index 9fbf0c4654..b53ec94519 100644
--- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs
+++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs
@@ -1,7 +1,10 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Framework.Allocation;
+using osu.Framework.Logging;
using osu.Game.Online.Multiplayer;
+using osu.Game.Online.RealtimeMultiplayer;
using osu.Game.Screens.Multi.Lounge;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Screens.Multi.Match;
@@ -13,5 +16,19 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer
protected override FilterControl CreateFilterControl() => new RealtimeFilterControl();
protected override RoomSubScreen CreateRoomSubScreen(Room room) => new RealtimeMatchSubScreen(room);
+
+ [Resolved]
+ private StatefulMultiplayerClient client { get; set; }
+
+ public override void Open(Room room)
+ {
+ if (!client.IsConnected.Value)
+ {
+ Logger.Log("Not currently connected to the multiplayer server.", LoggingTarget.Runtime, LogLevel.Important);
+ return;
+ }
+
+ base.Open(room);
+ }
}
}
diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs
index cdab1435c0..807ea74404 100644
--- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs
+++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs
@@ -4,6 +4,7 @@
using System.Collections.Specialized;
using System.Linq;
using osu.Framework.Allocation;
+using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Screens;
@@ -16,6 +17,7 @@ using osu.Game.Screens.Multi.RealtimeMultiplayer.Match;
using osu.Game.Screens.Multi.RealtimeMultiplayer.Participants;
using osu.Game.Screens.Play;
using osu.Game.Users;
+using ParticipantsList = osu.Game.Screens.Multi.RealtimeMultiplayer.Participants.ParticipantsList;
namespace osu.Game.Screens.Multi.RealtimeMultiplayer
{
@@ -34,6 +36,8 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer
private RealtimeMatchSettingsOverlay settingsOverlay;
+ private IBindable isConnected;
+
public RealtimeMatchSubScreen(Room room)
{
Title = room.RoomID.Value == null ? "New match" : room.Name.Value;
@@ -102,7 +106,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer
new Drawable[] { new ParticipantsListHeader() },
new Drawable[]
{
- new Participants.ParticipantsList
+ new ParticipantsList
{
RelativeSizeAxes = Axes.Both
},
@@ -173,6 +177,13 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer
Playlist.BindCollectionChanged(onPlaylistChanged, true);
client.LoadRequested += onLoadRequested;
+
+ isConnected = client.IsConnected.GetBoundCopy();
+ isConnected.BindValueChanged(connected =>
+ {
+ if (!connected.NewValue)
+ Schedule(this.Exit);
+ }, true);
}
public override bool OnBackButton()
diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs
index 7824b414f2..e467e5fcf8 100644
--- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs
+++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs
@@ -8,8 +8,8 @@ using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using osu.Framework.Allocation;
+using osu.Framework.Bindables;
using osu.Framework.Logging;
-using osu.Framework.Screens;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.RealtimeMultiplayer;
using osu.Game.Scoring;
@@ -31,6 +31,8 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer
[Resolved]
private StatefulMultiplayerClient client { get; set; }
+ private IBindable isConnected;
+
private readonly TaskCompletionSource resultsReady = new TaskCompletionSource();
private readonly ManualResetEventSlim startedEvent = new ManualResetEventSlim();
@@ -50,17 +52,26 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer
client.MatchStarted += onMatchStarted;
client.ResultsReady += onResultsReady;
+
+ isConnected = client.IsConnected.GetBoundCopy();
+ isConnected.BindValueChanged(connected =>
+ {
+ if (!connected.NewValue)
+ {
+ startedEvent.Set();
+
+ // messaging to the user about this disconnect will be provided by the RealtimeMatchSubScreen.
+ Schedule(() => PerformExit(false));
+ }
+ }, true);
+
client.ChangeState(MultiplayerUserState.Loaded);
if (!startedEvent.Wait(TimeSpan.FromSeconds(30)))
{
Logger.Log("Failed to start the multiplayer match in time.", LoggingTarget.Runtime, LogLevel.Important);
- Schedule(() =>
- {
- ValidForResume = false;
- this.Exit();
- });
+ Schedule(() => PerformExit(false));
}
Debug.Assert(client.Room != null);
diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs
index f982574eb3..2f60f504de 100644
--- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs
+++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs
@@ -43,6 +43,12 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer
public override void JoinRoom(Room room, Action onSuccess = null, Action onError = null)
{
+ if (!multiplayerClient.IsConnected.Value)
+ {
+ onError?.Invoke("Not currently connected to the multiplayer server.");
+ return;
+ }
+
// this is done here as a pre-check to avoid clicking on already closed rooms in the lounge from triggering a server join.
// should probably be done at a higher level, but due to the current structure of things this is the easiest place for now.
if (room.Status.Value is RoomStatusEnded)
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index c539dff5d9..2bc84ce5d5 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -386,7 +386,7 @@ namespace osu.Game.Screens.Play
if (!this.IsCurrentScreen()) return;
fadeOut(true);
- performImmediateExit();
+ PerformExit(true);
},
},
failAnimation = new FailAnimation(DrawableRuleset) { OnComplete = onFailComplete, },
@@ -458,20 +458,30 @@ namespace osu.Game.Screens.Play
return playable;
}
- private void performImmediateExit()
+ ///
+ /// Exits the .
+ ///
+ ///
+ /// Whether the exit is requested by the user, or a higher-level game component.
+ /// Pausing is allowed only in the former case.
+ ///
+ protected void PerformExit(bool userRequested)
{
// if a restart has been requested, cancel any pending completion (user has shown intent to restart).
completionProgressDelegate?.Cancel();
ValidForResume = false;
- performUserRequestedExit();
+ if (!this.IsCurrentScreen()) return;
+
+ if (userRequested)
+ performUserRequestedExit();
+ else
+ this.Exit();
}
private void performUserRequestedExit()
{
- if (!this.IsCurrentScreen()) return;
-
if (ValidForResume && HasFailed && !FailOverlay.IsPresent)
{
failAnimation.FinishTransforms(true);
@@ -498,7 +508,7 @@ namespace osu.Game.Screens.Play
RestartRequested?.Invoke();
if (this.IsCurrentScreen())
- performImmediateExit();
+ PerformExit(true);
else
this.MakeCurrent();
}