Move game start logic to a higher level

This commit is contained in:
Bartłomiej Dach 2020-12-30 18:00:57 +01:00
parent d34609b98e
commit f800448c87
3 changed files with 48 additions and 35 deletions

View File

@ -34,7 +34,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Cached]
private OngoingOperationTracker ongoingOperationTracker = new OngoingOperationTracker();
private IDisposable toggleReadyOperation;
private IDisposable readyClickOperation;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
@ -66,11 +66,16 @@ namespace osu.Game.Tests.Visual.Multiplayer
},
OnReadyClick = async () =>
{
toggleReadyOperation = ongoingOperationTracker.BeginOperation();
readyClickOperation = ongoingOperationTracker.BeginOperation();
bool gameplayStarted = await Client.ToggleReady();
if (!gameplayStarted)
toggleReadyOperation.Dispose();
if (Client.IsHost && Client.LocalUser?.State == MultiplayerUserState.Ready)
{
await Client.StartMatch();
return;
}
await Client.ToggleReady();
readyClickOperation.Dispose();
}
};
});
@ -182,7 +187,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("user waiting for load", () => Client.Room?.Users[0].State == MultiplayerUserState.WaitingForLoad);
AddAssert("ready button disabled", () => !button.ChildrenOfType<OsuButton>().Single().Enabled.Value);
AddStep("transitioned to gameplay", () => toggleReadyOperation.Dispose());
AddStep("transitioned to gameplay", () => readyClickOperation.Dispose());
AddAssert("ready button enabled", () => button.ChildrenOfType<OsuButton>().Single().Enabled.Value);
}
}

View File

@ -198,30 +198,23 @@ namespace osu.Game.Online.Multiplayer
/// <summary>
/// Toggles the <see cref="LocalUser"/>'s ready state.
/// </summary>
/// <returns><c>true</c> if this toggle triggered a gameplay start; <c>false</c> otherwise.</returns>
/// <exception cref="InvalidOperationException">If a toggle of ready state is not valid at this time.</exception>
public async Task<bool> ToggleReady()
public async Task ToggleReady()
{
var localUser = LocalUser;
if (localUser == null)
return false;
return;
switch (localUser.State)
{
case MultiplayerUserState.Idle:
await ChangeState(MultiplayerUserState.Ready);
return false;
return;
case MultiplayerUserState.Ready:
if (Room?.Host?.Equals(localUser) == true)
{
await StartMatch();
return true;
}
await ChangeState(MultiplayerUserState.Idle);
return false;
return;
default:
throw new InvalidOperationException($"Cannot toggle ready when in {localUser.State}");

View File

@ -11,6 +11,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Screens;
using osu.Game.Extensions;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay.Components;
@ -41,7 +42,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
private IBindable<bool> isConnected;
[CanBeNull]
private IDisposable gameplayStartOperation;
private IDisposable readyClickOperation;
public MultiplayerMatchSubScreen(Room room)
{
@ -161,7 +162,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
new MultiplayerMatchFooter
{
SelectedItem = { BindTarget = SelectedItem },
OnReadyClick = onToggleReady
OnReadyClick = onReadyClick
}
}
},
@ -208,23 +209,37 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) => SelectedItem.Value = Playlist.FirstOrDefault();
private void onToggleReady()
private void onReadyClick()
{
Debug.Assert(gameplayStartOperation == null);
gameplayStartOperation = ongoingOperationTracker.BeginOperation();
Debug.Assert(readyClickOperation == null);
readyClickOperation = ongoingOperationTracker.BeginOperation();
if (client.IsHost && client.LocalUser?.State == MultiplayerUserState.Ready)
{
client.StartMatch()
.ContinueWith(t =>
{
// accessing Exception here silences any potential errors from the antecedent task
if (t.Exception != null)
{
// gameplay was not started due to an exception; unblock button.
endOperation();
}
// gameplay is starting, the button will be unblocked on load requested.
});
return;
}
client.ToggleReady()
.ContinueWith(t =>
{
// if gameplay was started, the button will be unblocked on load requested.
// accessing Exception here also silences any potential errors from the antecedent task
// (we still want to unblock the button if the ready-up fails).
if (t.Exception == null && t.Result) return;
.ContinueWith(_ => endOperation())
.CatchUnobservedExceptions();
// gameplay was not started; unblock button.
gameplayStartOperation?.Dispose();
gameplayStartOperation = null;
});
void endOperation()
{
readyClickOperation?.Dispose();
readyClickOperation = null;
}
}
private void onLoadRequested()
@ -235,10 +250,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
StartPlay(() => new MultiplayerPlayer(SelectedItem.Value, userIds));
Debug.Assert(gameplayStartOperation != null);
Debug.Assert(readyClickOperation != null);
gameplayStartOperation.Dispose();
gameplayStartOperation = null;
readyClickOperation.Dispose();
readyClickOperation = null;
}
protected override void Dispose(bool isDisposing)