diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs index cef0532f9d..7170a76b8b 100644 --- a/osu.Game.Tests/Resources/TestResources.cs +++ b/osu.Game.Tests/Resources/TestResources.cs @@ -9,6 +9,8 @@ namespace osu.Game.Tests.Resources { public static class TestResources { + public const double QUICK_BEATMAP_LENGTH = 10000; + public static DllResourceStore GetStore() => new DllResourceStore(typeof(TestResources).Assembly); public static Stream OpenResource(string name) => GetStore().GetStream($"Resources/{name}"); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs index eadfc9b279..a3a1cacb0d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs @@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { base.SetUpSteps(); - AddStep("load chat display", () => Child = chatDisplay = new GameplayChatDisplay + AddStep("load chat display", () => Child = chatDisplay = new GameplayChatDisplay(SelectedRoom.Value) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 6c1aed71e6..7a3507d944 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -28,6 +28,8 @@ using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Multiplayer.Match; +using osu.Game.Screens.Play; +using osu.Game.Screens.Ranking; using osu.Game.Tests.Resources; using osu.Game.Users; using osuTK.Input; @@ -430,6 +432,40 @@ namespace osu.Game.Tests.Visual.Multiplayer } } + [Test] + public void TestGameplayFlow() + { + createRoom(() => new Room + { + Name = { Value = "Test Room" }, + Playlist = + { + new PlaylistItem + { + Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo }, + } + } + }); + + AddRepeatStep("click spectate button", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }, 2); + + AddUntilStep("wait for player", () => Stack.CurrentScreen is Player); + + // Gameplay runs in real-time, so we need to incrementally check if gameplay has finished in order to not time out. + for (double i = 1000; i < TestResources.QUICK_BEATMAP_LENGTH; i += 1000) + { + var time = i; + AddUntilStep($"wait for time > {i}", () => this.ChildrenOfType().SingleOrDefault()?.GameplayClock.CurrentTime > time); + } + + AddUntilStep("wait for results", () => Stack.CurrentScreen is ResultsScreen); + } + private void createRoom(Func room) { AddUntilStep("wait for lounge", () => multiplayerScreen.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs index 80da7a7e5e..a1543f99e1 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("initialise gameplay", () => { - Stack.Push(player = new MultiplayerPlayer(Client.CurrentMatchPlayingItem.Value, Client.Room?.Users.ToArray())); + Stack.Push(player = new MultiplayerPlayer(Client.APIRoom, Client.CurrentMatchPlayingItem.Value, Client.Room?.Users.ToArray())); }); } diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs index 5f960c1b5c..0396562959 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs @@ -10,20 +10,18 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components { public class MatchChatDisplay : StandAloneChatDisplay { - [Resolved(typeof(Room), nameof(Room.RoomID))] - private Bindable roomId { get; set; } - - [Resolved(typeof(Room), nameof(Room.ChannelId))] - private Bindable channelId { get; set; } + private readonly IBindable channelId = new Bindable(); [Resolved(CanBeNull = true)] private ChannelManager channelManager { get; set; } + private readonly Room room; private readonly bool leaveChannelOnDispose; - public MatchChatDisplay(bool leaveChannelOnDispose = true) + public MatchChatDisplay(Room room, bool leaveChannelOnDispose = true) : base(true) { + this.room = room; this.leaveChannelOnDispose = leaveChannelOnDispose; } @@ -31,15 +29,17 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components { base.LoadComplete(); + // Required for the time being since this component is created prior to the room being joined. + channelId.BindTo(room.ChannelId); channelId.BindValueChanged(_ => updateChannel(), true); } private void updateChannel() { - if (roomId.Value == null || channelId.Value == 0) + if (room.RoomID.Value == null || channelId.Value == 0) return; - Channel.Value = channelManager?.JoinChannel(new Channel { Id = channelId.Value, Type = ChannelType.Multiplayer, Name = $"#lazermp_{roomId.Value}" }); + Channel.Value = channelManager?.JoinChannel(new Channel { Id = channelId.Value, Type = ChannelType.Multiplayer, Name = $"#lazermp_{room.RoomID.Value}" }); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs index 9fe41842f3..3af72fa25a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Input.Bindings; +using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.Play; @@ -29,8 +30,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer public override bool PropagateNonPositionalInputSubTree => true; - public GameplayChatDisplay() - : base(leaveChannelOnDispose: false) + public GameplayChatDisplay(Room room) + : base(room, leaveChannelOnDispose: false) { RelativeSizeAxes = Axes.X; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 06e60903aa..fb18e7a31f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -173,7 +173,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer }, }, new Drawable[] { new OverlinedHeader("Chat") { Margin = new MarginPadding { Vertical = 5 }, }, }, - new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } + new Drawable[] { new MatchChatDisplay(Room) { RelativeSizeAxes = Axes.Both } } }, RowDimensions = new[] { @@ -395,7 +395,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer return new MultiSpectatorScreen(users.Take(PlayerGrid.MAX_PLAYERS).ToArray()); default: - return new PlayerLoader(() => new MultiplayerPlayer(SelectedItem.Value, users)); + return new PlayerLoader(() => new MultiplayerPlayer(Room, SelectedItem.Value, users)); } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 24657943d7..89acda27c3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -45,10 +45,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer /// /// Construct a multiplayer player. /// + /// The room. /// The playlist item to be played. /// The users which are participating in this game. - public MultiplayerPlayer(PlaylistItem playlistItem, MultiplayerRoomUser[] users) - : base(playlistItem, new PlayerConfiguration + public MultiplayerPlayer(Room room, PlaylistItem playlistItem, MultiplayerRoomUser[] users) + : base(room, playlistItem, new PlayerConfiguration { AllowPause = false, AllowRestart = false, @@ -92,7 +93,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer } }); - LoadComponentAsync(new GameplayChatDisplay + LoadComponentAsync(new GameplayChatDisplay(Room) { Expanded = { BindTarget = HUDOverlay.ShowHud }, }, chat => leaderboardFlow.Insert(2, chat)); @@ -186,10 +187,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override ResultsScreen CreateResults(ScoreInfo score) { - Debug.Assert(RoomId.Value != null); + Debug.Assert(Room.RoomID.Value != null); + return leaderboard.TeamScores.Count == 2 - ? new MultiplayerTeamResultsScreen(score, RoomId.Value.Value, PlaylistItem, leaderboard.TeamScores) - : new MultiplayerResultsScreen(score, RoomId.Value.Value, PlaylistItem); + ? new MultiplayerTeamResultsScreen(score, Room.RoomID.Value.Value, PlaylistItem, leaderboard.TeamScores) + : new MultiplayerResultsScreen(score, Room.RoomID.Value.Value, PlaylistItem); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs index 567ea6b988..c76bad7828 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs @@ -20,8 +20,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { public Action Exited; - public PlaylistsPlayer(PlaylistItem playlistItem, PlayerConfiguration configuration = null) - : base(playlistItem, configuration) + public PlaylistsPlayer(Room room, PlaylistItem playlistItem, PlayerConfiguration configuration = null) + : base(room, playlistItem, configuration) { } @@ -51,8 +51,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists protected override ResultsScreen CreateResults(ScoreInfo score) { - Debug.Assert(RoomId.Value != null); - return new PlaylistsResultsScreen(score, RoomId.Value.Value, PlaylistItem, true); + Debug.Assert(Room.RoomID.Value != null); + return new PlaylistsResultsScreen(score, Room.RoomID.Value.Value, PlaylistItem, true); } protected override async Task PrepareScoreForResultsAsync(Score score) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 98fed3b467..a9ce9c52c4 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -158,7 +158,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists }, new Drawable[] { leaderboard = new MatchLeaderboard { RelativeSizeAxes = Axes.Both }, }, new Drawable[] { new OverlinedHeader("Chat"), }, - new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } + new Drawable[] { new MatchChatDisplay(Room) { RelativeSizeAxes = Axes.Both } } }, RowDimensions = new[] { @@ -199,7 +199,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists Logger.Log($"Polling adjusted (selection: {selectionPollingComponent.TimeBetweenPolls.Value})"); } - protected override Screen CreateGameplayScreen() => new PlayerLoader(() => new PlaylistsPlayer(SelectedItem.Value) + protected override Screen CreateGameplayScreen() => new PlayerLoader(() => new PlaylistsPlayer(Room, SelectedItem.Value) { Exited = () => leaderboard.RefreshScores() }); diff --git a/osu.Game/Screens/Play/RoomSubmittingPlayer.cs b/osu.Game/Screens/Play/RoomSubmittingPlayer.cs index 7ba12f5db6..1002e7607f 100644 --- a/osu.Game/Screens/Play/RoomSubmittingPlayer.cs +++ b/osu.Game/Screens/Play/RoomSubmittingPlayer.cs @@ -1,8 +1,7 @@ // 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.Bindables; +using System.Diagnostics; using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Scoring; @@ -14,25 +13,28 @@ namespace osu.Game.Screens.Play /// public abstract class RoomSubmittingPlayer : SubmittingPlayer { - [Resolved(typeof(Room), nameof(Room.RoomID))] - protected Bindable RoomId { get; private set; } - protected readonly PlaylistItem PlaylistItem; + protected readonly Room Room; - protected RoomSubmittingPlayer(PlaylistItem playlistItem, PlayerConfiguration configuration = null) + protected RoomSubmittingPlayer(Room room, PlaylistItem playlistItem, PlayerConfiguration configuration = null) : base(configuration) { + Room = room; PlaylistItem = playlistItem; } protected override APIRequest CreateTokenRequest() { - if (!(RoomId.Value is long roomId)) + if (!(Room.RoomID.Value is long roomId)) return null; return new CreateRoomScoreRequest(roomId, PlaylistItem.ID, Game.VersionHash); } - protected override APIRequest CreateSubmissionRequest(Score score, long token) => new SubmitRoomScoreRequest(token, RoomId.Value ?? 0, PlaylistItem.ID, score.ScoreInfo); + protected override APIRequest CreateSubmissionRequest(Score score, long token) + { + Debug.Assert(Room.RoomID.Value != null); + return new SubmitRoomScoreRequest(token, Room.RoomID.Value.Value, PlaylistItem.ID, score.ScoreInfo); + } } }