diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils_Reposition.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.Reposition.cs similarity index 100% rename from osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils_Reposition.cs rename to osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.Reposition.cs diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapPanel.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapPanel.cs deleted file mode 100644 index c46beba037..0000000000 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapPanel.cs +++ /dev/null @@ -1,28 +0,0 @@ -// 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.Graphics; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick; -using osu.Game.Tests.Visual.Multiplayer; -using osuTK; - -namespace osu.Game.Tests.Visual.Matchmaking -{ - public partial class TestSceneBeatmapPanel : MultiplayerTestScene - { - public override void SetUpSteps() - { - base.SetUpSteps(); - - AddStep("add beatmap panel", () => - { - Child = new BeatmapPanel(CreateAPIBeatmap()) - { - Size = new Vector2(300, 70), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }; - }); - } - } -} diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectionOverlay.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectionOverlay.cs deleted file mode 100644 index 4e596d65cc..0000000000 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectionOverlay.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Testing; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick; -using osuTK; - -namespace osu.Game.Tests.Visual.Matchmaking -{ - public partial class TestSceneBeatmapSelectionOverlay : OsuTestScene - { - private BeatmapSelectionOverlay selectionOverlay = null!; - - [SetUpSteps] - public void SetupSteps() - { - AddStep("add drawable", () => Child = new Container - { - Width = 100, - AutoSizeAxes = Axes.Y, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(2), - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0.1f, - }, - selectionOverlay = new BeatmapSelectionOverlay - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - } - } - }); - } - - [Test] - public void TestSelectionOverlay() - { - AddStep("add maarvin", () => selectionOverlay.AddUser(new APIUser - { - Id = 6411631, - Username = "Maarvin", - }, isOwnUser: true)); - AddStep("add peppy", () => selectionOverlay.AddUser(new APIUser - { - Id = 2, - Username = "peppy", - }, false)); - AddStep("add smogipoo", () => selectionOverlay.AddUser(new APIUser - { - Id = 1040328, - Username = "smoogipoo", - }, false)); - AddStep("remove smogipoo", () => selectionOverlay.RemoveUser(1040328)); - AddStep("remove peppy", () => selectionOverlay.RemoveUser(2)); - AddStep("remove maarvin", () => selectionOverlay.RemoveUser(6411631)); - } - } -} diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneIdleScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneIdleScreen.cs index 174a77390e..08df61d629 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneIdleScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneIdleScreen.cs @@ -11,7 +11,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Idle; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match.RoundWarmup; using osu.Game.Tests.Visual.Multiplayer; using osuTK; @@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.Matchmaking return (user, 0); }).ToArray(); - Child = new ScreenStack(new IdleScreen()) + Child = new ScreenStack(new SubScreenRoundWarmup()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingCloud.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingCloud.cs index c25057c84b..d656971b5a 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingCloud.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingCloud.cs @@ -6,20 +6,20 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Utils; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Screens.OnlinePlay.Matchmaking; +using osu.Game.Screens.OnlinePlay.Matchmaking.Queue; using osu.Game.Users; namespace osu.Game.Tests.Visual.Matchmaking { public partial class TestSceneMatchmakingCloud : OsuTestScene { - private MatchmakingCloud cloud = null!; + private CloudVisualisation cloud = null!; protected override void LoadComplete() { base.LoadComplete(); - Child = cloud = new MatchmakingCloud + Child = cloud = new CloudVisualisation { RelativeSizeAxes = Axes.Both, }; diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingPoolSelector.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingPoolSelector.cs index 442a06606b..5971cd9091 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingPoolSelector.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingPoolSelector.cs @@ -3,7 +3,7 @@ using osu.Framework.Graphics; using osu.Game.Online.Matchmaking; -using osu.Game.Screens.OnlinePlay.Matchmaking; +using osu.Game.Screens.OnlinePlay.Matchmaking.Queue; using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.Visual.Matchmaking @@ -14,7 +14,7 @@ namespace osu.Game.Tests.Visual.Matchmaking { base.SetUpSteps(); - AddStep("add selector", () => Child = new MatchmakingPoolSelector + AddStep("add selector", () => Child = new PoolSelector { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingQueueScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingQueueScreen.cs index 72eba6e1c8..5193d58ee6 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingQueueScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingQueueScreen.cs @@ -7,8 +7,8 @@ using osu.Framework.Allocation; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Screens.OnlinePlay.Matchmaking; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens; +using osu.Game.Screens.OnlinePlay.Matchmaking.Intro; +using osu.Game.Screens.OnlinePlay.Matchmaking.Queue; using osu.Game.Tests.Visual.Multiplayer; using osu.Game.Users; @@ -17,16 +17,16 @@ namespace osu.Game.Tests.Visual.Matchmaking public partial class TestSceneMatchmakingQueueScreen : MultiplayerTestScene { [Cached] - private readonly MatchmakingController controller = new MatchmakingController(); + private readonly QueueController controller = new QueueController(); - private MatchmakingQueueScreen? queueScreen => Stack.CurrentScreen as MatchmakingQueueScreen; + private ScreenQueue? queueScreen => Stack.CurrentScreen as ScreenQueue; [SetUpSteps] public override void SetUpSteps() { base.SetUpSteps(); - AddStep("load screen", () => LoadScreen(new MatchmakingIntroScreen())); + AddStep("load screen", () => LoadScreen(new IntroScreen())); } [Test] @@ -44,15 +44,15 @@ namespace osu.Game.Tests.Visual.Matchmaking }).ToArray(); }); - AddStep("change state to idle", () => queueScreen!.SetState(MatchmakingQueueScreen.MatchmakingScreenState.Idle)); + AddStep("change state to idle", () => queueScreen!.SetState(ScreenQueue.MatchmakingScreenState.Idle)); - AddStep("change state to queueing", () => queueScreen!.SetState(MatchmakingQueueScreen.MatchmakingScreenState.Queueing)); + AddStep("change state to queueing", () => queueScreen!.SetState(ScreenQueue.MatchmakingScreenState.Queueing)); - AddStep("change state to found match", () => queueScreen!.SetState(MatchmakingQueueScreen.MatchmakingScreenState.PendingAccept)); + AddStep("change state to found match", () => queueScreen!.SetState(ScreenQueue.MatchmakingScreenState.PendingAccept)); - AddStep("change state to waiting for room", () => queueScreen!.SetState(MatchmakingQueueScreen.MatchmakingScreenState.AcceptedWaitingForRoom)); + AddStep("change state to waiting for room", () => queueScreen!.SetState(ScreenQueue.MatchmakingScreenState.AcceptedWaitingForRoom)); - AddStep("change state to in room", () => queueScreen!.SetState(MatchmakingQueueScreen.MatchmakingScreenState.InRoom)); + AddStep("change state to in room", () => queueScreen!.SetState(ScreenQueue.MatchmakingScreenState.InRoom)); } } } diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreen.cs index d8767fbe85..2269e1c76c 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreen.cs @@ -16,7 +16,7 @@ using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; -using osu.Game.Screens.OnlinePlay.Matchmaking; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match; using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.Visual.Matchmaking @@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Matchmaking private const int beatmap_count = 50; private MultiplayerRoomUser[] users = null!; - private MatchmakingScreen screen = null!; + private ScreenMatchmaking screen = null!; public override void SetUpSteps() { @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual.Matchmaking StarRating = i / 10.0 }).ToArray(); - LoadScreen(screen = new MatchmakingScreen(new MultiplayerRoom(0) + LoadScreen(screen = new ScreenMatchmaking(new MultiplayerRoom(0) { Users = users, Playlist = beatmaps diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreenStack.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreenStack.cs index 94547dd115..ba7e27b753 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreenStack.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingScreenStack.cs @@ -11,7 +11,7 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Scoring; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match; using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.Visual.Matchmaking @@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.Matchmaking AddStep("add carousel", () => { - Child = new MatchmakingScreenStack + Child = new ScreenMatchmaking.ScreenStack { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneRoomStatisticPanel.cs b/osu.Game.Tests/Visual/Matchmaking/TestScenePanelRoomAward.cs similarity index 66% rename from osu.Game.Tests/Visual/Matchmaking/TestSceneRoomStatisticPanel.cs rename to osu.Game.Tests/Visual/Matchmaking/TestScenePanelRoomAward.cs index 494f9b6517..494d1c411a 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneRoomStatisticPanel.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestScenePanelRoomAward.cs @@ -2,18 +2,18 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Results; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match.Results; using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestSceneRoomStatisticPanel : MultiplayerTestScene + public partial class TestScenePanelRoomAward : MultiplayerTestScene { public override void SetUpSteps() { base.SetUpSteps(); - AddStep("add statistic", () => Child = new RoomStatisticPanel("Statistic description", 1) + AddStep("add statistic", () => Child = new PanelRoomAward("Statistic description", 1) { Anchor = Anchor.Centre, Origin = Anchor.Centre diff --git a/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs index 1c12b4d2d0..e894616f9e 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestScenePickScreen.cs @@ -10,7 +10,7 @@ using osu.Framework.Utils; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect; using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.Visual.Matchmaking @@ -79,9 +79,9 @@ namespace osu.Game.Tests.Visual.Matchmaking { var selectedItems = new List(); - PickScreen screen = null!; + SubScreenBeatmapSelect screen = null!; - AddStep("add screen", () => Child = new ScreenStack(screen = new PickScreen())); + AddStep("add screen", () => Child = new ScreenStack(screen = new SubScreenBeatmapSelect())); AddStep("select maps", () => { diff --git a/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanel.cs b/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanel.cs index 805e83a76d..a7c14cfd94 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanel.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanel.cs @@ -8,7 +8,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; -using osu.Game.Screens.OnlinePlay.Matchmaking; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match; using osu.Game.Tests.Visual.Multiplayer; using osu.Game.Users; @@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual.Matchmaking { public partial class TestScenePlayerPanel : MultiplayerTestScene { - private PlayerPanel panel = null!; + private MatchmakingUserPanel panel = null!; public override void SetUpSteps() { @@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.Matchmaking AddStep("join room", () => JoinRoom(CreateDefaultRoom(MatchType.Matchmaking))); WaitForJoined(); - AddStep("add panel", () => Child = panel = new PlayerPanel(new MultiplayerRoomUser(1) + AddStep("add panel", () => Child = panel = new MatchmakingUserPanel(new MultiplayerRoomUser(1) { User = new APIUser { diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneResultsScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneResultsScreen.cs index 6b3d42694b..d445c46a48 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneResultsScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneResultsScreen.cs @@ -10,7 +10,7 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Scoring; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Results; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match.Results; using osu.Game.Tests.Visual.Multiplayer; using osuTK; @@ -29,7 +29,7 @@ namespace osu.Game.Tests.Visual.Matchmaking AddStep("add results screen", () => { - Child = new ScreenStack(new ResultsScreen()) + Child = new ScreenStack(new SubScreenResults()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneRoundResultsScreen.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneRoundResultsScreen.cs index 561c994945..cbdbd33158 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneRoundResultsScreen.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneRoundResultsScreen.cs @@ -13,7 +13,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.RoundResults; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match.RoundResults; using osu.Game.Tests.Visual.Multiplayer; using osuTK; @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Matchmaking AddStep("load screen", () => { - Child = new ScreenStack(new RoundResultsScreen()) + Child = new ScreenStack(new SubScreenRoundResults()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectionGrid.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneSelectionGrid.cs similarity index 93% rename from osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectionGrid.cs rename to osu.Game.Tests/Visual/Matchmaking/TestSceneSelectionGrid.cs index e74bcda33d..6fba5af070 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectionGrid.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneSelectionGrid.cs @@ -11,17 +11,17 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.Rooms; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect; using osu.Game.Tests.Visual.OnlinePlay; using osuTK; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestSceneBeatmapSelectionGrid : OnlinePlayTestScene + public partial class TestSceneSelectionGrid : OnlinePlayTestScene { private MultiplayerPlaylistItem[] items = null!; - private BeatmapSelectionGrid grid = null!; + private SelectionGrid grid = null!; [Resolved] private BeatmapManager beatmapManager { get; set; } = null!; @@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.Matchmaking { base.SetUpSteps(); - AddStep("add grid", () => Child = grid = new BeatmapSelectionGrid + AddStep("add grid", () => Child = grid = new SelectionGrid { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, @@ -154,7 +154,7 @@ namespace osu.Game.Tests.Visual.Matchmaking var (candidateItems, _) = pickRandomItems(count); grid.TransferCandidatePanelsToRollContainer(candidateItems); - grid.Delay(BeatmapSelectionGrid.ARRANGE_DELAY) + grid.Delay(SelectionGrid.ARRANGE_DELAY) .Schedule(() => grid.ArrangeItemsForRollAnimation()); }); @@ -162,7 +162,7 @@ namespace osu.Game.Tests.Visual.Matchmaking AddStep("display roll order", () => { - var panels = grid.ChildrenOfType().ToArray(); + var panels = grid.ChildrenOfType().ToArray(); for (int i = 0; i < panels.Length; i++) { diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectionPanel.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneSelectionPanel.cs similarity index 85% rename from osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectionPanel.cs rename to osu.Game.Tests/Visual/Matchmaking/TestSceneSelectionPanel.cs index addb0ed3a0..6745802b30 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneBeatmapSelectionPanel.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneSelectionPanel.cs @@ -7,12 +7,12 @@ using osu.Framework.Graphics; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Overlays; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect; using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestSceneBeatmapSelectionPanel : MultiplayerTestScene + public partial class TestSceneSelectionPanel : MultiplayerTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); @@ -20,9 +20,9 @@ namespace osu.Game.Tests.Visual.Matchmaking [Test] public void TestBeatmapPanel() { - BeatmapSelectionPanel? panel = null; + SelectionPanel? panel = null; - AddStep("add panel", () => Child = panel = new BeatmapSelectionPanel(new MultiplayerPlaylistItem()) + AddStep("add panel", () => Child = panel = new SelectionPanel(new MultiplayerPlaylistItem()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneStageDisplay.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneStageDisplay.cs index 9fde9f156c..dc4f09c555 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneStageDisplay.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneStageDisplay.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; using osu.Game.Overlays; -using osu.Game.Screens.OnlinePlay.Matchmaking; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match; using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.Visual.Matchmaking diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneStageBubble.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneStageSegment.cs similarity index 84% rename from osu.Game.Tests/Visual/Matchmaking/TestSceneStageBubble.cs rename to osu.Game.Tests/Visual/Matchmaking/TestSceneStageSegment.cs index a317121335..c9d74cc99d 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneStageBubble.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneStageSegment.cs @@ -9,12 +9,12 @@ using osu.Game.Online.Matchmaking; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; -using osu.Game.Screens.OnlinePlay.Matchmaking; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match; using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestSceneStageBubble : MultiplayerTestScene + public partial class TestSceneStageSegment : MultiplayerTestScene { public override void SetUpSteps() { @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Matchmaking AddStep("join room", () => JoinRoom(CreateDefaultRoom(MatchType.Matchmaking))); WaitForJoined(); - AddStep("add bubble", () => Child = new StageBubble(null, MatchmakingStage.RoundWarmupTime, "Next Round") + AddStep("add bubble", () => Child = new StageDisplay.StageSegment(null, MatchmakingStage.RoundWarmupTime, "Next Round") { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneStageText.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneStatusText.cs similarity index 84% rename from osu.Game.Tests/Visual/Matchmaking/TestSceneStageText.cs rename to osu.Game.Tests/Visual/Matchmaking/TestSceneStatusText.cs index bc465f53a4..26380152b1 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestSceneStageText.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneStatusText.cs @@ -7,12 +7,12 @@ using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; -using osu.Game.Screens.OnlinePlay.Matchmaking; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match; using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestSceneStageText : MultiplayerTestScene + public partial class TestSceneStatusText : MultiplayerTestScene { public override void SetUpSteps() { @@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Matchmaking AddStep("join room", () => JoinRoom(CreateDefaultRoom(MatchType.Matchmaking))); WaitForJoined(); - AddStep("create display", () => Child = new StageText + AddStep("create display", () => Child = new StageDisplay.StatusText { Anchor = Anchor.Centre, Origin = Anchor.Centre diff --git a/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanelList.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneUserPanelOverlay.cs similarity index 89% rename from osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanelList.cs rename to osu.Game.Tests/Visual/Matchmaking/TestSceneUserPanelOverlay.cs index 5e43a37e07..9ed233a507 100644 --- a/osu.Game.Tests/Visual/Matchmaking/TestScenePlayerPanelList.cs +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneUserPanelOverlay.cs @@ -11,15 +11,15 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; -using osu.Game.Screens.OnlinePlay.Matchmaking; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match; using osu.Game.Tests.Visual.Multiplayer; using osuTK; namespace osu.Game.Tests.Visual.Matchmaking { - public partial class TestScenePlayerPanelList : MultiplayerTestScene + public partial class TestSceneUserPanelOverlay : MultiplayerTestScene { - private PlayerPanelList list = null!; + private UserPanelOverlay list = null!; public override void SetUpSteps() { @@ -34,7 +34,7 @@ namespace osu.Game.Tests.Visual.Matchmaking Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, Size = new Vector2(0.8f), - Child = list = new PlayerPanelList() + Child = list = new UserPanelOverlay() }); } @@ -55,15 +55,15 @@ namespace osu.Game.Tests.Visual.Matchmaking } }); - AddStep("change to split mode", () => list.DisplayStyle = PlayerPanelList.PanelDisplayStyle.Split); - AddStep("change to grid mode", () => list.DisplayStyle = PlayerPanelList.PanelDisplayStyle.Grid); - AddStep("change to hidden mode", () => list.DisplayStyle = PlayerPanelList.PanelDisplayStyle.Hidden); + AddStep("change to split mode", () => list.DisplayStyle = PanelDisplayStyle.Split); + AddStep("change to grid mode", () => list.DisplayStyle = PanelDisplayStyle.Grid); + AddStep("change to hidden mode", () => list.DisplayStyle = PanelDisplayStyle.Hidden); } [Test] public void AddPanelsGrid() { - AddStep("change to grid mode", () => list.DisplayStyle = PlayerPanelList.PanelDisplayStyle.Grid); + AddStep("change to grid mode", () => list.DisplayStyle = PanelDisplayStyle.Grid); int userId = 0; @@ -84,7 +84,7 @@ namespace osu.Game.Tests.Visual.Matchmaking [Test] public void AddPanelsSplit() { - AddStep("change to split mode", () => list.DisplayStyle = PlayerPanelList.PanelDisplayStyle.Split); + AddStep("change to split mode", () => list.DisplayStyle = PanelDisplayStyle.Split); int userId = 0; diff --git a/osu.Game/Graphics/Carousel/Carousel_ScrollContainer.cs b/osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs similarity index 100% rename from osu.Game/Graphics/Carousel/Carousel_ScrollContainer.cs rename to osu.Game/Graphics/Carousel/Carousel.ScrollContainer.cs diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index d610bd64d5..4dd42b7fd2 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -65,7 +65,7 @@ using osu.Game.Screens.Edit; using osu.Game.Screens.Footer; using osu.Game.Screens.Menu; using osu.Game.Screens.OnlinePlay.DailyChallenge; -using osu.Game.Screens.OnlinePlay.Matchmaking; +using osu.Game.Screens.OnlinePlay.Matchmaking.Queue; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Play; @@ -80,6 +80,7 @@ using osu.Game.Utils; using osuTK; using osuTK.Graphics; using Sentry; +using IntroScreen = osu.Game.Screens.Menu.IntroScreen; using MatchType = osu.Game.Online.Rooms.MatchType; namespace osu.Game @@ -1271,7 +1272,7 @@ namespace osu.Game loadComponentSingleFile(new BackgroundDataStoreProcessor(), Add); loadComponentSingleFile(detachedBeatmapStore = new RealmDetachedBeatmapStore(), Add, true); - loadComponentSingleFile(new MatchmakingController(), Add, true); + loadComponentSingleFile(new QueueController(), Add, true); Add(externalLinkOpener = new ExternalLinkOpener()); Add(new MusicKeyBindingHandler()); diff --git a/osu.Game/OsuGameBase_Importing.cs b/osu.Game/OsuGameBase.Importing.cs similarity index 100% rename from osu.Game/OsuGameBase_Importing.cs rename to osu.Game/OsuGameBase.Importing.cs diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow_ConflictResolution.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.ConflictResolution.cs similarity index 100% rename from osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow_ConflictResolution.cs rename to osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.ConflictResolution.cs diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow_KeyButton.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.KeyButton.cs similarity index 100% rename from osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow_KeyButton.cs rename to osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.KeyButton.cs diff --git a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils_ErrorFunction.cs b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.ErrorFunction.cs similarity index 100% rename from osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils_ErrorFunction.cs rename to osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.ErrorFunction.cs diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index c74b60c5d7..c4ba3145b5 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -37,7 +37,6 @@ using osu.Game.Rulesets; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; using osu.Game.Screens.OnlinePlay.DailyChallenge; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.SelectV2; @@ -483,7 +482,7 @@ namespace osu.Game.Screens.Menu private void loadSongSelect() => this.Push(new SoloSongSelect()); - private void joinOrLeaveMatchmakingQueue() => this.Push(new MatchmakingIntroScreen()); + private void joinOrLeaveMatchmakingQueue() => this.Push(new OnlinePlay.Matchmaking.Intro.IntroScreen()); private partial class MobileDisclaimerDialog : PopupDialog { diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/MatchmakingIntroScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Intro/ScreenIntro.cs similarity index 96% rename from osu.Game/Screens/OnlinePlay/Matchmaking/Screens/MatchmakingIntroScreen.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Intro/ScreenIntro.cs index 34c113c39f..b3fff7dc00 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/MatchmakingIntroScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Intro/ScreenIntro.cs @@ -14,10 +14,14 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; using osu.Game.Screens.OnlinePlay.Match; +using osu.Game.Screens.OnlinePlay.Matchmaking.Queue; -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Intro { - public partial class MatchmakingIntroScreen : OsuScreen + /// + /// A brief intro animation that introduces matchmaking to the user. + /// + public partial class IntroScreen : OsuScreen { public override bool DisallowExternalBeatmapRulesetChanges => false; @@ -51,7 +55,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens protected override BackgroundScreen CreateBackground() => new MatchmakingIntroBackgroundScreen(colourProvider); - public MatchmakingIntroScreen() + public IntroScreen() { ValidForResume = false; } @@ -191,7 +195,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens Schedule(() => { if (this.IsCurrentScreen()) - this.Push(new MatchmakingQueueScreen()); + this.Push(new ScreenQueue()); }); } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/BeatmapSelectionGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SelectionGrid.cs similarity index 94% rename from osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/BeatmapSelectionGrid.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SelectionGrid.cs index 813e8efa0d..bd75514b30 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/BeatmapSelectionGrid.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SelectionGrid.cs @@ -20,9 +20,9 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osuTK; -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect { - public partial class BeatmapSelectionGrid : CompositeDrawable + public partial class SelectionGrid : CompositeDrawable { public const double ARRANGE_DELAY = 200; @@ -37,10 +37,10 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick [Resolved] private IAPIProvider api { get; set; } = null!; - private readonly Dictionary panelLookup = new Dictionary(); + private readonly Dictionary panelLookup = new Dictionary(); private readonly PanelGridContainer panelGridContainer; - private readonly Container rollContainer; + private readonly Container rollContainer; private readonly OsuScrollContainer scroll; private bool allowSelection = true; @@ -51,7 +51,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick private Sample? swooshSample; private double? lastSamplePlayback; - public BeatmapSelectionGrid() + public SelectionGrid() { InternalChildren = new Drawable[] { @@ -67,7 +67,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick Spacing = new Vector2(panel_spacing) }, }, - rollContainer = new Container + rollContainer = new Container { RelativeSizeAxes = Axes.Both, Masking = true, @@ -108,7 +108,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick public void AddItem(MultiplayerPlaylistItem item) { - var panel = panelLookup[item.ID] = new BeatmapSelectionPanel(item) + var panel = panelLookup[item.ID] = new SelectionPanel(item) { Size = new Vector2(300, 70), AllowSelection = allowSelection, @@ -176,7 +176,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick var rng = new Random(); - var remainingPanels = new List(); + var remainingPanels = new List(); foreach (var panel in panelGridContainer.Children.ToArray()) { @@ -216,7 +216,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick { var panel = rollContainer.Children[i]; - var position = positions[i] * (BeatmapPanel.SIZE + new Vector2(panel_spacing)); + var position = positions[i] * (SelectionPanel.SIZE + new Vector2(panel_spacing)); panel.MoveTo(position, duration + stagger * i, new SplitEasingFunction(Easing.InCubic, Easing.OutExpo, 0.3f)); @@ -285,7 +285,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick while ((numSteps - 1) % rollContainer.Children.Count != finalItemIndex) numSteps++; - BeatmapSelectionPanel? lastPanel = null; + SelectionPanel? lastPanel = null; for (int i = 0; i < numSteps; i++) { @@ -346,7 +346,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick PresentRolledBeatmap(finalItem); } - private partial class PanelGridContainer : FillFlowContainer + private partial class PanelGridContainer : FillFlowContainer { public bool LayoutDisabled; diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SelectionPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SelectionPanel.cs new file mode 100644 index 0000000000..1a51ddac64 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SelectionPanel.cs @@ -0,0 +1,502 @@ +// 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.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Extensions; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Database; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Rooms; +using osu.Game.Overlays; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect +{ + public partial class SelectionPanel : Container + { + public static readonly Vector2 SIZE = new Vector2(300, 70); + + private const float corner_radius = 6; + private const float border_width = 3; + + public readonly MultiplayerPlaylistItem Item; + + private readonly Container scaleContainer; + private readonly BeatmapPanel beatmapPanel; + private readonly AvatarOverlay selectionOverlay; + private readonly Container border; + private readonly Box flash; + + public bool AllowSelection; + + public Action? Action; + + [Resolved] + private BeatmapLookupCache beatmapLookupCache { get; set; } = null!; + + public override bool PropagatePositionalInputSubTree => AllowSelection; + + public SelectionPanel(MultiplayerPlaylistItem item) + { + Item = item; + Size = SIZE; + + InternalChildren = new Drawable[] + { + scaleContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(-border_width), + Child = border = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = corner_radius + border_width, + Alpha = 0, + Child = new Box { RelativeSizeAxes = Axes.Both }, + } + }, + beatmapPanel = new BeatmapPanel + { + RelativeSizeAxes = Axes.Both, + OverlayLayer = + { + Children = new[] + { + flash = new Box + { + Blending = BlendingParameters.Additive, + RelativeSizeAxes = Axes.Both, + Alpha = 0, + }, + } + } + }, + selectionOverlay = new AvatarOverlay + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = 10 }, + Origin = Anchor.CentreLeft, + }, + } + }, + new HoverClickSounds(), + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + beatmapLookupCache.GetBeatmapAsync(Item.BeatmapID).ContinueWith(b => Schedule(() => + { + var beatmap = b.GetResultSafely()!; + + beatmap.StarRating = Item.StarRating; + + beatmapPanel.Beatmap = beatmap; + })); + } + + public bool AddUser(APIUser user, bool isOwnUser = false) => selectionOverlay.AddUser(user, isOwnUser); + + public bool RemoveUser(int userId) => selectionOverlay.RemoveUser(userId); + + public bool RemoveUser(APIUser user) => RemoveUser(user.Id); + + protected override bool OnHover(HoverEvent e) + { + flash.FadeTo(0.2f, 50) + .Then() + .FadeTo(0.1f, 300); + + return true; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + base.OnHoverLost(e); + + flash.FadeOut(200); + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (e.Button == MouseButton.Left) + { + scaleContainer.ScaleTo(0.95f, 400, Easing.OutExpo); + return true; + } + + return base.OnMouseDown(e); + } + + protected override void OnMouseUp(MouseUpEvent e) + { + base.OnMouseUp(e); + + if (e.Button == MouseButton.Left) + { + scaleContainer.ScaleTo(1f, 500, Easing.OutElasticHalf); + } + } + + protected override bool OnClick(ClickEvent e) + { + Action?.Invoke(Item); + + flash.FadeTo(0.5f, 50) + .Then() + .FadeTo(0.1f, 400); + + return true; + } + + public void ShowBorder() => border.Show(); + + public void HideBorder() => border.Hide(); + + public void FadeInAndEnterFromBelow(double duration = 500, double delay = 0, float distance = 200) + { + scaleContainer + .FadeOut() + .MoveToY(distance) + .Delay(delay) + .FadeIn(duration / 2) + .MoveToY(0, duration, Easing.OutExpo); + } + + public void PopOutAndExpire(double duration = 400, double delay = 0, Easing easing = Easing.InCubic) + { + AllowSelection = false; + + scaleContainer.Delay(delay) + .ScaleTo(0, duration, easing) + .FadeOut(duration); + + this.Delay(delay + duration).FadeOut().Expire(); + } + + // TODO: combine following two classes with above implementation for simplicity? + private partial class BeatmapPanel : CompositeDrawable + { + public readonly Container OverlayLayer = new Container { RelativeSizeAxes = Axes.Both }; + + public APIBeatmap? Beatmap + { + get => beatmap; + set + { + if (beatmap?.OnlineID == value?.OnlineID) + return; + + beatmap = value; + + if (IsLoaded) + updateContent(); + } + } + + private APIBeatmap? beatmap; + + private Container content = null!; + private UpdateableOnlineBeatmapSetCover cover = null!; + + public BeatmapPanel(APIBeatmap? beatmap = null) + { + this.beatmap = beatmap; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Masking = true; + CornerRadius = 6; + + InternalChildren = new Drawable[] + { + cover = new UpdateableOnlineBeatmapSetCover(BeatmapSetCoverType.Card, timeBeforeLoad: 0, timeBeforeUnload: 10000) + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal( + colourProvider.Background4.Opacity(0.7f), + colourProvider.Background4.Opacity(0.4f) + ) + }, + content = new Container + { + RelativeSizeAxes = Axes.Both, + }, + OverlayLayer, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + updateContent(); + FinishTransforms(true); + } + + private void updateContent() + { + foreach (var child in content.Children) + child.FadeOut(300).Expire(); + + cover.OnlineInfo = beatmap?.BeatmapSet; + + if (beatmap != null) + { + var panelContent = new BeatmapPanelContent(beatmap) + { + RelativeSizeAxes = Axes.Both, + }; + + content.Add(panelContent); + + panelContent.FadeInFromZero(300); + } + } + + private partial class BeatmapPanelContent : CompositeDrawable + { + private readonly APIBeatmap beatmap; + + public BeatmapPanelContent(APIBeatmap beatmap) + { + this.beatmap = beatmap; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new FillFlowContainer + { + Direction = FillDirection.Vertical, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Padding = new MarginPadding { Horizontal = 12 }, + Children = new Drawable[] + { + new TruncatingSpriteText + { + Text = new RomanisableString(beatmap.Metadata.TitleUnicode, beatmap.Metadata.TitleUnicode), + Font = OsuFont.Default.With(size: 19, weight: FontWeight.SemiBold), + RelativeSizeAxes = Axes.X, + }, + new TextFlowContainer(s => + { + s.Font = OsuFont.GetFont(size: 16, weight: FontWeight.SemiBold); + }).With(d => + { + d.RelativeSizeAxes = Axes.X; + d.AutoSizeAxes = Axes.Y; + d.AddText("by "); + d.AddText(new RomanisableString(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist)); + }), + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Margin = new MarginPadding { Top = 6 }, + Spacing = new Vector2(4), + Children = new Drawable[] + { + new StarRatingDisplay(new StarDifficulty(beatmap.StarRating, 0), StarRatingDisplaySize.Small) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + new TruncatingSpriteText + { + Text = beatmap.DifficultyName, + Font = OsuFont.Default.With(size: 16, weight: FontWeight.SemiBold), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + } + }, + }, + }; + } + } + } + + private partial class AvatarOverlay : CompositeDrawable + { + private readonly Dictionary avatars = new Dictionary(); + + private readonly Container avatarContainer; + + private Sample? userAddedSample; + private double? lastSamplePlayback; + + public new Axes AutoSizeAxes + { + get => base.AutoSizeAxes; + set => base.AutoSizeAxes = value; + } + + public new MarginPadding Padding + { + get => base.Padding; + set => base.Padding = value; + } + + public AvatarOverlay() + { + InternalChild = avatarContainer = new Container(); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + avatarContainer.AutoSizeAxes = AutoSizeAxes; + avatarContainer.RelativeSizeAxes = RelativeSizeAxes; + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + userAddedSample = audio.Samples.Get(@"Multiplayer/player-ready"); + } + + public bool AddUser(APIUser user, bool isOwnUser) + { + if (avatars.ContainsKey(user.Id)) + return false; + + var avatar = new SelectionAvatar(user, isOwnUser) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + }; + + avatarContainer.Add(avatars[user.Id] = avatar); + + if (lastSamplePlayback == null || Time.Current - lastSamplePlayback > OsuGameBase.SAMPLE_DEBOUNCE_TIME) + { + userAddedSample?.Play(); + lastSamplePlayback = Time.Current; + } + + updateLayout(); + + avatar.FinishTransforms(); + + return true; + } + + public bool RemoveUser(int id) + { + if (!avatars.Remove(id, out var avatar)) + return false; + + avatar.PopOutAndExpire(); + avatarContainer.ChangeChildDepth(avatar, float.MaxValue); + + updateLayout(); + + return true; + } + + private void updateLayout() + { + const double stagger = 30; + const float spacing = 4; + + double delay = 0; + float x = 0; + + for (int i = avatarContainer.Count - 1; i >= 0; i--) + { + var avatar = avatarContainer[i]; + + if (avatar.Expired) + continue; + + avatar.Delay(delay).MoveToX(x, 500, Easing.OutElasticQuarter); + + x -= avatar.LayoutSize.X + spacing; + + delay += stagger; + } + } + + public partial class SelectionAvatar : CompositeDrawable + { + public bool Expired { get; private set; } + + private readonly Container content; + + public SelectionAvatar(APIUser user, bool isOwnUser) + { + Size = new Vector2(30); + + InternalChildren = new Drawable[] + { + content = new Container + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Child = new MatchmakingAvatar(user, isOwnUser) + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + content.ScaleTo(0) + .ScaleTo(1, 500, Easing.OutElasticHalf) + .FadeIn(200); + } + + public void PopOutAndExpire() + { + content.ScaleTo(0, 400, Easing.OutExpo); + + this.FadeOut(100).Expire(); + Expired = true; + } + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/PickScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs similarity index 87% rename from osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/PickScreen.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs index 96cfa67642..cf86deeb3e 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/PickScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/SubScreenBeatmapSelect.cs @@ -9,19 +9,19 @@ using osu.Framework.Graphics.Containers; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect { - public partial class PickScreen : MatchmakingSubScreen + public partial class SubScreenBeatmapSelect : MatchmakingSubScreen { - public override PlayerPanelList.PanelDisplayStyle PlayersDisplayStyle => PlayerPanelList.PanelDisplayStyle.Split; + public override PanelDisplayStyle PlayersDisplayStyle => PanelDisplayStyle.Split; public override Drawable PlayersDisplayArea { get; } - private readonly BeatmapSelectionGrid selectionGrid; + private readonly SelectionGrid selectionGrid; [Resolved] private MultiplayerClient client { get; set; } = null!; - public PickScreen() + public SubScreenBeatmapSelect() { InternalChildren = new Drawable[] { @@ -29,7 +29,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Horizontal = 200 }, - Child = selectionGrid = new BeatmapSelectionGrid + Child = selectionGrid = new SelectionGrid { RelativeSizeAxes = Axes.Both, }, diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingPlayer.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/Gameplay/ScreenGameplay.cs similarity index 77% rename from osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingPlayer.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/Gameplay/ScreenGameplay.cs index af19aa1252..f6f324eb90 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/Gameplay/ScreenGameplay.cs @@ -8,11 +8,11 @@ using osu.Game.Online.Rooms; using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.Multiplayer; -namespace osu.Game.Screens.OnlinePlay.Matchmaking +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.Gameplay { - public partial class MatchmakingPlayer : MultiplayerPlayer + public partial class ScreenGameplay : MultiplayerPlayer { - public MatchmakingPlayer(Room room, PlaylistItem playlistItem, MultiplayerRoomUser[] users) + public ScreenGameplay(Room room, PlaylistItem playlistItem, MultiplayerRoomUser[] users) : base(room, playlistItem, users) { } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingAvatar.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingAvatar.cs similarity index 87% rename from osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingAvatar.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingAvatar.cs index e3d314844f..faf32c6604 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingAvatar.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingAvatar.cs @@ -11,8 +11,12 @@ using osu.Game.Users.Drawables; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.OnlinePlay.Matchmaking +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match { + /// + /// A circular player avatar used in matchmaking displays. + /// Is part of a but can also be used in isolation for a more ambient/decorative user display. + /// public partial class MatchmakingAvatar : CompositeDrawable { public static readonly Vector2 SIZE = new Vector2(30); diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/MatchmakingSubScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingSubScreen.cs similarity index 88% rename from osu.Game/Screens/OnlinePlay/Matchmaking/Screens/MatchmakingSubScreen.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingSubScreen.cs index fc41b7db84..0141c424bd 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/MatchmakingSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingSubScreen.cs @@ -4,11 +4,11 @@ using osu.Framework.Graphics; using osu.Framework.Screens; -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match { public abstract partial class MatchmakingSubScreen : Screen { - public abstract PlayerPanelList.PanelDisplayStyle PlayersDisplayStyle { get; } + public abstract PanelDisplayStyle PlayersDisplayStyle { get; } public abstract Drawable? PlayersDisplayArea { get; } protected MatchmakingSubScreen() diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/PlayerPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingUserPanel.cs similarity index 94% rename from osu.Game/Screens/OnlinePlay/Matchmaking/PlayerPanel.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingUserPanel.cs index 117893bb8c..ce4b471df4 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/PlayerPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingUserPanel.cs @@ -14,9 +14,13 @@ using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Users; using osuTK; -namespace osu.Game.Screens.OnlinePlay.Matchmaking +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match { - public partial class PlayerPanel : UserPanel + /// + /// A panel used throughout matchmaking to represent a user, including local information like their + /// rank and high level statistics in the matchmaking system. + /// + public partial class MatchmakingUserPanel : UserPanel { public static readonly Vector2 SIZE_HORIZONTAL = new Vector2(250, 100); public static readonly Vector2 SIZE_VERTICAL = new Vector2(150, 200); @@ -51,7 +55,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking private bool horizontal; - public PlayerPanel(MultiplayerRoomUser user) + public MatchmakingUserPanel(MultiplayerRoomUser user) : base(user.User!) { RoomUser = user; diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Results/RoomStatisticPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/Results/PanelRoomAward.cs similarity index 89% rename from osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Results/RoomStatisticPanel.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/Results/PanelRoomAward.cs index 5988a73ef8..5e7c3865c1 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Results/RoomStatisticPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/Results/PanelRoomAward.cs @@ -11,16 +11,16 @@ using osu.Game.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; using osuTK.Graphics; -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Results +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.Results { - public partial class RoomStatisticPanel : CompositeDrawable + public partial class PanelRoomAward : CompositeDrawable { private readonly Color4 backgroundColour = Color4.SaddleBrown; private readonly string text; private readonly int userId; - public RoomStatisticPanel(string text, int userId) + public PanelRoomAward(string text, int userId) { this.text = text; this.userId = userId; diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Results/UserStatisticPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/Results/PanelUserStatistic.cs similarity index 87% rename from osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Results/UserStatisticPanel.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/Results/PanelUserStatistic.cs index 3a39fc714d..2051359f32 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Results/UserStatisticPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/Results/PanelUserStatistic.cs @@ -8,15 +8,15 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Sprites; using osuTK.Graphics; -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Results +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.Results { - public partial class UserStatisticPanel : CompositeDrawable + public partial class PanelUserStatistic : CompositeDrawable { private readonly Color4 backgroundColour = Color4.SaddleBrown; private readonly string text; - public UserStatisticPanel(string text) + public PanelUserStatistic(string text) { this.text = text; diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Results/ResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/Results/SubScreenResults.cs similarity index 95% rename from osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Results/ResultsScreen.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/Results/SubScreenResults.cs index 83c587e7cd..3e6b437f63 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Results/ResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/Results/SubScreenResults.cs @@ -14,23 +14,26 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Utils; using osuTK; -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Results +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.Results { - public partial class ResultsScreen : MatchmakingSubScreen + /// + /// Final room results, during + /// + public partial class SubScreenResults : MatchmakingSubScreen { private const float grid_spacing = 5; - public override PlayerPanelList.PanelDisplayStyle PlayersDisplayStyle => PlayerPanelList.PanelDisplayStyle.Grid; + public override PanelDisplayStyle PlayersDisplayStyle => PanelDisplayStyle.Grid; public override Drawable PlayersDisplayArea { get; } [Resolved] private MultiplayerClient client { get; set; } = null!; private readonly OsuSpriteText placementText; - private readonly FillFlowContainer userStatistics; - private readonly FillFlowContainer roomStatistics; + private readonly FillFlowContainer userStatistics; + private readonly FillFlowContainer roomStatistics; - public ResultsScreen() + public SubScreenResults() { InternalChild = new GridContainer { @@ -103,7 +106,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Results Text = "Breakdown", Font = OsuFont.Default.With(size: 12) }, - userStatistics = new FillFlowContainer + userStatistics = new FillFlowContainer { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, @@ -139,7 +142,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Results Text = "Statistics", Font = OsuFont.Default.With(size: 12) }, - roomStatistics = new FillFlowContainer + roomStatistics = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -196,7 +199,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Results void addStatistic(string text) { - userStatistics.Add(new UserStatisticPanel(text) + userStatistics.Add(new PanelUserStatistic(text) { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre @@ -321,7 +324,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Results void addStatistic(int userId, string text) { - roomStatistics.Add(new RoomStatisticPanel(text, userId) + roomStatistics.Add(new PanelRoomAward(text, userId) { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/RoundResults/RoundResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs similarity index 82% rename from osu.Game/Screens/OnlinePlay/Matchmaking/Screens/RoundResults/RoundResultsScreen.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs index 8fd56877eb..580d157a8b 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/RoundResults/RoundResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundResults/SubScreenRoundResults.cs @@ -18,18 +18,22 @@ using osu.Game.Models; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Scoring; using osu.Game.Screens.Ranking; -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.RoundResults +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.RoundResults { - public partial class RoundResultsScreen : MatchmakingSubScreen + /// + /// Per-round results, during + /// + public partial class SubScreenRoundResults : MatchmakingSubScreen { private const int panel_spacing = 5; - public override PlayerPanelList.PanelDisplayStyle PlayersDisplayStyle => PlayerPanelList.PanelDisplayStyle.Hidden; + public override PanelDisplayStyle PlayersDisplayStyle => PanelDisplayStyle.Hidden; public override Drawable? PlayersDisplayArea => null; [Resolved] @@ -153,6 +157,32 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.RoundResults } }); + private partial class RoundResultsScorePanel : CompositeDrawable + { + public RoundResultsScorePanel(ScoreInfo score) + { + AutoSizeAxes = Axes.Both; + InternalChild = new InstantSizingScorePanel(score); + } + + public override bool PropagateNonPositionalInputSubTree => false; + public override bool PropagatePositionalInputSubTree => false; + + private partial class InstantSizingScorePanel : ScorePanel + { + public InstantSizingScorePanel(ScoreInfo score, bool isNewLocalScore = false) + : base(score, isNewLocalScore) + { + } + + protected override void LoadComplete() + { + base.LoadComplete(); + FinishTransforms(true); + } + } + } + private partial class AutoScrollContainer : UserTrackingScrollContainer { private const float initial_offset = -0.5f; diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Idle/IdleScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundWarmup/SubScreenRoundWarmup.cs similarity index 52% rename from osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Idle/IdleScreen.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundWarmup/SubScreenRoundWarmup.cs index 6f982d89f2..e389cbabfa 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Idle/IdleScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/RoundWarmup/SubScreenRoundWarmup.cs @@ -3,12 +3,16 @@ using osu.Framework.Graphics; using osu.Framework.Screens; +using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Idle +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.RoundWarmup { - public partial class IdleScreen : MatchmakingSubScreen + /// + /// Shown during + /// + public partial class SubScreenRoundWarmup : MatchmakingSubScreen { - public override PlayerPanelList.PanelDisplayStyle PlayersDisplayStyle => PlayerPanelList.PanelDisplayStyle.Grid; + public override PanelDisplayStyle PlayersDisplayStyle => PanelDisplayStyle.Grid; public override Drawable PlayersDisplayArea => this; public override void OnEntering(ScreenTransitionEvent e) diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs new file mode 100644 index 0000000000..29a1acb2b8 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.ScreenStack.cs @@ -0,0 +1,133 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics; +using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Screens; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match.Results; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match.RoundResults; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match.RoundWarmup; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match +{ + public partial class ScreenMatchmaking + { + public partial class ScreenStack : CompositeDrawable + { + [Resolved] + private MultiplayerClient client { get; set; } = null!; + + private Framework.Screens.ScreenStack screenStack = null!; + private UserPanelOverlay playersList = null!; + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(10) + { + Bottom = StageDisplay.HEIGHT, + }, + Children = new Drawable[] + { + screenStack = new Framework.Screens.ScreenStack(), + } + }, + playersList = new UserPanelOverlay + { + DisplayArea = this + }, + new StageDisplay + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + screenStack.ScreenPushed += onScreenPushed; + screenStack.ScreenExited += onScreenExited; + + screenStack.Push(new SubScreenRoundWarmup()); + + client.MatchRoomStateChanged += onMatchRoomStateChanged; + onMatchRoomStateChanged(client.Room!.MatchState); + } + + private void onScreenPushed(IScreen lastScreen, IScreen newScreen) + { + if (newScreen is not MatchmakingSubScreen matchmakingSubScreen) + return; + + playersList.DisplayStyle = matchmakingSubScreen.PlayersDisplayStyle; + playersList.DisplayArea = matchmakingSubScreen.PlayersDisplayArea; + } + + private void onScreenExited(IScreen lastScreen, IScreen newScreen) + { + if (newScreen is not MatchmakingSubScreen matchmakingSubScreen) + return; + + playersList.DisplayStyle = matchmakingSubScreen.PlayersDisplayStyle; + playersList.DisplayArea = matchmakingSubScreen.PlayersDisplayArea; + } + + private void onMatchRoomStateChanged(MatchRoomState? state) => Scheduler.Add(() => + { + if (state is not MatchmakingRoomState matchmakingState) + return; + + switch (matchmakingState.Stage) + { + case MatchmakingStage.WaitingForClientsJoin: + case MatchmakingStage.RoundWarmupTime: + while (screenStack.CurrentScreen is not SubScreenRoundWarmup) + screenStack.Exit(); + break; + + case MatchmakingStage.UserBeatmapSelect: + screenStack.Push(new SubScreenBeatmapSelect()); + break; + + case MatchmakingStage.ServerBeatmapFinalised: + Debug.Assert(screenStack.CurrentScreen is SubScreenBeatmapSelect); + ((SubScreenBeatmapSelect)screenStack.CurrentScreen).RollFinalBeatmap(matchmakingState.CandidateItems, matchmakingState.CandidateItem); + break; + + case MatchmakingStage.ResultsDisplaying: + screenStack.Push(new SubScreenRoundResults()); + break; + + case MatchmakingStage.Ended: + screenStack.Push(new SubScreenResults()); + break; + } + }); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (client.IsNotNull()) + client.MatchRoomStateChanged -= onMatchRoomStateChanged; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs similarity index 95% rename from osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingScreen.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs index 7dde7a480b..dbe958dcac 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs @@ -25,13 +25,16 @@ using osu.Game.Overlays; using osu.Game.Overlays.Dialog; using osu.Game.Rulesets; using osu.Game.Screens.OnlinePlay.Match.Components; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match.Gameplay; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Users; -namespace osu.Game.Screens.OnlinePlay.Matchmaking +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match { - public partial class MatchmakingScreen : OsuScreen + /// + /// The main matchmaking screen which houses a custom through the life cycle of a single session. + /// + public partial class ScreenMatchmaking : OsuScreen { /// /// Padding between rows of the content. @@ -76,7 +79,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking private MatchChatDisplay chat = null!; - public MatchmakingScreen(MultiplayerRoom room) + public ScreenMatchmaking(MultiplayerRoom room) { this.room = room; @@ -128,7 +131,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background6, }, - new MatchmakingScreenStack(), + new ScreenStack(), } } ], @@ -248,7 +251,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking sampleStart?.Play(); - this.Push(new MultiplayerPlayerLoader(() => new MatchmakingPlayer(new Room(room), new PlaylistItem(client.Room!.CurrentPlaylistItem), room.Users.ToArray()))); + this.Push(new MultiplayerPlayerLoader(() => new ScreenGameplay(new Room(room), new PlaylistItem(client.Room!.CurrentPlaylistItem), room.Users.ToArray()))); }); private void checkForAutomaticDownload() diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.StageSegment.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.StageSegment.cs new file mode 100644 index 0000000000..f97bf9fe68 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.StageSegment.cs @@ -0,0 +1,234 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Matchmaking; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match +{ + public partial class StageDisplay + { + internal partial class StageSegment : CompositeDrawable + { + [Resolved] + private MultiplayerClient client { get; set; } = null!; + + public readonly int? Round; + + private readonly MatchmakingStage stage; + + private readonly LocalisableString displayText; + private Drawable progressBar = null!; + + private DateTimeOffset countdownStartTime; + private DateTimeOffset countdownEndTime; + private SpriteIcon arrow = null!; + + private Sample? countdownTickSample; + private double? lastSamplePlayback; + + public bool Active { get; private set; } + + public float Progress => progressBar.Width; + + public StageSegment(int? round, MatchmakingStage stage, LocalisableString displayText) + { + Round = round; + this.stage = stage; + this.displayText = displayText; + + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio, OverlayColourProvider colourProvider) + { + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5), + Children = new Drawable[] + { + arrow = new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Alpha = 0.5f, + Size = new Vector2(16), + Icon = FontAwesome.Solid.ArrowRight, + Margin = new MarginPadding { Horizontal = 10 } + }, + new Container + { + Masking = true, + CornerRadius = 5, + CornerExponent = 10, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = + ColourInfo.GradientVertical( + colourProvider.Dark2, + colourProvider.Dark1 + ), + }, + progressBar = new Box + { + Blending = BlendingParameters.Additive, + EdgeSmoothness = new Vector2(1), + RelativeSizeAxes = Axes.Both, + Width = 0, + Colour = colourProvider.Dark3, + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = displayText, + Padding = new MarginPadding(10) + } + } + } + } + }; + + Alpha = 0.5f; + countdownTickSample = audio.Samples.Get(@"Multiplayer/countdown-tick"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + client.MatchRoomStateChanged += onMatchRoomStateChanged; + client.CountdownStarted += onCountdownStarted; + client.CountdownStopped += onCountdownStopped; + + if (client.Room != null) + { + onMatchRoomStateChanged(client.Room.MatchState); + foreach (var countdown in client.Room.ActiveCountdowns) + onCountdownStarted(countdown); + } + } + + protected override void Update() + { + base.Update(); + + if (!Active) + return; + + TimeSpan total = countdownEndTime - countdownStartTime; + TimeSpan elapsed = DateTimeOffset.Now - countdownStartTime; + + if (total.TotalMilliseconds <= 0) + { + progressBar.Width = 0; + return; + } + + progressBar.Width = (float)Math.Clamp(elapsed.TotalMilliseconds / total.TotalMilliseconds, 0, 1); + + int secondsRemaining = Math.Max(0, (int)Math.Ceiling((total.TotalMilliseconds - elapsed.TotalMilliseconds) / 1000)); + + if (total.TotalMilliseconds - elapsed.TotalMilliseconds <= 3000 + && lastSamplePlayback != secondsRemaining) + { + countdownTickSample?.Play(); + lastSamplePlayback = secondsRemaining; + } + } + + private void onMatchRoomStateChanged(MatchRoomState? state) => Scheduler.Add(() => + { + bool wasActive = Active; + + Active = false; + + if (state is not MatchmakingRoomState roomState) + return; + + if (Round != null && roomState.CurrentRound != Round) + return; + + Active = stage == roomState.Stage; + + if (wasActive) + progressBar.Width = 1; + + bool isPreparing = + (stage == MatchmakingStage.RoundWarmupTime && roomState.Stage == MatchmakingStage.WaitingForClientsJoin) || + (stage == MatchmakingStage.GameplayWarmupTime && roomState.Stage == MatchmakingStage.WaitingForClientsBeatmapDownload) || + (stage == MatchmakingStage.ResultsDisplaying && roomState.Stage == MatchmakingStage.Gameplay); + + if (isPreparing) + { + arrow.FadeTo(1, 500) + .Then() + .FadeTo(0.5f, 500) + .Loop(); + } + }); + + private void onCountdownStarted(MultiplayerCountdown countdown) => Scheduler.Add(() => + { + if (!Active) + return; + + if (countdown is not MatchmakingStageCountdown) + return; + + countdownStartTime = DateTimeOffset.Now; + countdownEndTime = countdownStartTime + countdown.TimeRemaining; + arrow.FadeIn(500, Easing.OutQuint); + + this.FadeIn(200); + }); + + private void onCountdownStopped(MultiplayerCountdown countdown) => Scheduler.Add(() => + { + if (!Active) + return; + + if (countdown is not MatchmakingStageCountdown) + return; + + countdownEndTime = DateTimeOffset.Now; + }); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (client.IsNotNull()) + { + client.MatchRoomStateChanged -= onMatchRoomStateChanged; + client.CountdownStarted -= onCountdownStarted; + client.CountdownStopped -= onCountdownStopped; + } + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.StatusText.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.StatusText.cs new file mode 100644 index 0000000000..8d94df11e4 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.StatusText.cs @@ -0,0 +1,129 @@ +// 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.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; + +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match +{ + public partial class StageDisplay + { + public partial class StatusText : CompositeDrawable + { + [Resolved] + private MultiplayerClient client { get; set; } = null!; + + private OsuSpriteText text = null!; + + private Sample? textChangedSample; + private double? lastSamplePlayback; + + public StatusText() + { + AutoSizeAxes = Axes.X; + Height = 16; + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + InternalChild = text = new OsuSpriteText + { + Alpha = 0, + Height = 16, + Font = OsuFont.Style.Caption1, + AlwaysPresent = true, + }; + + textChangedSample = audio.Samples.Get(@"Multiplayer/Matchmaking/stage-message"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + client.MatchRoomStateChanged += onMatchRoomStateChanged; + onMatchRoomStateChanged(client.Room!.MatchState); + } + + private void onMatchRoomStateChanged(MatchRoomState? state) => Scheduler.Add(() => + { + if (state is not MatchmakingRoomState matchmakingState) + return; + + text.Text = getTextForStatus(matchmakingState.Stage); + + if (text.Text == string.Empty || (lastSamplePlayback != null && Time.Current - lastSamplePlayback < OsuGameBase.SAMPLE_DEBOUNCE_TIME)) + return; + + textChangedSample?.Play(); + lastSamplePlayback = Time.Current; + + LocalisableString textForStatus = getTextForStatus(matchmakingState.Stage); + + if (string.IsNullOrEmpty(textForStatus.ToString())) + { + text.FadeOut(); + return; + } + + text.RotateTo(2f) + .RotateTo(0, 500, Easing.OutQuint); + + text.FadeInFromZero(500, Easing.OutQuint); + + using (text.BeginDelayedSequence(500)) + { + text + .FadeTo(0.6f, 400, Easing.In) + .Then() + .FadeTo(1, 400, Easing.Out) + .Loop(); + } + + text.ScaleTo(0.3f) + .ScaleTo(1, 500, Easing.OutQuint); + + text.Text = textForStatus; + }); + + private LocalisableString getTextForStatus(MatchmakingStage status) + { + switch (status) + { + case MatchmakingStage.WaitingForClientsJoin: + return "Players are joining the match..."; + + case MatchmakingStage.WaitingForClientsBeatmapDownload: + return "Players are downloading the beatmap..."; + + case MatchmakingStage.Gameplay: + return "Game is in progress..."; + + case MatchmakingStage.Ended: + return "Thanks for playing! The match will close shortly."; + + default: + return string.Empty; + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (client.IsNotNull()) + client.MatchRoomStateChanged -= onMatchRoomStateChanged; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/StageDisplay.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.cs similarity index 90% rename from osu.Game/Screens/OnlinePlay/Matchmaking/StageDisplay.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.cs index a5bb72c4b6..db302163a5 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/StageDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/StageDisplay.cs @@ -16,8 +16,11 @@ using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osu.Game.Overlays; using osuTK; -namespace osu.Game.Screens.OnlinePlay.Matchmaking +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match { + /// + /// A "global" footer staple element in matchmaking which shows the current progression of the room, from start to finish. + /// public partial class StageDisplay : CompositeDrawable { public const float HEIGHT = 96; @@ -68,7 +71,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking Direction = FillDirection.Horizontal, }, }, - new StageText + new StatusText { Y = 32, Anchor = Anchor.Centre, @@ -93,23 +96,23 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking }, }; - flow.Add(new StageBubble(null, MatchmakingStage.WaitingForClientsJoin, "Waiting for other users")); + flow.Add(new StageSegment(null, MatchmakingStage.WaitingForClientsJoin, "Waiting for other users")); for (int i = 1; i <= round_count; i++) { - flow.Add(new StageBubble(i, MatchmakingStage.RoundWarmupTime, "Next Round")); - flow.Add(new StageBubble(i, MatchmakingStage.UserBeatmapSelect, "Beatmap Selection")); - flow.Add(new StageBubble(i, MatchmakingStage.GameplayWarmupTime, "Get Ready")); - flow.Add(new StageBubble(i, MatchmakingStage.ResultsDisplaying, "Results")); + flow.Add(new StageSegment(i, MatchmakingStage.RoundWarmupTime, "Next Round")); + flow.Add(new StageSegment(i, MatchmakingStage.UserBeatmapSelect, "Beatmap Selection")); + flow.Add(new StageSegment(i, MatchmakingStage.GameplayWarmupTime, "Get Ready")); + flow.Add(new StageSegment(i, MatchmakingStage.ResultsDisplaying, "Results")); } - flow.Add(new StageBubble(null, MatchmakingStage.Ended, "Match End")); + flow.Add(new StageSegment(null, MatchmakingStage.Ended, "Match End")); } protected override void Update() { base.Update(); - var bubble = flow.OfType().FirstOrDefault(b => b.Active); + var bubble = flow.OfType().FirstOrDefault(b => b.Active); if (bubble != null) { diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/PlayerPanelList.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/UserPanelOverlay.cs similarity index 91% rename from osu.Game/Screens/OnlinePlay/Matchmaking/PlayerPanelList.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Match/UserPanelOverlay.cs index a226ce19be..9ddddda710 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/PlayerPanelList.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/UserPanelOverlay.cs @@ -12,14 +12,18 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; using osuTK; -namespace osu.Game.Screens.OnlinePlay.Matchmaking +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match { - public partial class PlayerPanelList : CompositeDrawable + /// + /// A component which maintains the layout of the players in a matchmaking room. + /// Can be controlled to display the panels in a certain location and in multiple styles. + /// + public partial class UserPanelOverlay : CompositeDrawable { [Resolved] private MultiplayerClient client { get; set; } = null!; - private Container panels = null!; + private Container panels = null!; private PlayerPanelCellContainer gridLayout = null!; private PlayerPanelCellContainer splitLayoutLeft = null!; private PlayerPanelCellContainer splitLayoutRight = null!; @@ -56,7 +60,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking Direction = FillDirection.Vertical, Spacing = new Vector2(20, 5), }, - panels = new Container + panels = new Container { RelativeSizeAxes = Axes.Both } @@ -106,7 +110,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking private void onUserJoined(MultiplayerRoomUser user) => Scheduler.Add(() => { - panels.Add(new PlayerPanel(user) + panels.Add(new MatchmakingUserPanel(user) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -211,7 +215,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking [Resolved] private MultiplayerClient client { get; set; } = null!; - public void AcquirePanels(PlayerPanel[] panels) + public void AcquirePanels(MatchmakingUserPanel[] panels) { while (Count < panels.Length) { @@ -255,10 +259,10 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking private partial class PlayerPanelCell : Drawable { - private PlayerPanel? panel; + private MatchmakingUserPanel? panel; private bool isAnimating; - public void AcquirePanel(PlayerPanel panel) + public void AcquirePanel(MatchmakingUserPanel panel) { this.panel = panel; isAnimating = true; @@ -276,7 +280,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking if (panel == null) return; - Size = panel.Horizontal ? PlayerPanel.SIZE_HORIZONTAL : PlayerPanel.SIZE_VERTICAL; + Size = panel.Horizontal ? MatchmakingUserPanel.SIZE_HORIZONTAL : MatchmakingUserPanel.SIZE_VERTICAL; Size *= panel.Scale; var targetPos = getFinalPosition(); @@ -298,12 +302,12 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking => panel.Parent!.ToLocalSpace(ScreenSpaceDrawQuad.Centre) - panel.AnchorPosition; } } + } - public enum PanelDisplayStyle - { - Grid, - Split, - Hidden - } + public enum PanelDisplayStyle + { + Grid, + Split, + Hidden } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingCloud.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/CloudVisualisation.cs similarity index 92% rename from osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingCloud.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Queue/CloudVisualisation.cs index 3fab5ab207..33ed21f3db 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingCloud.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/CloudVisualisation.cs @@ -11,12 +11,17 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Utils; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match; using osu.Game.Screens.Ranking; using osuTK; -namespace osu.Game.Screens.OnlinePlay.Matchmaking +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue { - public partial class MatchmakingCloud : CompositeDrawable + /// + /// A visualisation at the top level of matchmaking which shows the overall system status. + /// This is intended to be something which users can watch while idle, for fun or otherwise. + /// + public partial class CloudVisualisation : CompositeDrawable { private APIUser[] users = []; private Container usersContainer = null!; diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingPoolSelector.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/PoolSelector.cs similarity index 97% rename from osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingPoolSelector.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Queue/PoolSelector.cs index 8976b1f3b0..eb84a525a8 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingPoolSelector.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/PoolSelector.cs @@ -16,9 +16,9 @@ using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.OnlinePlay.Matchmaking +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue { - public partial class MatchmakingPoolSelector : CompositeDrawable + public partial class PoolSelector : CompositeDrawable { private const float icon_size = 48; @@ -27,7 +27,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking private FillFlowContainer poolFlow = null!; - public MatchmakingPoolSelector() + public PoolSelector() { AutoSizeAxes = Axes.Both; } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingController.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs similarity index 79% rename from osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingController.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs index 1a426501d7..40ac0e5777 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/MatchmakingController.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs @@ -10,13 +10,21 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens; +using osu.Game.Screens.OnlinePlay.Matchmaking.Intro; -namespace osu.Game.Screens.OnlinePlay.Matchmaking +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue { - public partial class MatchmakingController : Component + /// + /// A component which acts as a bridge between the online component (ie ) + /// and the visual representations and flow of queueing for matchmaking. + /// + /// Includes support for deferring to background. + /// + /// + /// This is initialised and cached in the but can be used throughout the system via DI. + public partial class QueueController : Component { - public readonly Bindable CurrentState = new Bindable(); + public readonly Bindable CurrentState = new Bindable(); [Resolved] private MultiplayerClient client { get; set; } = null!; @@ -63,12 +71,12 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking private void onRoomUpdated() => Scheduler.Add(() => { if (client.Room == null) - CurrentState.Value = MatchmakingQueueScreen.MatchmakingScreenState.Idle; + CurrentState.Value = ScreenQueue.MatchmakingScreenState.Idle; }); private void onMatchmakingQueueJoined() => Scheduler.Add(() => { - CurrentState.Value = MatchmakingQueueScreen.MatchmakingScreenState.Queueing; + CurrentState.Value = ScreenQueue.MatchmakingScreenState.Queueing; if (isBackgrounded) { @@ -79,15 +87,15 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking private void onMatchmakingQueueLeft() => Scheduler.Add(() => { - if (CurrentState.Value != MatchmakingQueueScreen.MatchmakingScreenState.InRoom) - CurrentState.Value = MatchmakingQueueScreen.MatchmakingScreenState.Idle; + if (CurrentState.Value != ScreenQueue.MatchmakingScreenState.InRoom) + CurrentState.Value = ScreenQueue.MatchmakingScreenState.Idle; closeNotifications(); }); private void onMatchmakingRoomInvited() => Scheduler.Add(() => { - CurrentState.Value = MatchmakingQueueScreen.MatchmakingScreenState.PendingAccept; + CurrentState.Value = ScreenQueue.MatchmakingScreenState.PendingAccept; if (backgroundNotification != null) { @@ -101,7 +109,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking client.JoinRoom(new Room { RoomID = roomId }, password) .FireAndForget(() => Scheduler.Add(() => { - CurrentState.Value = MatchmakingQueueScreen.MatchmakingScreenState.InRoom; + CurrentState.Value = ScreenQueue.MatchmakingScreenState.InRoom; })); }); @@ -118,7 +126,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking CompletionClickAction = () => { client.MatchmakingAcceptInvitation().FireAndForget(); - performer?.PerformFromScreen(s => s.Push(new MatchmakingIntroScreen())); + performer?.PerformFromScreen(s => s.Push(new IntroScreen())); closeNotifications(); return true; diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/MatchmakingQueueScreen.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs similarity index 96% rename from osu.Game/Screens/OnlinePlay/Matchmaking/Screens/MatchmakingQueueScreen.cs rename to osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs index d23ff9bf84..d13bc9c2da 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/MatchmakingQueueScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/ScreenQueue.cs @@ -27,18 +27,22 @@ using osu.Game.Online.Multiplayer; using osu.Game.Overlays; using osu.Game.Overlays.Dialog; using osu.Game.Rulesets; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match; using osuTK; -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens +namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue { - public partial class MatchmakingQueueScreen : OsuScreen + /// + /// The initial screen that users arrive at when preparing for a quick play session. + /// + public partial class ScreenQueue : OsuScreen { public override bool ShowFooter => true; private Container mainContent = null!; private MatchmakingScreenState state; - private MatchmakingCloud cloud = null!; + private CloudVisualisation cloud = null!; [Resolved] private IAPIProvider api { get; set; } = null!; @@ -56,7 +60,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens private IDialogOverlay dialogOverlay { get; set; } = null!; [Resolved] - private MatchmakingController controller { get; set; } = null!; + private QueueController controller { get; set; } = null!; [Resolved] private UserLookupCache userLookupCache { get; set; } = null!; @@ -79,7 +83,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens InternalChildren = new Drawable[] { - cloud = new MatchmakingCloud + cloud = new CloudVisualisation { Y = -100, Anchor = Anchor.Centre, @@ -252,7 +256,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens Spacing = new Vector2(10), Children = new Drawable[] { - new MatchmakingPoolSelector + new PoolSelector { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, @@ -411,7 +415,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens }; using (BeginDelayedSequence(2000)) - Schedule(() => this.Push(new MatchmakingScreen(client.Room!))); + Schedule(() => this.Push(new ScreenMatchmaking(client.Room!))); break; default: diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/MatchmakingScreenStack.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/MatchmakingScreenStack.cs deleted file mode 100644 index 2e13c59055..0000000000 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/MatchmakingScreenStack.cs +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Diagnostics; -using osu.Framework.Allocation; -using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Screens; -using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Idle; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Results; -using osu.Game.Screens.OnlinePlay.Matchmaking.Screens.RoundResults; - -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens -{ - public partial class MatchmakingScreenStack : CompositeDrawable - { - [Resolved] - private MultiplayerClient client { get; set; } = null!; - - private ScreenStack screenStack = null!; - private PlayerPanelList playersList = null!; - - [BackgroundDependencyLoader] - private void load() - { - RelativeSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(10) - { - Bottom = StageDisplay.HEIGHT, - }, - Children = new Drawable[] - { - screenStack = new ScreenStack(), - } - }, - playersList = new PlayerPanelList - { - DisplayArea = this - }, - new StageDisplay - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - screenStack.ScreenPushed += onScreenPushed; - screenStack.ScreenExited += onScreenExited; - - screenStack.Push(new IdleScreen()); - - client.MatchRoomStateChanged += onMatchRoomStateChanged; - onMatchRoomStateChanged(client.Room!.MatchState); - } - - private void onScreenPushed(IScreen lastScreen, IScreen newScreen) - { - if (newScreen is not MatchmakingSubScreen matchmakingSubScreen) - return; - - playersList.DisplayStyle = matchmakingSubScreen.PlayersDisplayStyle; - playersList.DisplayArea = matchmakingSubScreen.PlayersDisplayArea; - } - - private void onScreenExited(IScreen lastScreen, IScreen newScreen) - { - if (newScreen is not MatchmakingSubScreen matchmakingSubScreen) - return; - - playersList.DisplayStyle = matchmakingSubScreen.PlayersDisplayStyle; - playersList.DisplayArea = matchmakingSubScreen.PlayersDisplayArea; - } - - private void onMatchRoomStateChanged(MatchRoomState? state) => Scheduler.Add(() => - { - if (state is not MatchmakingRoomState matchmakingState) - return; - - switch (matchmakingState.Stage) - { - case MatchmakingStage.WaitingForClientsJoin: - case MatchmakingStage.RoundWarmupTime: - while (screenStack.CurrentScreen is not IdleScreen) - screenStack.Exit(); - break; - - case MatchmakingStage.UserBeatmapSelect: - screenStack.Push(new PickScreen()); - break; - - case MatchmakingStage.ServerBeatmapFinalised: - Debug.Assert(screenStack.CurrentScreen is PickScreen); - ((PickScreen)screenStack.CurrentScreen).RollFinalBeatmap(matchmakingState.CandidateItems, matchmakingState.CandidateItem); - break; - - case MatchmakingStage.ResultsDisplaying: - screenStack.Push(new RoundResultsScreen()); - break; - - case MatchmakingStage.Ended: - screenStack.Push(new ResultsScreen()); - break; - } - }); - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - if (client.IsNotNull()) - client.MatchRoomStateChanged -= onMatchRoomStateChanged; - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/BeatmapPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/BeatmapPanel.cs deleted file mode 100644 index 807c7d3355..0000000000 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/BeatmapPanel.cs +++ /dev/null @@ -1,176 +0,0 @@ -// 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.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Localisation; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Overlays; -using osuTK; - -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick -{ - public partial class BeatmapPanel : CompositeDrawable - { - public static readonly Vector2 SIZE = new Vector2(300, 70); - - public readonly Container OverlayLayer = new Container { RelativeSizeAxes = Axes.Both }; - - public APIBeatmap? Beatmap - { - get => beatmap; - set - { - if (beatmap?.OnlineID == value?.OnlineID) - return; - - beatmap = value; - - if (IsLoaded) - updateContent(); - } - } - - private APIBeatmap? beatmap; - - private Container content = null!; - private UpdateableOnlineBeatmapSetCover cover = null!; - - public BeatmapPanel(APIBeatmap? beatmap = null) - { - this.beatmap = beatmap; - } - - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) - { - Masking = true; - CornerRadius = 6; - - InternalChildren = new Drawable[] - { - cover = new UpdateableOnlineBeatmapSetCover(BeatmapSetCoverType.Card, timeBeforeLoad: 0, timeBeforeUnload: 10000) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal( - colourProvider.Background4.Opacity(0.7f), - colourProvider.Background4.Opacity(0.4f) - ) - }, - content = new Container - { - RelativeSizeAxes = Axes.Both, - }, - OverlayLayer, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - updateContent(); - FinishTransforms(true); - } - - private void updateContent() - { - foreach (var child in content.Children) - child.FadeOut(300).Expire(); - - cover.OnlineInfo = beatmap?.BeatmapSet; - - if (beatmap != null) - { - var panelContent = new BeatmapPanelContent(beatmap) - { - RelativeSizeAxes = Axes.Both, - }; - - content.Add(panelContent); - - panelContent.FadeInFromZero(300); - } - } - - private partial class BeatmapPanelContent : CompositeDrawable - { - private readonly APIBeatmap beatmap; - - public BeatmapPanelContent(APIBeatmap beatmap) - { - this.beatmap = beatmap; - } - - [BackgroundDependencyLoader] - private void load() - { - InternalChild = new FillFlowContainer - { - Direction = FillDirection.Vertical, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Padding = new MarginPadding { Horizontal = 12 }, - Children = new Drawable[] - { - new TruncatingSpriteText - { - Text = new RomanisableString(beatmap.Metadata.TitleUnicode, beatmap.Metadata.TitleUnicode), - Font = OsuFont.Default.With(size: 19, weight: FontWeight.SemiBold), - RelativeSizeAxes = Axes.X, - }, - new TextFlowContainer(s => - { - s.Font = OsuFont.GetFont(size: 16, weight: FontWeight.SemiBold); - }).With(d => - { - d.RelativeSizeAxes = Axes.X; - d.AutoSizeAxes = Axes.Y; - d.AddText("by "); - d.AddText(new RomanisableString(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist)); - }), - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Margin = new MarginPadding { Top = 6 }, - Spacing = new Vector2(4), - Children = new Drawable[] - { - new StarRatingDisplay(new StarDifficulty(beatmap.StarRating, 0), StarRatingDisplaySize.Small) - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - new TruncatingSpriteText - { - Text = beatmap.DifficultyName, - Font = OsuFont.Default.With(size: 16, weight: FontWeight.SemiBold), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - } - }, - }, - }; - } - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/BeatmapSelectionOverlay.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/BeatmapSelectionOverlay.cs deleted file mode 100644 index 2a15201d11..0000000000 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/BeatmapSelectionOverlay.cs +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Online.API.Requests.Responses; -using osuTK; - -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick -{ - public partial class BeatmapSelectionOverlay : CompositeDrawable - { - private readonly Dictionary avatars = new Dictionary(); - - private readonly Container avatarContainer; - - private Sample? userAddedSample; - private double? lastSamplePlayback; - - public new Axes AutoSizeAxes - { - get => base.AutoSizeAxes; - set => base.AutoSizeAxes = value; - } - - public new MarginPadding Padding - { - get => base.Padding; - set => base.Padding = value; - } - - public BeatmapSelectionOverlay() - { - InternalChild = avatarContainer = new Container(); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - avatarContainer.AutoSizeAxes = AutoSizeAxes; - avatarContainer.RelativeSizeAxes = RelativeSizeAxes; - } - - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - userAddedSample = audio.Samples.Get(@"Multiplayer/player-ready"); - } - - public bool AddUser(APIUser user, bool isOwnUser) - { - if (avatars.ContainsKey(user.Id)) - return false; - - var avatar = new SelectionAvatar(user, isOwnUser) - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - }; - - avatarContainer.Add(avatars[user.Id] = avatar); - - if (lastSamplePlayback == null || Time.Current - lastSamplePlayback > OsuGameBase.SAMPLE_DEBOUNCE_TIME) - { - userAddedSample?.Play(); - lastSamplePlayback = Time.Current; - } - - updateLayout(); - - avatar.FinishTransforms(); - - return true; - } - - public bool RemoveUser(int id) - { - if (!avatars.Remove(id, out var avatar)) - return false; - - avatar.PopOutAndExpire(); - avatarContainer.ChangeChildDepth(avatar, float.MaxValue); - - updateLayout(); - - return true; - } - - private void updateLayout() - { - const double stagger = 30; - const float spacing = 4; - - double delay = 0; - float x = 0; - - for (int i = avatarContainer.Count - 1; i >= 0; i--) - { - var avatar = avatarContainer[i]; - - if (avatar.Expired) - continue; - - avatar.Delay(delay).MoveToX(x, 500, Easing.OutElasticQuarter); - - x -= avatar.LayoutSize.X + spacing; - - delay += stagger; - } - } - - public partial class SelectionAvatar : CompositeDrawable - { - public bool Expired { get; private set; } - - private readonly Container content; - - public SelectionAvatar(APIUser user, bool isOwnUser) - { - Size = new Vector2(30); - - InternalChildren = new Drawable[] - { - content = new Container - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Child = new MatchmakingAvatar(user, isOwnUser) - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - content.ScaleTo(0) - .ScaleTo(1, 500, Easing.OutElasticHalf) - .FadeIn(200); - } - - public void PopOutAndExpire() - { - content.ScaleTo(0, 400, Easing.OutExpo); - - this.FadeOut(100).Expire(); - Expired = true; - } - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/BeatmapSelectionPanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/BeatmapSelectionPanel.cs deleted file mode 100644 index 090c275bef..0000000000 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/Pick/BeatmapSelectionPanel.cs +++ /dev/null @@ -1,190 +0,0 @@ -// 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 osu.Framework.Allocation; -using osu.Framework.Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Events; -using osu.Game.Database; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Online.Rooms; -using osuTK.Input; - -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.Pick -{ - public partial class BeatmapSelectionPanel : Container - { - private const float corner_radius = 6; - private const float border_width = 3; - - public readonly MultiplayerPlaylistItem Item; - - private readonly Container scaleContainer; - private readonly BeatmapPanel beatmapPanel; - private readonly BeatmapSelectionOverlay selectionOverlay; - private readonly Container border; - private readonly Box flash; - - public bool AllowSelection; - - public Action? Action; - - [Resolved] - private BeatmapLookupCache beatmapLookupCache { get; set; } = null!; - - public override bool PropagatePositionalInputSubTree => AllowSelection; - - public BeatmapSelectionPanel(MultiplayerPlaylistItem item) - { - Item = item; - Size = BeatmapPanel.SIZE; - - InternalChildren = new Drawable[] - { - scaleContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(-border_width), - Child = border = new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = corner_radius + border_width, - Alpha = 0, - Child = new Box { RelativeSizeAxes = Axes.Both }, - } - }, - beatmapPanel = new BeatmapPanel - { - RelativeSizeAxes = Axes.Both, - OverlayLayer = - { - Children = new[] - { - flash = new Box - { - Blending = BlendingParameters.Additive, - RelativeSizeAxes = Axes.Both, - Alpha = 0, - }, - } - } - }, - selectionOverlay = new BeatmapSelectionOverlay - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Horizontal = 10 }, - Origin = Anchor.CentreLeft, - }, - } - }, - new HoverClickSounds(), - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - beatmapLookupCache.GetBeatmapAsync(Item.BeatmapID).ContinueWith(b => Schedule(() => - { - var beatmap = b.GetResultSafely()!; - - beatmap.StarRating = Item.StarRating; - - beatmapPanel.Beatmap = beatmap; - })); - } - - public bool AddUser(APIUser user, bool isOwnUser = false) => selectionOverlay.AddUser(user, isOwnUser); - - public bool RemoveUser(int userId) => selectionOverlay.RemoveUser(userId); - - public bool RemoveUser(APIUser user) => RemoveUser(user.Id); - - protected override bool OnHover(HoverEvent e) - { - flash.FadeTo(0.2f, 50) - .Then() - .FadeTo(0.1f, 300); - - return true; - } - - protected override void OnHoverLost(HoverLostEvent e) - { - base.OnHoverLost(e); - - flash.FadeOut(200); - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - if (e.Button == MouseButton.Left) - { - scaleContainer.ScaleTo(0.95f, 400, Easing.OutExpo); - return true; - } - - return base.OnMouseDown(e); - } - - protected override void OnMouseUp(MouseUpEvent e) - { - base.OnMouseUp(e); - - if (e.Button == MouseButton.Left) - { - scaleContainer.ScaleTo(1f, 500, Easing.OutElasticHalf); - } - } - - protected override bool OnClick(ClickEvent e) - { - Action?.Invoke(Item); - - flash.FadeTo(0.5f, 50) - .Then() - .FadeTo(0.1f, 400); - - return true; - } - - public void ShowBorder() => border.Show(); - - public void HideBorder() => border.Hide(); - - public void FadeInAndEnterFromBelow(double duration = 500, double delay = 0, float distance = 200) - { - scaleContainer - .FadeOut() - .MoveToY(distance) - .Delay(delay) - .FadeIn(duration / 2) - .MoveToY(0, duration, Easing.OutExpo); - } - - public void PopOutAndExpire(double duration = 400, double delay = 0, Easing easing = Easing.InCubic) - { - AllowSelection = false; - - scaleContainer.Delay(delay) - .ScaleTo(0, duration, easing) - .FadeOut(duration); - - this.Delay(delay + duration).FadeOut().Expire(); - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/RoundResults/RoundResultsScorePanel.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/RoundResults/RoundResultsScorePanel.cs deleted file mode 100644 index ad30c19c02..0000000000 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Screens/RoundResults/RoundResultsScorePanel.cs +++ /dev/null @@ -1,36 +0,0 @@ -// 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.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Scoring; -using osu.Game.Screens.Ranking; - -namespace osu.Game.Screens.OnlinePlay.Matchmaking.Screens.RoundResults -{ - internal partial class RoundResultsScorePanel : CompositeDrawable - { - public RoundResultsScorePanel(ScoreInfo score) - { - AutoSizeAxes = Axes.Both; - InternalChild = new InstantSizingScorePanel(score); - } - - public override bool PropagateNonPositionalInputSubTree => false; - public override bool PropagatePositionalInputSubTree => false; - - private partial class InstantSizingScorePanel : ScorePanel - { - public InstantSizingScorePanel(ScoreInfo score, bool isNewLocalScore = false) - : base(score, isNewLocalScore) - { - } - - protected override void LoadComplete() - { - base.LoadComplete(); - FinishTransforms(true); - } - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/StageBubble.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/StageBubble.cs deleted file mode 100644 index da6de711ff..0000000000 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/StageBubble.cs +++ /dev/null @@ -1,231 +0,0 @@ -// 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 osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Localisation; -using osu.Game.Graphics.Sprites; -using osu.Game.Online.Matchmaking; -using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; -using osu.Game.Overlays; -using osuTK; - -namespace osu.Game.Screens.OnlinePlay.Matchmaking -{ - internal partial class StageBubble : CompositeDrawable - { - [Resolved] - private MultiplayerClient client { get; set; } = null!; - - public readonly int? Round; - - private readonly MatchmakingStage stage; - - private readonly LocalisableString displayText; - private Drawable progressBar = null!; - - private DateTimeOffset countdownStartTime; - private DateTimeOffset countdownEndTime; - private SpriteIcon arrow = null!; - - private Sample? countdownTickSample; - private double? lastSamplePlayback; - - public bool Active { get; private set; } - - public float Progress => progressBar.Width; - - public StageBubble(int? round, MatchmakingStage stage, LocalisableString displayText) - { - Round = round; - this.stage = stage; - this.displayText = displayText; - - AutoSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader] - private void load(AudioManager audio, OverlayColourProvider colourProvider) - { - InternalChild = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5), - Children = new Drawable[] - { - arrow = new SpriteIcon - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Alpha = 0.5f, - Size = new Vector2(16), - Icon = FontAwesome.Solid.ArrowRight, - Margin = new MarginPadding { Horizontal = 10 } - }, - new Container - { - Masking = true, - CornerRadius = 5, - CornerExponent = 10, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AutoSizeAxes = Axes.Both, - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = - ColourInfo.GradientVertical( - colourProvider.Dark2, - colourProvider.Dark1 - ), - }, - progressBar = new Box - { - Blending = BlendingParameters.Additive, - EdgeSmoothness = new Vector2(1), - RelativeSizeAxes = Axes.Both, - Width = 0, - Colour = colourProvider.Dark3, - }, - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = displayText, - Padding = new MarginPadding(10) - } - } - } - } - }; - - Alpha = 0.5f; - countdownTickSample = audio.Samples.Get(@"Multiplayer/countdown-tick"); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - client.MatchRoomStateChanged += onMatchRoomStateChanged; - client.CountdownStarted += onCountdownStarted; - client.CountdownStopped += onCountdownStopped; - - if (client.Room != null) - { - onMatchRoomStateChanged(client.Room.MatchState); - foreach (var countdown in client.Room.ActiveCountdowns) - onCountdownStarted(countdown); - } - } - - protected override void Update() - { - base.Update(); - - if (!Active) - return; - - TimeSpan total = countdownEndTime - countdownStartTime; - TimeSpan elapsed = DateTimeOffset.Now - countdownStartTime; - - if (total.TotalMilliseconds <= 0) - { - progressBar.Width = 0; - return; - } - - progressBar.Width = (float)Math.Clamp(elapsed.TotalMilliseconds / total.TotalMilliseconds, 0, 1); - - int secondsRemaining = Math.Max(0, (int)Math.Ceiling((total.TotalMilliseconds - elapsed.TotalMilliseconds) / 1000)); - - if (total.TotalMilliseconds - elapsed.TotalMilliseconds <= 3000 - && lastSamplePlayback != secondsRemaining) - { - countdownTickSample?.Play(); - lastSamplePlayback = secondsRemaining; - } - } - - private void onMatchRoomStateChanged(MatchRoomState? state) => Scheduler.Add(() => - { - bool wasActive = Active; - - Active = false; - - if (state is not MatchmakingRoomState roomState) - return; - - if (Round != null && roomState.CurrentRound != Round) - return; - - Active = stage == roomState.Stage; - - if (wasActive) - progressBar.Width = 1; - - bool isPreparing = - (stage == MatchmakingStage.RoundWarmupTime && roomState.Stage == MatchmakingStage.WaitingForClientsJoin) || - (stage == MatchmakingStage.GameplayWarmupTime && roomState.Stage == MatchmakingStage.WaitingForClientsBeatmapDownload) || - (stage == MatchmakingStage.ResultsDisplaying && roomState.Stage == MatchmakingStage.Gameplay); - - if (isPreparing) - { - arrow.FadeTo(1, 500) - .Then() - .FadeTo(0.5f, 500) - .Loop(); - } - }); - - private void onCountdownStarted(MultiplayerCountdown countdown) => Scheduler.Add(() => - { - if (!Active) - return; - - if (countdown is not MatchmakingStageCountdown) - return; - - countdownStartTime = DateTimeOffset.Now; - countdownEndTime = countdownStartTime + countdown.TimeRemaining; - arrow.FadeIn(500, Easing.OutQuint); - - this.FadeIn(200); - }); - - private void onCountdownStopped(MultiplayerCountdown countdown) => Scheduler.Add(() => - { - if (!Active) - return; - - if (countdown is not MatchmakingStageCountdown) - return; - - countdownEndTime = DateTimeOffset.Now; - }); - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - if (client.IsNotNull()) - { - client.MatchRoomStateChanged -= onMatchRoomStateChanged; - client.CountdownStarted -= onCountdownStarted; - client.CountdownStopped -= onCountdownStopped; - } - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/StageText.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/StageText.cs deleted file mode 100644 index 677906ee9b..0000000000 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/StageText.cs +++ /dev/null @@ -1,126 +0,0 @@ -// 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.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Localisation; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking; - -namespace osu.Game.Screens.OnlinePlay.Matchmaking -{ - public partial class StageText : CompositeDrawable - { - [Resolved] - private MultiplayerClient client { get; set; } = null!; - - private OsuSpriteText text = null!; - - private Sample? textChangedSample; - private double? lastSamplePlayback; - - public StageText() - { - AutoSizeAxes = Axes.X; - Height = 16; - } - - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - InternalChild = text = new OsuSpriteText - { - Alpha = 0, - Height = 16, - Font = OsuFont.Style.Caption1, - AlwaysPresent = true, - }; - - textChangedSample = audio.Samples.Get(@"Multiplayer/Matchmaking/stage-message"); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - client.MatchRoomStateChanged += onMatchRoomStateChanged; - onMatchRoomStateChanged(client.Room!.MatchState); - } - - private void onMatchRoomStateChanged(MatchRoomState? state) => Scheduler.Add(() => - { - if (state is not MatchmakingRoomState matchmakingState) - return; - - text.Text = getTextForStatus(matchmakingState.Stage); - - if (text.Text == string.Empty || (lastSamplePlayback != null && Time.Current - lastSamplePlayback < OsuGameBase.SAMPLE_DEBOUNCE_TIME)) - return; - - textChangedSample?.Play(); - lastSamplePlayback = Time.Current; - - LocalisableString textForStatus = getTextForStatus(matchmakingState.Stage); - - if (string.IsNullOrEmpty(textForStatus.ToString())) - { - text.FadeOut(); - return; - } - - text.RotateTo(2f) - .RotateTo(0, 500, Easing.OutQuint); - - text.FadeInFromZero(500, Easing.OutQuint); - - using (text.BeginDelayedSequence(500)) - { - text - .FadeTo(0.6f, 400, Easing.In) - .Then() - .FadeTo(1, 400, Easing.Out) - .Loop(); - } - - text.ScaleTo(0.3f) - .ScaleTo(1, 500, Easing.OutQuint); - - text.Text = textForStatus; - }); - - private LocalisableString getTextForStatus(MatchmakingStage status) - { - switch (status) - { - case MatchmakingStage.WaitingForClientsJoin: - return "Players are joining the match..."; - - case MatchmakingStage.WaitingForClientsBeatmapDownload: - return "Players are downloading the beatmap..."; - - case MatchmakingStage.Gameplay: - return "Game is in progress..."; - - case MatchmakingStage.Ended: - return "Thanks for playing! The match will close shortly."; - - default: - return string.Empty; - } - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - if (client.IsNotNull()) - client.MatchRoomStateChanged -= onMatchRoomStateChanged; - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid_Cell.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid.Cell.cs similarity index 100% rename from osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid_Cell.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid.Cell.cs diff --git a/osu.Game/Screens/Ranking/UserTagControl_AddTagsPopover.cs b/osu.Game/Screens/Ranking/UserTagControl.AddTagsPopover.cs similarity index 100% rename from osu.Game/Screens/Ranking/UserTagControl_AddTagsPopover.cs rename to osu.Game/Screens/Ranking/UserTagControl.AddTagsPopover.cs diff --git a/osu.Game/Screens/Ranking/UserTagControl_DrawableUserTag.cs b/osu.Game/Screens/Ranking/UserTagControl.DrawableUserTag.cs similarity index 100% rename from osu.Game/Screens/Ranking/UserTagControl_DrawableUserTag.cs rename to osu.Game/Screens/Ranking/UserTagControl.DrawableUserTag.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapDetailsArea_Header.cs b/osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapDetailsArea_Header.cs rename to osu.Game/Screens/SelectV2/BeatmapDetailsArea.Header.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapDetailsArea_WedgeSelector.cs b/osu.Game/Screens/SelectV2/BeatmapDetailsArea.WedgeSelector.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapDetailsArea_WedgeSelector.cs rename to osu.Game/Screens/SelectV2/BeatmapDetailsArea.WedgeSelector.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore_Tooltip.cs b/osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.Tooltip.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapLeaderboardScore_Tooltip.cs rename to osu.Game/Screens/SelectV2/BeatmapLeaderboardScore.Tooltip.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge_FailRetryDisplay.cs b/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.FailRetryDisplay.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge_FailRetryDisplay.cs rename to osu.Game/Screens/SelectV2/BeatmapMetadataWedge.FailRetryDisplay.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge_MetadataDisplay.cs b/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.MetadataDisplay.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge_MetadataDisplay.cs rename to osu.Game/Screens/SelectV2/BeatmapMetadataWedge.MetadataDisplay.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge_RatingSpreadDisplay.cs b/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.RatingSpreadDisplay.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge_RatingSpreadDisplay.cs rename to osu.Game/Screens/SelectV2/BeatmapMetadataWedge.RatingSpreadDisplay.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge_SuccessRateDisplay.cs b/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.SuccessRateDisplay.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge_SuccessRateDisplay.cs rename to osu.Game/Screens/SelectV2/BeatmapMetadataWedge.SuccessRateDisplay.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge_TagsLine.cs b/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.TagsLine.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge_TagsLine.cs rename to osu.Game/Screens/SelectV2/BeatmapMetadataWedge.TagsLine.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapMetadataWedge_UserRatingDisplay.cs b/osu.Game/Screens/SelectV2/BeatmapMetadataWedge.UserRatingDisplay.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapMetadataWedge_UserRatingDisplay.cs rename to osu.Game/Screens/SelectV2/BeatmapMetadataWedge.UserRatingDisplay.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge_DifficultyDisplay.cs b/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge_DifficultyDisplay.cs rename to osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyDisplay.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge_DifficultyStatisticsDisplay.cs b/osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge_DifficultyStatisticsDisplay.cs rename to osu.Game/Screens/SelectV2/BeatmapTitleWedge.DifficultyStatisticsDisplay.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge_FavouriteButton.cs b/osu.Game/Screens/SelectV2/BeatmapTitleWedge.FavouriteButton.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge_FavouriteButton.cs rename to osu.Game/Screens/SelectV2/BeatmapTitleWedge.FavouriteButton.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge_Statistic.cs b/osu.Game/Screens/SelectV2/BeatmapTitleWedge.Statistic.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge_Statistic.cs rename to osu.Game/Screens/SelectV2/BeatmapTitleWedge.Statistic.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge_StatisticDifficulty.cs b/osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticDifficulty.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge_StatisticDifficulty.cs rename to osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticDifficulty.cs diff --git a/osu.Game/Screens/SelectV2/BeatmapTitleWedge_StatisticPlayCount.cs b/osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticPlayCount.cs similarity index 100% rename from osu.Game/Screens/SelectV2/BeatmapTitleWedge_StatisticPlayCount.cs rename to osu.Game/Screens/SelectV2/BeatmapTitleWedge.StatisticPlayCount.cs diff --git a/osu.Game/Screens/SelectV2/FilterControl_DifficultyRangeSlider.cs b/osu.Game/Screens/SelectV2/FilterControl.DifficultyRangeSlider.cs similarity index 100% rename from osu.Game/Screens/SelectV2/FilterControl_DifficultyRangeSlider.cs rename to osu.Game/Screens/SelectV2/FilterControl.DifficultyRangeSlider.cs diff --git a/osu.Game/Screens/SelectV2/FooterButtonOptions_Popover.cs b/osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs similarity index 100% rename from osu.Game/Screens/SelectV2/FooterButtonOptions_Popover.cs rename to osu.Game/Screens/SelectV2/FooterButtonOptions.Popover.cs