Integrate ready button implementation

This commit is contained in:
Dan Balasescu 2022-03-17 18:43:04 +09:00
parent 461d41529b
commit da0ffab14e
6 changed files with 64 additions and 110 deletions

View File

@ -1,9 +1,7 @@
// 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 System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
@ -35,8 +33,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
private BeatmapManager beatmaps;
private RulesetStore rulesets;
private IDisposable readyClickOperation;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
@ -67,23 +63,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(200, 50),
OnReadyClick = () =>
{
readyClickOperation = OngoingOperationTracker.BeginOperation();
Task.Run(async () =>
{
if (MultiplayerClient.IsHost && MultiplayerClient.LocalUser?.State == MultiplayerUserState.Ready)
{
await MultiplayerClient.StartMatch();
return;
}
await MultiplayerClient.ToggleReady();
readyClickOperation.Dispose();
});
}
});
});
@ -208,9 +187,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddUntilStep("user waiting for load", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.WaitingForLoad);
AddAssert("ready button disabled", () => !button.ChildrenOfType<OsuButton>().Single().Enabled.Value);
AddStep("transitioned to gameplay", () => readyClickOperation.Dispose());
AddStep("finish gameplay", () =>
{
MultiplayerClient.ChangeUserState(MultiplayerClient.Room?.Users[0].UserID ?? 0, MultiplayerUserState.Loaded);

View File

@ -1,9 +1,7 @@
// 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 System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
@ -36,8 +34,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
private BeatmapManager beatmaps;
private RulesetStore rulesets;
private IDisposable readyClickOperation;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
@ -77,23 +73,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(200, 50),
OnReadyClick = () =>
{
readyClickOperation = OngoingOperationTracker.BeginOperation();
Task.Run(async () =>
{
if (MultiplayerClient.IsHost && MultiplayerClient.LocalUser?.State == MultiplayerUserState.Ready)
{
await MultiplayerClient.StartMatch();
return;
}
await MultiplayerClient.ToggleReady();
readyClickOperation.Dispose();
});
}
}
}
};

View File

@ -1,7 +1,6 @@
// 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.Graphics;
using osu.Framework.Graphics.Containers;
@ -12,13 +11,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
private const float ready_button_width = 600;
private const float spectate_button_width = 200;
public Action OnReadyClick
{
set => readyButton.OnReadyClick = value;
}
private readonly MultiplayerReadyButton readyButton;
public MultiplayerMatchFooter()
{
RelativeSizeAxes = Axes.Both;
@ -36,7 +28,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
RelativeSizeAxes = Axes.Both,
},
null,
readyButton = new MultiplayerReadyButton
new MultiplayerReadyButton
{
RelativeSizeAxes = Axes.Both,
},

View File

@ -2,7 +2,9 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
@ -19,28 +21,23 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
{
public class MultiplayerReadyButton : MultiplayerRoomComposite
{
public Action OnReadyClick
{
set => button.Action = value;
}
[Resolved]
private OsuColour colours { get; set; }
[Resolved]
private OngoingOperationTracker ongoingOperationTracker { get; set; }
private IBindable<bool> operationInProgress;
[CanBeNull]
private IDisposable clickOperation;
private Sample sampleReady;
private Sample sampleReadyAll;
private Sample sampleUnready;
private readonly ButtonWithTrianglesExposed button;
private int countReady;
private ScheduledDelegate readySampleDelegate;
private IBindable<bool> operationInProgress;
public MultiplayerReadyButton()
{
@ -48,6 +45,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
{
RelativeSizeAxes = Axes.Both,
Size = Vector2.One,
Action = onReadyClick,
Enabled = { Value = true },
};
}
@ -73,10 +71,56 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
protected override void OnRoomUpdated()
{
base.OnRoomUpdated();
updateState();
}
protected override void OnRoomLoadRequested()
{
base.OnRoomLoadRequested();
endOperation();
}
private void onReadyClick()
{
if (Room == null)
return;
Debug.Assert(clickOperation == null);
clickOperation = ongoingOperationTracker.BeginOperation();
// Ensure the current user becomes ready before being able to do anything else (start match, stop countdown, unready).
if (!isReady() || !Client.IsHost)
{
toggleReady();
return;
}
// And if a countdown isn't running, start the match.
startMatch();
bool isReady() => Client.LocalUser?.State == MultiplayerUserState.Ready || Client.LocalUser?.State == MultiplayerUserState.Spectating;
void toggleReady() => Client.ToggleReady().ContinueWith(_ => endOperation());
void startMatch() => 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.
});
}
private void endOperation()
{
clickOperation?.Dispose();
clickOperation = null;
}
private void updateState()
{
var localUser = Client.LocalUser;

View File

@ -1,11 +1,9 @@
// 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 System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -46,14 +44,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
[Resolved]
private MultiplayerClient client { get; set; }
[Resolved]
private OngoingOperationTracker ongoingOperationTracker { get; set; }
private readonly IBindable<bool> isConnected = new Bindable<bool>();
[CanBeNull]
private IDisposable readyClickOperation;
private AddItemButton addItemButton;
public MultiplayerMatchSubScreen(Room room)
@ -230,10 +222,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
this.Push(new MultiplayerMatchSongSelect(Room, itemToEdit));
}
protected override Drawable CreateFooter() => new MultiplayerMatchFooter
{
OnReadyClick = onReadyClick,
};
protected override Drawable CreateFooter() => new MultiplayerMatchFooter();
protected override RoomSettingsOverlay CreateRoomSettingsOverlay(Room room) => new MultiplayerMatchSettingsOverlay(room);
@ -331,38 +320,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
}
}
private void onReadyClick()
{
Debug.Assert(readyClickOperation == null);
readyClickOperation = ongoingOperationTracker.BeginOperation();
if (client.IsHost && (client.LocalUser?.State == MultiplayerUserState.Ready || client.LocalUser?.State == MultiplayerUserState.Spectating))
{
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 => endOperation());
void endOperation()
{
readyClickOperation?.Dispose();
readyClickOperation = null;
}
}
private void onRoomUpdated()
{
// may happen if the client is kicked or otherwise removed from the room.
@ -418,9 +375,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
return;
StartPlay();
readyClickOperation?.Dispose();
readyClickOperation = null;
}
protected override Screen CreateGameplayScreen()

View File

@ -21,6 +21,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
base.LoadComplete();
Client.RoomUpdated += invokeOnRoomUpdated;
Client.LoadRequested += invokeOnRoomLoadRequested;
Client.UserLeft += invokeUserLeft;
Client.UserKicked += invokeUserKicked;
Client.UserJoined += invokeUserJoined;
@ -38,6 +39,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
private void invokeItemAdded(MultiplayerPlaylistItem item) => Schedule(() => PlaylistItemAdded(item));
private void invokeItemRemoved(long item) => Schedule(() => PlaylistItemRemoved(item));
private void invokeItemChanged(MultiplayerPlaylistItem item) => Schedule(() => PlaylistItemChanged(item));
private void invokeOnRoomLoadRequested() => Scheduler.AddOnce(OnRoomLoadRequested);
/// <summary>
/// Invoked when a user has joined the room.
@ -94,6 +96,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
{
}
/// <summary>
/// Invoked when the room requests the local user to load into gameplay.
/// </summary>
protected virtual void OnRoomLoadRequested()
{
}
protected override void Dispose(bool isDisposing)
{
if (Client != null)