diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs index b9f147e44a..136625682a 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps; -using osu.Game.Database; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Rulesets; @@ -29,9 +28,6 @@ namespace osu.Game.Tests.Visual.Multiplayer private BeatmapSetInfo importedSet; private BeatmapInfo importedBeatmap; - [Cached(typeof(UserLookupCache))] - private UserLookupCache lookupCache = new TestUserLookupCache(); - [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) { @@ -60,22 +56,132 @@ namespace osu.Game.Tests.Visual.Multiplayer importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First(); importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0); }); + + AddStep("change to all players mode", () => Client.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers })); } [Test] - public void DoTest() + public void TestNonExpiredItemsAddedToQueueList() { - AddStep("change to round robin mode", () => Client.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayersRoundRobin })); - AddStep("add playlist item for user 1", () => Client.AddPlaylistItem(new MultiplayerPlaylistItem - { - BeatmapID = importedBeatmap.OnlineID!.Value - })); + assertItemInQueueListStep(1, 0); + + addItemStep(); + assertItemInQueueListStep(2, 1); + + addItemStep(); + assertItemInQueueListStep(3, 2); + } + + [Test] + public void TestExpiredItemsAddedToHistoryList() + { + assertItemInQueueListStep(1, 0); + + addItemStep(true); + assertItemInHistoryListStep(2, 0); + + addItemStep(true); + assertItemInHistoryListStep(3, 0); + assertItemInHistoryListStep(2, 1); + + // Initial item is still in the queue. + assertItemInQueueListStep(1, 0); + } + + [Test] + public void TestExpiredItemsMoveToQueueList() + { + addItemStep(); + addItemStep(); + + AddStep("finish current item", () => Client.FinishCurrentItem()); + + assertItemInHistoryListStep(1, 0); + assertItemInQueueListStep(2, 0); + assertItemInQueueListStep(3, 1); + + AddStep("finish current item", () => Client.FinishCurrentItem()); + + assertItemInHistoryListStep(2, 0); + assertItemInHistoryListStep(1, 1); + assertItemInQueueListStep(3, 0); + + AddStep("finish current item", () => Client.FinishCurrentItem()); + + assertItemInHistoryListStep(3, 0); + assertItemInHistoryListStep(2, 1); + assertItemInHistoryListStep(1, 2); + } + + [Test] + public void TestJoinRoomWithMixedItemsAddedInCorrectLists() + { + AddStep("leave room", () => RoomManager.PartRoom()); + AddUntilStep("wait for room part", () => Client.Room == null); + } + + /// <summary> + /// Adds a step to create a new playlist item. + /// </summary> + private void addItemStep(bool expired = false) => AddStep("add item", () => Client.AddPlaylistItem(new MultiplayerPlaylistItem(new PlaylistItem + { + Beatmap = { Value = importedBeatmap }, + BeatmapID = importedBeatmap.OnlineID ?? -1, + Expired = expired + }))); + + /// <summary> + /// Asserts the position of a given playlist item in the queue list. + /// </summary> + /// <param name="playlistItemId">The item id.</param> + /// <param name="visualIndex">The index at which the item should appear visually. The item with index 0 is at the top of the list.</param> + private void assertItemInQueueListStep(int playlistItemId, int visualIndex) => AddUntilStep($"{playlistItemId} in queue at pos = {visualIndex}", () => + { + return !inHistoryList(playlistItemId) + && this.ChildrenOfType<MultiplayerQueueList>() + .Single() + .ChildrenOfType<DrawableRoomPlaylistItem>() + .OrderBy(drawable => drawable.Position.Y) + .TakeWhile(drawable => drawable.Item.ID != playlistItemId) + .Count() == visualIndex; + }); + + /// <summary> + /// Asserts the position of a given playlist item in the history list. + /// </summary> + /// <param name="playlistItemId">The item id.</param> + /// <param name="visualIndex">The index at which the item should appear visually. The item with index 0 is at the top of the list.</param> + private void assertItemInHistoryListStep(int playlistItemId, int visualIndex) => AddUntilStep($"{playlistItemId} in history at pos = {visualIndex}", () => + { + return !inQueueList(playlistItemId) + && this.ChildrenOfType<MultiplayerHistoryList>() + .Single() + .ChildrenOfType<DrawableRoomPlaylistItem>() + .OrderBy(drawable => drawable.Position.Y) + .TakeWhile(drawable => drawable.Item.ID != playlistItemId) + .Count() == visualIndex; + }); + + private bool inQueueList(int playlistItemId) + { + return this.ChildrenOfType<MultiplayerQueueList>() + .Single() + .ChildrenOfType<DrawableRoomPlaylistItem>() + .Any(i => i.Item.ID == playlistItemId); + } + + private bool inHistoryList(int playlistItemId) + { + return this.ChildrenOfType<MultiplayerHistoryList>() + .Single() + .ChildrenOfType<DrawableRoomPlaylistItem>() + .Any(i => i.Item.ID == playlistItemId); } public class MultiplayerPlaylist : MultiplayerRoomComposite { - private MultiplayerQueueList multiplayerQueueList; - private DrawableRoomPlaylist historyList; + private MultiplayerQueueList queueList; + private MultiplayerHistoryList historyList; private bool firstPopulation = true; [BackgroundDependencyLoader] @@ -88,11 +194,11 @@ namespace osu.Game.Tests.Visual.Multiplayer { new Drawable[] { - multiplayerQueueList = new MultiplayerQueueList + queueList = new MultiplayerQueueList { RelativeSizeAxes = Axes.Both }, - historyList = new DrawableRoomPlaylist(false, false, true) + historyList = new MultiplayerHistoryList { RelativeSizeAxes = Axes.Both } @@ -120,17 +226,20 @@ namespace osu.Game.Tests.Visual.Multiplayer { base.PlaylistItemAdded(item); + var apiItem = Playlist.Single(i => i.ID == item.ID); + if (item.Expired) - historyList.Items.Add(getPlaylistItem(item)); + historyList.Items.Add(apiItem); else - multiplayerQueueList.Items.Add(getPlaylistItem(item)); + queueList.Items.Add(apiItem); } protected override void PlaylistItemRemoved(long item) { base.PlaylistItemRemoved(item); - multiplayerQueueList.Items.RemoveAll(i => i.ID == item); + queueList.Items.RemoveAll(i => i.ID == item); + historyList.Items.RemoveAll(i => i.ID == item); } protected override void PlaylistItemChanged(MultiplayerPlaylistItem item) @@ -140,8 +249,6 @@ namespace osu.Game.Tests.Visual.Multiplayer PlaylistItemRemoved(item.ID); PlaylistItemAdded(item); } - - private PlaylistItem getPlaylistItem(MultiplayerPlaylistItem item) => Playlist.Single(i => i.ID == item.ID); } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerHistoryList.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerHistoryList.cs new file mode 100644 index 0000000000..76bb364f3a --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerHistoryList.cs @@ -0,0 +1,30 @@ +// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.Rooms; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist +{ + public class MultiplayerHistoryList : DrawableRoomPlaylist + { + public MultiplayerHistoryList() + : base(false, false, false, true) + { + } + + protected override FillFlowContainer<RearrangeableListItem<PlaylistItem>> CreateListFillFlowContainer() => new HistoryFillFlowContainer + { + Spacing = new Vector2(0, 2) + }; + + private class HistoryFillFlowContainer : FillFlowContainer<RearrangeableListItem<PlaylistItem>> + { + public override IEnumerable<Drawable> FlowingChildren => base.FlowingChildren.Reverse(); + } + } +} diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 2d77e17513..b746f7e667 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -145,7 +145,7 @@ namespace osu.Game.Tests.Visual.Multiplayer ((IMultiplayerClient)this).ResultsReady(); - finishCurrentItem().Wait(); + FinishCurrentItem().Wait(); } break; @@ -390,7 +390,7 @@ namespace osu.Game.Tests.Visual.Multiplayer await updateCurrentItem(Room).ConfigureAwait(false); } - private async Task finishCurrentItem() + public async Task FinishCurrentItem() { Debug.Assert(Room != null); Debug.Assert(APIRoom != null);