diff --git a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs index df8f63f6ed..fd43674b3b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs @@ -95,10 +95,10 @@ namespace osu.Game.Tests.Visual.Multiplayer protected void RunGameplay() { AddUntilStep("wait for idle", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Idle); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("wait for ready", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Ready); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("wait for player", () => multiplayerComponents.CurrentScreen is Player player && player.IsLoaded); AddStep("exit player", () => multiplayerComponents.MultiplayerScreen.MakeCurrent()); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs index 266ac60168..582dacb332 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs @@ -102,10 +102,10 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID); AddUntilStep("wait for idle", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Idle); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("wait for ready", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Ready); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("wait for player", () => CurrentScreen is Player player && player.IsLoaded); AddAssert("ruleset is correct", () => ((Player)CurrentScreen).Ruleset.Value.Equals(new OsuRuleset().RulesetInfo)); @@ -119,10 +119,10 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID); AddUntilStep("wait for idle", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Idle); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("wait for ready", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Ready); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("wait for player", () => CurrentScreen is Player player && player.IsLoaded); AddAssert("mods are correct", () => !((Player)CurrentScreen).Mods.Value.Any()); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs similarity index 79% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs index 7bf03caa88..4e54740a69 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs @@ -27,9 +27,9 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerReadyButton : MultiplayerTestScene + public class TestSceneMatchStartControl : MultiplayerTestScene { - private MultiplayerReadyButton button; + private MatchStartControl control; private BeatmapSetInfo importedSet; private readonly Bindable selectedItem = new Bindable(); @@ -62,7 +62,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Child = new PopoverContainer { RelativeSizeAxes = Axes.Both, - Child = button = new MultiplayerReadyButton + Child = control = new MatchStartControl { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -74,17 +74,17 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestStartWithCountdown() { - ClickButtonWhenEnabled(); - AddUntilStep("countdown button shown", () => this.ChildrenOfType().SingleOrDefault()?.IsPresent == true); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); + AddUntilStep("countdown button shown", () => this.ChildrenOfType().SingleOrDefault()?.IsPresent == true); + ClickButtonWhenEnabled(); AddStep("click the first countdown button", () => { - var popoverButton = this.ChildrenOfType().First(); + var popoverButton = this.ChildrenOfType().First(); InputManager.MoveMouseTo(popoverButton); InputManager.Click(MouseButton.Left); }); - AddAssert("countdown button not visible", () => !this.ChildrenOfType().Single().IsPresent); + AddAssert("countdown button not visible", () => !this.ChildrenOfType().Single().IsPresent); AddStep("finish countdown", () => MultiplayerClient.FinishCountdown()); AddUntilStep("match started", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.WaitingForLoad); } @@ -92,17 +92,17 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestCancelCountdown() { - ClickButtonWhenEnabled(); - AddUntilStep("countdown button shown", () => this.ChildrenOfType().SingleOrDefault()?.IsPresent == true); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); + AddUntilStep("countdown button shown", () => this.ChildrenOfType().SingleOrDefault()?.IsPresent == true); + ClickButtonWhenEnabled(); AddStep("click the first countdown button", () => { - var popoverButton = this.ChildrenOfType().First(); + var popoverButton = this.ChildrenOfType().First(); InputManager.MoveMouseTo(popoverButton); InputManager.Click(MouseButton.Left); }); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddStep("finish countdown", () => MultiplayerClient.FinishCountdown()); AddUntilStep("match not started", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Ready); @@ -119,10 +119,10 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("start with countdown", () => MultiplayerClient.SendMatchRequest(new StartMatchCountdownRequest { Delay = TimeSpan.FromMinutes(2) }).WaitSafely()); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("user is ready", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Ready); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("user is idle", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Idle); } @@ -132,25 +132,25 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("set spectating", () => MultiplayerClient.ChangeUserState(API.LocalUser.Value.OnlineID, MultiplayerUserState.Spectating)); AddUntilStep("local user is spectating", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Spectating); - AddAssert("countdown button is visible", () => this.ChildrenOfType().Single().IsPresent); - AddAssert("countdown button disabled", () => !this.ChildrenOfType().Single().Enabled.Value); + AddAssert("countdown button is visible", () => this.ChildrenOfType().Single().IsPresent); + AddAssert("countdown button disabled", () => !this.ChildrenOfType().Single().Enabled.Value); AddStep("add second user", () => MultiplayerClient.AddUser(new APIUser { Id = 2, Username = "Another user" })); - AddAssert("countdown button disabled", () => !this.ChildrenOfType().Single().Enabled.Value); + AddAssert("countdown button disabled", () => !this.ChildrenOfType().Single().Enabled.Value); AddStep("set second user ready", () => MultiplayerClient.ChangeUserState(2, MultiplayerUserState.Ready)); - AddAssert("countdown button enabled", () => this.ChildrenOfType().Single().Enabled.Value); + AddAssert("countdown button enabled", () => this.ChildrenOfType().Single().Enabled.Value); } [Test] public void TestSpectatingDuringCountdownWithNoReadyUsersCancelsCountdown() { - ClickButtonWhenEnabled(); - AddUntilStep("countdown button shown", () => this.ChildrenOfType().SingleOrDefault()?.IsPresent == true); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); + AddUntilStep("countdown button shown", () => this.ChildrenOfType().SingleOrDefault()?.IsPresent == true); + ClickButtonWhenEnabled(); AddStep("click the first countdown button", () => { - var popoverButton = this.ChildrenOfType().First(); + var popoverButton = this.ChildrenOfType().First(); InputManager.MoveMouseTo(popoverButton); InputManager.Click(MouseButton.Left); }); @@ -168,12 +168,12 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("add second user", () => MultiplayerClient.AddUser(new APIUser { Id = 2, Username = "Another user" })); AddStep("set second user ready", () => MultiplayerClient.ChangeUserState(2, MultiplayerUserState.Ready)); - ClickButtonWhenEnabled(); - AddUntilStep("countdown button shown", () => this.ChildrenOfType().SingleOrDefault()?.IsPresent == true); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); + AddUntilStep("countdown button shown", () => this.ChildrenOfType().SingleOrDefault()?.IsPresent == true); + ClickButtonWhenEnabled(); AddStep("click the first countdown button", () => { - var popoverButton = this.ChildrenOfType().First(); + var popoverButton = this.ChildrenOfType().First(); InputManager.MoveMouseTo(popoverButton); InputManager.Click(MouseButton.Left); }); @@ -181,7 +181,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("set spectating", () => MultiplayerClient.ChangeUserState(API.LocalUser.Value.OnlineID, MultiplayerUserState.Spectating)); AddUntilStep("local user is spectating", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Spectating); - AddAssert("ready button enabled", () => this.ChildrenOfType().Single().Enabled.Value); + AddAssert("ready button enabled", () => this.ChildrenOfType().Single().Enabled.Value); } [Test] @@ -199,7 +199,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("transfer host to local user", () => MultiplayerClient.TransferHost(API.LocalUser.Value.OnlineID)); AddUntilStep("local user is host", () => MultiplayerClient.Room?.Host?.Equals(MultiplayerClient.LocalUser) == true); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("local user became ready", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Ready); AddAssert("countdown still active", () => MultiplayerClient.Room?.Countdown != null); } @@ -211,7 +211,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("ensure ready button enabled", () => { - readyButton = button.ChildrenOfType().Single(); + readyButton = control.ChildrenOfType().Single(); return readyButton.Enabled.Value; }); @@ -230,10 +230,10 @@ namespace osu.Game.Tests.Visual.Multiplayer MultiplayerClient.TransferHost(2); }); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("user is ready", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Ready); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("user is idle", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Idle); } @@ -249,7 +249,7 @@ namespace osu.Game.Tests.Visual.Multiplayer MultiplayerClient.AddUser(new APIUser { Id = 2, Username = "Another user" }); }); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("user is ready", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Ready); verifyGameplayStartFlow(); @@ -264,7 +264,7 @@ namespace osu.Game.Tests.Visual.Multiplayer MultiplayerClient.TransferHost(2); }); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddStep("make user host", () => MultiplayerClient.TransferHost(MultiplayerClient.Room?.Users[0].UserID ?? 0)); verifyGameplayStartFlow(); @@ -279,14 +279,14 @@ namespace osu.Game.Tests.Visual.Multiplayer MultiplayerClient.AddUser(new APIUser { Id = 2, Username = "Another user" }); }); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("user is ready", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Ready); AddStep("transfer host", () => MultiplayerClient.TransferHost(MultiplayerClient.Room?.Users[1].UserID ?? 0)); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("user is idle (match not started)", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Idle); - AddAssert("ready button enabled", () => button.ChildrenOfType().Single().Enabled.Value); + AddAssert("ready button enabled", () => control.ChildrenOfType().Single().Enabled.Value); } [TestCase(true)] @@ -304,7 +304,7 @@ namespace osu.Game.Tests.Visual.Multiplayer if (!isHost) AddStep("transfer host", () => MultiplayerClient.TransferHost(2)); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddRepeatStep("change user ready state", () => { @@ -322,7 +322,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private void verifyGameplayStartFlow() { AddUntilStep("user is ready", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Ready); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("user waiting for load", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.WaitingForLoad); AddStep("finish gameplay", () => @@ -331,7 +331,7 @@ namespace osu.Game.Tests.Visual.Multiplayer MultiplayerClient.ChangeUserState(MultiplayerClient.Room?.Users[0].UserID ?? 0, MultiplayerUserState.FinishedPlay); }); - AddUntilStep("ready button enabled", () => button.ChildrenOfType().Single().Enabled.Value); + AddUntilStep("ready button enabled", () => control.ChildrenOfType().Single().Enabled.Value); } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 6300dfa381..d0765fc4b3 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -41,6 +41,7 @@ using osu.Game.Screens.Ranking; using osu.Game.Screens.Spectate; using osu.Game.Tests.Resources; using osuTK.Input; +using ReadyButton = osu.Game.Screens.OnlinePlay.Components.ReadyButton; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs index a51d4678fe..850a115f4c 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs @@ -145,7 +145,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for spectating user state", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Spectating); - ClickButtonWhenEnabled(); + ClickButtonWhenEnabled(); AddUntilStep("match started", () => MultiplayerClient.Room?.State == MultiplayerRoomState.WaitingForLoad); } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs index 13c9e021db..07ac580276 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs @@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Multiplayer public class TestSceneMultiplayerSpectateButton : MultiplayerTestScene { private MultiplayerSpectateButton spectateButton; - private MultiplayerReadyButton readyButton; + private MatchStartControl startControl; private readonly Bindable selectedItem = new Bindable(); @@ -72,7 +72,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Origin = Anchor.Centre, Size = new Vector2(200, 50), }, - readyButton = new MultiplayerReadyButton + startControl = new MatchStartControl { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -146,6 +146,6 @@ namespace osu.Game.Tests.Visual.Multiplayer => AddUntilStep($"spectate button {(shouldBeEnabled ? "is" : "is not")} enabled", () => spectateButton.ChildrenOfType().Single().Enabled.Value == shouldBeEnabled); private void assertReadyButtonEnablement(bool shouldBeEnabled) - => AddUntilStep($"ready button {(shouldBeEnabled ? "is" : "is not")} enabled", () => readyButton.ChildrenOfType().Single().Enabled.Value == shouldBeEnabled); + => AddUntilStep($"ready button {(shouldBeEnabled ? "is" : "is not")} enabled", () => startControl.ChildrenOfType().Single().Enabled.Value == shouldBeEnabled); } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/CountdownButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/CountdownButton.cs new file mode 100644 index 0000000000..e598f6670c --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/CountdownButton.cs @@ -0,0 +1,87 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using Humanizer; +using osu.Framework.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match +{ + public class CountdownButton : IconButton, IHasPopover + { + private static readonly TimeSpan[] available_delays = + { + TimeSpan.FromSeconds(10), + TimeSpan.FromSeconds(30), + TimeSpan.FromMinutes(1), + TimeSpan.FromMinutes(2) + }; + + public new Action Action; + + private readonly Drawable background; + + public CountdownButton() + { + Icon = FontAwesome.Solid.CaretDown; + IconScale = new Vector2(0.6f); + + Add(background = new Box + { + RelativeSizeAxes = Axes.Both, + Depth = float.MaxValue + }); + + base.Action = this.ShowPopover; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Green; + } + + public Popover GetPopover() + { + var flow = new FillFlowContainer + { + Width = 200, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(2), + }; + + foreach (var duration in available_delays) + { + flow.Add(new PopoverButton + { + RelativeSizeAxes = Axes.X, + Text = $"Start match in {duration.Humanize()}", + BackgroundColour = background.Colour, + Action = () => + { + Action(duration); + this.HidePopover(); + } + }); + } + + return new OsuPopover { Child = flow }; + } + + public class PopoverButton : OsuButton + { + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs similarity index 51% rename from osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs index 4c4cc87f6d..d97ac601d5 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs @@ -4,32 +4,21 @@ using System; using System.Diagnostics; using System.Linq; -using Humanizer; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; -using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Localisation; using osu.Framework.Threading; -using osu.Game.Graphics; -using osu.Game.Graphics.Backgrounds; -using osu.Game.Graphics.UserInterface; -using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.Countdown; using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { - public class MultiplayerReadyButton : MultiplayerRoomComposite + public class MatchStartControl : MultiplayerRoomComposite { [Resolved] private OngoingOperationTracker ongoingOperationTracker { get; set; } @@ -47,7 +36,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private ScheduledDelegate readySampleDelegate; private IBindable operationInProgress; - public MultiplayerReadyButton() + public MatchStartControl() { InternalChild = new GridContainer { @@ -231,220 +220,5 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match countReady = newCountReady; }); } - - public class ReadyButton : Components.ReadyButton - { - public new Triangles Triangles => base.Triangles; - - [Resolved] - private MultiplayerClient multiplayerClient { get; set; } - - [Resolved] - private OsuColour colours { get; set; } - - [CanBeNull] - private MultiplayerRoom room => multiplayerClient.Room; - - protected override void LoadComplete() - { - base.LoadComplete(); - - multiplayerClient.RoomUpdated += () => Scheduler.AddOnce(onRoomUpdated); - onRoomUpdated(); - } - - protected override void Update() - { - base.Update(); - - if (room?.Countdown != null) - { - // Update the countdown timer. - onRoomUpdated(); - } - } - - private void onRoomUpdated() - { - updateButtonText(); - updateButtonColour(); - } - - private void updateButtonText() - { - if (room == null) - { - Text = "Ready"; - return; - } - - var localUser = multiplayerClient.LocalUser; - - int countReady = room.Users.Count(u => u.State == MultiplayerUserState.Ready); - int countTotal = room.Users.Count(u => u.State != MultiplayerUserState.Spectating); - string countText = $"({countReady} / {countTotal} ready)"; - - if (room.Countdown != null) - { - string countdownText = $"Starting in {room.Countdown.EndTime - DateTimeOffset.Now:mm\\:ss}"; - - switch (localUser?.State) - { - default: - Text = $"Ready ({countdownText.ToLowerInvariant()})"; - break; - - case MultiplayerUserState.Spectating: - case MultiplayerUserState.Ready: - Text = $"{countdownText} {countText}"; - break; - } - } - else - { - switch (localUser?.State) - { - default: - Text = "Ready"; - break; - - case MultiplayerUserState.Spectating: - case MultiplayerUserState.Ready: - Text = room.Host?.Equals(localUser) == true - ? $"Start match {countText}" - : $"Waiting for host... {countText}"; - - break; - } - } - } - - private void updateButtonColour() - { - if (room == null) - { - setGreen(); - return; - } - - var localUser = multiplayerClient.LocalUser; - - switch (localUser?.State) - { - default: - setGreen(); - break; - - case MultiplayerUserState.Spectating: - case MultiplayerUserState.Ready: - if (room?.Host?.Equals(localUser) == true && room.Countdown == null) - setGreen(); - else - setYellow(); - - break; - } - - void setYellow() - { - BackgroundColour = colours.YellowDark; - Triangles.ColourDark = colours.YellowDark; - Triangles.ColourLight = colours.Yellow; - } - - void setGreen() - { - BackgroundColour = colours.Green; - Triangles.ColourDark = colours.Green; - Triangles.ColourLight = colours.GreenLight; - } - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - if (multiplayerClient != null) - multiplayerClient.RoomUpdated -= onRoomUpdated; - } - - public override LocalisableString TooltipText - { - get - { - if (room?.Countdown != null && multiplayerClient.IsHost && multiplayerClient.LocalUser?.State == MultiplayerUserState.Ready) - return "Cancel countdown"; - - return base.TooltipText; - } - } - } - - public class CountdownButton : IconButton, IHasPopover - { - private static readonly TimeSpan[] available_delays = - { - TimeSpan.FromSeconds(10), - TimeSpan.FromSeconds(30), - TimeSpan.FromMinutes(1), - TimeSpan.FromMinutes(2) - }; - - public new Action Action; - - private readonly Drawable background; - - public CountdownButton() - { - Icon = FontAwesome.Solid.CaretDown; - IconScale = new Vector2(0.6f); - - Add(background = new Box - { - RelativeSizeAxes = Axes.Both, - Depth = float.MaxValue - }); - - base.Action = this.ShowPopover; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - background.Colour = colours.Green; - } - - public Popover GetPopover() - { - var flow = new FillFlowContainer - { - Width = 200, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(2), - }; - - foreach (var duration in available_delays) - { - flow.Add(new PopoverButton - { - RelativeSizeAxes = Axes.X, - Text = $"Start match in {duration.Humanize()}", - BackgroundColour = background.Colour, - Action = () => - { - Action(duration); - this.HidePopover(); - } - }); - } - - return new OsuPopover { Child = flow }; - } - - public class PopoverButton : OsuButton - { - } - } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs index b4fce5903b..a07c95bca8 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs @@ -28,7 +28,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match RelativeSizeAxes = Axes.Both, }, null, - new MultiplayerReadyButton + new MatchStartControl { RelativeSizeAxes = Axes.Both, }, diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/ReadyButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/ReadyButton.cs new file mode 100644 index 0000000000..8e3a9f9349 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/ReadyButton.cs @@ -0,0 +1,162 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Backgrounds; +using osu.Game.Online.Multiplayer; + +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match +{ + public class ReadyButton : Components.ReadyButton + { + public new Triangles Triangles => base.Triangles; + + [Resolved] + private MultiplayerClient multiplayerClient { get; set; } + + [Resolved] + private OsuColour colours { get; set; } + + [CanBeNull] + private MultiplayerRoom room => multiplayerClient.Room; + + protected override void LoadComplete() + { + base.LoadComplete(); + + multiplayerClient.RoomUpdated += () => Scheduler.AddOnce(onRoomUpdated); + onRoomUpdated(); + } + + protected override void Update() + { + base.Update(); + + if (room?.Countdown != null) + { + // Update the countdown timer. + onRoomUpdated(); + } + } + + private void onRoomUpdated() + { + updateButtonText(); + updateButtonColour(); + } + + private void updateButtonText() + { + if (room == null) + { + Text = "Ready"; + return; + } + + var localUser = multiplayerClient.LocalUser; + + int countReady = room.Users.Count(u => u.State == MultiplayerUserState.Ready); + int countTotal = room.Users.Count(u => u.State != MultiplayerUserState.Spectating); + string countText = $"({countReady} / {countTotal} ready)"; + + if (room.Countdown != null) + { + string countdownText = $"Starting in {room.Countdown.EndTime - DateTimeOffset.Now:mm\\:ss}"; + + switch (localUser?.State) + { + default: + Text = $"Ready ({countdownText.ToLowerInvariant()})"; + break; + + case MultiplayerUserState.Spectating: + case MultiplayerUserState.Ready: + Text = $"{countdownText} {countText}"; + break; + } + } + else + { + switch (localUser?.State) + { + default: + Text = "Ready"; + break; + + case MultiplayerUserState.Spectating: + case MultiplayerUserState.Ready: + Text = room.Host?.Equals(localUser) == true + ? $"Start match {countText}" + : $"Waiting for host... {countText}"; + + break; + } + } + } + + private void updateButtonColour() + { + if (room == null) + { + setGreen(); + return; + } + + var localUser = multiplayerClient.LocalUser; + + switch (localUser?.State) + { + default: + setGreen(); + break; + + case MultiplayerUserState.Spectating: + case MultiplayerUserState.Ready: + if (room?.Host?.Equals(localUser) == true && room.Countdown == null) + setGreen(); + else + setYellow(); + + break; + } + + void setYellow() + { + BackgroundColour = colours.YellowDark; + Triangles.ColourDark = colours.YellowDark; + Triangles.ColourLight = colours.Yellow; + } + + void setGreen() + { + BackgroundColour = colours.Green; + Triangles.ColourDark = colours.Green; + Triangles.ColourLight = colours.GreenLight; + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (multiplayerClient != null) + multiplayerClient.RoomUpdated -= onRoomUpdated; + } + + public override LocalisableString TooltipText + { + get + { + if (room?.Countdown != null && multiplayerClient.IsHost && multiplayerClient.LocalUser?.State == MultiplayerUserState.Ready) + return "Cancel countdown"; + + return base.TooltipText; + } + } + } +}