mirror of
https://github.com/ppy/osu.git
synced 2025-01-26 18:52:55 +08:00
Centralise and improve messaging around online state
When the server requests a disconnect due to a user connecting via a second device, the client will now log the user out on the first device and show a notification informing them of the cause of disconnection.
This commit is contained in:
parent
2391035e49
commit
42fada578e
@ -100,7 +100,11 @@ namespace osu.Game.Online
|
|||||||
return Task.FromResult((PersistentEndpointClient)new HubClient(newConnection));
|
return Task.FromResult((PersistentEndpointClient)new HubClient(newConnection));
|
||||||
}
|
}
|
||||||
|
|
||||||
Task IHubClientConnector.Disconnect() => base.Disconnect();
|
async Task IHubClientConnector.Disconnect()
|
||||||
|
{
|
||||||
|
await Disconnect().ConfigureAwait(false);
|
||||||
|
API.Logout();
|
||||||
|
}
|
||||||
|
|
||||||
protected override string ClientName { get; }
|
protected override string ClientName { get; }
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Development;
|
using osu.Framework.Development;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Logging;
|
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
@ -88,6 +87,11 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action? ResultsReady;
|
public event Action? ResultsReady;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked just prior to disconnection requested by the server via <see cref="IStatefulUserHubClient.DisconnectRequested"/>.
|
||||||
|
/// </summary>
|
||||||
|
public event Action? Disconnecting;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the <see cref="MultiplayerClient"/> is currently connected.
|
/// Whether the <see cref="MultiplayerClient"/> is currently connected.
|
||||||
/// This is NOT thread safe and usage should be scheduled.
|
/// This is NOT thread safe and usage should be scheduled.
|
||||||
@ -155,10 +159,7 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
{
|
{
|
||||||
// clean up local room state on server disconnect.
|
// clean up local room state on server disconnect.
|
||||||
if (!connected.NewValue && Room != null)
|
if (!connected.NewValue && Room != null)
|
||||||
{
|
|
||||||
Logger.Log("Clearing room due to multiplayer server connection loss.", LoggingTarget.Runtime, LogLevel.Important);
|
|
||||||
LeaveRoom();
|
LeaveRoom();
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,7 +882,11 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
|
|
||||||
Task IStatefulUserHubClient.DisconnectRequested()
|
Task IStatefulUserHubClient.DisconnectRequested()
|
||||||
{
|
{
|
||||||
Schedule(() => DisconnectInternal());
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
Disconnecting?.Invoke();
|
||||||
|
DisconnectInternal();
|
||||||
|
});
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
120
osu.Game/Online/OnlineStatusNotifier.cs
Normal file
120
osu.Game/Online/OnlineStatusNotifier.cs
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Screens;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.Multiplayer;
|
||||||
|
using osu.Game.Online.Spectator;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.Notifications;
|
||||||
|
using osu.Game.Screens.OnlinePlay;
|
||||||
|
|
||||||
|
namespace osu.Game.Online
|
||||||
|
{
|
||||||
|
public partial class OnlineStatusNotifier : Component
|
||||||
|
{
|
||||||
|
private readonly Func<IScreen> getCurrentScreen;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private MultiplayerClient multiplayerClient { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private SpectatorClient spectatorClient { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private INotificationOverlay? notificationOverlay { get; set; }
|
||||||
|
|
||||||
|
private IBindable<APIState> apiState = null!;
|
||||||
|
private IBindable<bool> multiplayerState = null!;
|
||||||
|
private IBindable<bool> spectatorState = null!;
|
||||||
|
private bool forcedDisconnection;
|
||||||
|
|
||||||
|
public OnlineStatusNotifier(Func<IScreen> getCurrentScreen)
|
||||||
|
{
|
||||||
|
this.getCurrentScreen = getCurrentScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(IAPIProvider api)
|
||||||
|
{
|
||||||
|
apiState = api.State.GetBoundCopy();
|
||||||
|
multiplayerState = multiplayerClient.IsConnected.GetBoundCopy();
|
||||||
|
spectatorState = spectatorClient.IsConnected.GetBoundCopy();
|
||||||
|
|
||||||
|
multiplayerClient.Disconnecting += notifyAboutForcedDisconnection;
|
||||||
|
spectatorClient.Disconnecting += notifyAboutForcedDisconnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyAboutForcedDisconnection()
|
||||||
|
{
|
||||||
|
if (forcedDisconnection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
forcedDisconnection = true;
|
||||||
|
notificationOverlay?.Post(new SimpleErrorNotification
|
||||||
|
{
|
||||||
|
Icon = FontAwesome.Solid.ExclamationCircle,
|
||||||
|
Text = "You have been logged out on this device due to a login to your account on another device."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
apiState.BindValueChanged(_ =>
|
||||||
|
{
|
||||||
|
if (apiState.Value == APIState.Online)
|
||||||
|
forcedDisconnection = false;
|
||||||
|
|
||||||
|
Scheduler.AddOnce(updateState);
|
||||||
|
});
|
||||||
|
multiplayerState.BindValueChanged(_ => Scheduler.AddOnce(updateState));
|
||||||
|
spectatorState.BindValueChanged(_ => Scheduler.AddOnce(updateState));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateState()
|
||||||
|
{
|
||||||
|
if (forcedDisconnection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (apiState.Value == APIState.Offline && getCurrentScreen() is OnlinePlayScreen)
|
||||||
|
{
|
||||||
|
notificationOverlay?.Post(new SimpleErrorNotification
|
||||||
|
{
|
||||||
|
Icon = FontAwesome.Solid.ExclamationCircle,
|
||||||
|
Text = "API connection was lost. Can't continue with online play."
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!multiplayerClient.IsConnected.Value && multiplayerClient.Room != null)
|
||||||
|
{
|
||||||
|
notificationOverlay?.Post(new SimpleErrorNotification
|
||||||
|
{
|
||||||
|
Icon = FontAwesome.Solid.ExclamationCircle,
|
||||||
|
Text = "Connection to the multiplayer server was lost. Exiting multiplayer."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle spectator server failure somehow?
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
if (spectatorClient.IsNotNull())
|
||||||
|
spectatorClient.Disconnecting -= notifyAboutForcedDisconnection;
|
||||||
|
|
||||||
|
if (multiplayerClient.IsNotNull())
|
||||||
|
multiplayerClient.Disconnecting -= notifyAboutForcedDisconnection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -115,12 +115,14 @@ namespace osu.Game.Online.Spectator
|
|||||||
return connection.InvokeAsync(nameof(ISpectatorServer.EndWatchingUser), userId);
|
return connection.InvokeAsync(nameof(ISpectatorServer.EndWatchingUser), userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Task DisconnectInternal()
|
protected override async Task DisconnectInternal()
|
||||||
{
|
{
|
||||||
if (connector == null)
|
await base.DisconnectInternal().ConfigureAwait(false);
|
||||||
return Task.CompletedTask;
|
|
||||||
|
|
||||||
return connector.Disconnect();
|
if (connector == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await connector.Disconnect().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,11 @@ namespace osu.Game.Online.Spectator
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual event Action<int, long>? OnUserScoreProcessed;
|
public virtual event Action<int, long>? OnUserScoreProcessed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked just prior to disconnection requested by the server via <see cref="IStatefulUserHubClient.DisconnectRequested"/>.
|
||||||
|
/// </summary>
|
||||||
|
public event Action? Disconnecting;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A dictionary containing all users currently being watched, with the number of watching components for each user.
|
/// A dictionary containing all users currently being watched, with the number of watching components for each user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -297,7 +302,11 @@ namespace osu.Game.Online.Spectator
|
|||||||
|
|
||||||
protected abstract Task StopWatchingUserInternal(int userId);
|
protected abstract Task StopWatchingUserInternal(int userId);
|
||||||
|
|
||||||
protected abstract Task DisconnectInternal();
|
protected virtual Task DisconnectInternal()
|
||||||
|
{
|
||||||
|
Disconnecting?.Invoke();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
|
@ -1054,6 +1054,7 @@ namespace osu.Game
|
|||||||
Add(difficultyRecommender);
|
Add(difficultyRecommender);
|
||||||
Add(externalLinkOpener = new ExternalLinkOpener());
|
Add(externalLinkOpener = new ExternalLinkOpener());
|
||||||
Add(new MusicKeyBindingHandler());
|
Add(new MusicKeyBindingHandler());
|
||||||
|
Add(new OnlineStatusNotifier(() => ScreenStack.CurrentScreen));
|
||||||
|
|
||||||
// side overlays which cancel each other.
|
// side overlays which cancel each other.
|
||||||
var singleDisplaySideOverlays = new OverlayContainer[] { Settings, Notifications, FirstRunOverlay };
|
var singleDisplaySideOverlays = new OverlayContainer[] { Settings, Notifications, FirstRunOverlay };
|
||||||
|
@ -71,7 +71,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
screenStack = new OnlinePlaySubScreenStack { RelativeSizeAxes = Axes.Both },
|
screenStack = new OnlinePlaySubScreenStack { RelativeSizeAxes = Axes.Both },
|
||||||
new Header(ScreenTitle, screenStack),
|
new Header(ScreenTitle, screenStack),
|
||||||
RoomManager,
|
RoomManager,
|
||||||
ongoingOperationTracker
|
ongoingOperationTracker,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -79,10 +79,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
private void onlineStateChanged(ValueChangedEvent<APIState> state) => Schedule(() =>
|
private void onlineStateChanged(ValueChangedEvent<APIState> state) => Schedule(() =>
|
||||||
{
|
{
|
||||||
if (state.NewValue != APIState.Online)
|
if (state.NewValue != APIState.Online)
|
||||||
{
|
|
||||||
Logger.Log("API connection was lost, can't continue with online play", LoggingTarget.Network, LogLevel.Important);
|
|
||||||
Schedule(forcefullyExit);
|
Schedule(forcefullyExit);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
|
@ -181,10 +181,10 @@ namespace osu.Game.Tests.Visual.Spectator
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Task DisconnectInternal()
|
protected override async Task DisconnectInternal()
|
||||||
{
|
{
|
||||||
|
await base.DisconnectInternal().ConfigureAwait(false);
|
||||||
isConnected.Value = false;
|
isConnected.Value = false;
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user