diff --git a/README.md b/README.md index 24b70b2de6..f18c5e76f9 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ You can see some examples of custom rulesets by visiting the [custom ruleset dir Please make sure you have the following prerequisites: -- A desktop platform with the [.NET 5.0 SDK](https://dotnet.microsoft.com/download) or higher installed. +- A desktop platform with the [.NET 5.0 SDK](https://dotnet.microsoft.com/download) installed. - When developing with mobile, [Xamarin](https://docs.microsoft.com/en-us/xamarin/) is required, which is shipped together with Visual Studio or [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/). - When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as [Visual Studio 2019+](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/). - When running on Linux, please have a system-wide FFmpeg installation available to support video decoding. diff --git a/osu.Android.props b/osu.Android.props index 563836d29b..1532d4ce23 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs b/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs index 3211405670..844fe7705a 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs @@ -85,6 +85,7 @@ namespace osu.Game.Tests.Visual.Background // of note, this needs to be a type that doesn't match BackgroundScreenDefault else it is silently not pushed by the background stack. AddStep("push new background to stack", () => stack.Push(nestedScreen = new BackgroundScreenBeatmap(Beatmap.Value))); AddUntilStep("wait for screen to load", () => nestedScreen.IsLoaded && nestedScreen.IsCurrentScreen()); + AddUntilStep("previous background hidden", () => !screen.IsAlive); AddAssert("top level background hasn't changed yet", () => screen.CheckLastLoadChange() == null); diff --git a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs index 357db16e2c..5acb44ac45 100644 --- a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs @@ -31,17 +31,16 @@ namespace osu.Game.Tests.Visual.Multiplayer protected BeatmapInfo InitialBeatmap { get; private set; } protected BeatmapInfo OtherBeatmap { get; private set; } - protected IScreen CurrentScreen => multiplayerScreenStack.CurrentScreen; - protected IScreen CurrentSubScreen => multiplayerScreenStack.MultiplayerScreen.CurrentSubScreen; + protected IScreen CurrentScreen => multiplayerComponents.CurrentScreen; + protected IScreen CurrentSubScreen => multiplayerComponents.MultiplayerScreen.CurrentSubScreen; private BeatmapManager beatmaps; private RulesetStore rulesets; private BeatmapSetInfo importedSet; - private TestMultiplayerScreenStack multiplayerScreenStack; + private TestMultiplayerComponents multiplayerComponents; - protected TestMultiplayerClient Client => multiplayerScreenStack.Client; - protected TestMultiplayerRoomManager RoomManager => multiplayerScreenStack.RoomManager; + protected TestMultiplayerClient Client => multiplayerComponents.Client; [Cached(typeof(UserLookupCache))] private UserLookupCache lookupCache = new TestUserLookupCache(); @@ -65,12 +64,12 @@ namespace osu.Game.Tests.Visual.Multiplayer OtherBeatmap = importedSet.Beatmaps.Last(b => b.RulesetID == 0); }); - AddStep("load multiplayer", () => LoadScreen(multiplayerScreenStack = new TestMultiplayerScreenStack())); - AddUntilStep("wait for multiplayer to load", () => multiplayerScreenStack.IsLoaded); + AddStep("load multiplayer", () => LoadScreen(multiplayerComponents = new TestMultiplayerComponents())); + AddUntilStep("wait for multiplayer to load", () => multiplayerComponents.IsLoaded); AddUntilStep("wait for lounge to load", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); - AddUntilStep("wait for lounge", () => multiplayerScreenStack.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); - AddStep("open room", () => multiplayerScreenStack.ChildrenOfType().Single().Open(new Room + AddUntilStep("wait for lounge", () => multiplayerComponents.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); + AddStep("open room", () => multiplayerComponents.ChildrenOfType().Single().Open(new Room { Name = { Value = "Test Room" }, QueueMode = { Value = Mode }, @@ -93,7 +92,7 @@ namespace osu.Game.Tests.Visual.Multiplayer InputManager.Click(MouseButton.Left); }); - AddUntilStep("wait for join", () => RoomManager.RoomJoined); + AddUntilStep("wait for join", () => Client.RoomJoined); } [Test] @@ -110,8 +109,8 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for ready", () => Client.LocalUser?.State == MultiplayerUserState.Ready); clickReadyButton(); - AddUntilStep("wait for player", () => multiplayerScreenStack.CurrentScreen is Player player && player.IsLoaded); - AddStep("exit player", () => multiplayerScreenStack.MultiplayerScreen.MakeCurrent()); + AddUntilStep("wait for player", () => multiplayerComponents.CurrentScreen is Player player && player.IsLoaded); + AddStep("exit player", () => multiplayerComponents.MultiplayerScreen.MakeCurrent()); } private void clickReadyButton() diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 710855a605..bd0e5c4eb9 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -46,10 +46,10 @@ namespace osu.Game.Tests.Visual.Multiplayer private RulesetStore rulesets; private BeatmapSetInfo importedSet; - private TestMultiplayerScreenStack multiplayerScreenStack; + private TestMultiplayerComponents multiplayerComponents; - private TestMultiplayerClient client => multiplayerScreenStack.Client; - private TestMultiplayerRoomManager roomManager => multiplayerScreenStack.RoomManager; + private TestMultiplayerClient client => multiplayerComponents.Client; + private TestMultiplayerRoomManager roomManager => multiplayerComponents.RoomManager; [Cached(typeof(UserLookupCache))] private UserLookupCache lookupCache = new TestUserLookupCache(); @@ -71,8 +71,8 @@ namespace osu.Game.Tests.Visual.Multiplayer importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First(); }); - AddStep("load multiplayer", () => LoadScreen(multiplayerScreenStack = new TestMultiplayerScreenStack())); - AddUntilStep("wait for multiplayer to load", () => multiplayerScreenStack.IsLoaded); + AddStep("load multiplayer", () => LoadScreen(multiplayerComponents = new TestMultiplayerComponents())); + AddUntilStep("wait for multiplayer to load", () => multiplayerComponents.IsLoaded); AddUntilStep("wait for lounge to load", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); } @@ -216,7 +216,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("Press select", () => InputManager.Key(Key.Enter)); AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); - AddUntilStep("wait for join", () => roomManager.RoomJoined); + AddUntilStep("wait for join", () => client.RoomJoined); } [Test] @@ -295,7 +295,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("join room", () => InputManager.Key(Key.Enter)); AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); - AddUntilStep("wait for join", () => roomManager.RoomJoined); + AddUntilStep("wait for join", () => client.RoomJoined); AddAssert("Check participant count correct", () => client.APIRoom?.ParticipantCount.Value == 1); AddAssert("Check participant list contains user", () => client.APIRoom?.RecentParticipants.Count(u => u.Id == API.LocalUser.Value.Id) == 1); @@ -353,7 +353,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType().First().TriggerClick()); AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); - AddUntilStep("wait for join", () => roomManager.RoomJoined); + AddUntilStep("wait for join", () => client.RoomJoined); } [Test] @@ -419,7 +419,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("Enter song select", () => { - var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerScreenStack.CurrentScreen).CurrentSubScreen; + var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen; ((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(client.Room?.Settings.PlaylistItemId); }); @@ -433,7 +433,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("start match externally", () => client.StartMatch()); - AddUntilStep("play started", () => multiplayerScreenStack.CurrentScreen is Player); + AddUntilStep("play started", () => multiplayerComponents.CurrentScreen is Player); AddAssert("Beatmap matches current item", () => Beatmap.Value.BeatmapInfo.OnlineID == client.Room?.Playlist.First().BeatmapID); } @@ -473,7 +473,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("start match externally", () => client.StartMatch()); - AddAssert("play not started", () => multiplayerScreenStack.IsCurrentScreen()); + AddAssert("play not started", () => multiplayerComponents.IsCurrentScreen()); } [Test] @@ -517,7 +517,7 @@ namespace osu.Game.Tests.Visual.Multiplayer importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First(); }); - AddUntilStep("play started", () => multiplayerScreenStack.CurrentScreen is SpectatorScreen); + AddUntilStep("play started", () => multiplayerComponents.CurrentScreen is SpectatorScreen); } [Test] @@ -559,16 +559,16 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("open mod overlay", () => this.ChildrenOfType().Single().TriggerClick()); - AddStep("invoke on back button", () => multiplayerScreenStack.OnBackButton()); + AddStep("invoke on back button", () => multiplayerComponents.OnBackButton()); AddAssert("mod overlay is hidden", () => this.ChildrenOfType().Single().State.Value == Visibility.Hidden); AddAssert("dialog overlay is hidden", () => DialogOverlay.State.Value == Visibility.Hidden); - testLeave("back button", () => multiplayerScreenStack.OnBackButton()); + testLeave("back button", () => multiplayerComponents.OnBackButton()); // mimics home button and OS window close - testLeave("forced exit", () => multiplayerScreenStack.Exit()); + testLeave("forced exit", () => multiplayerComponents.Exit()); void testLeave(string actionName, Action action) { @@ -605,7 +605,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep($"wait for time > {i}", () => this.ChildrenOfType().SingleOrDefault()?.GameplayClock.CurrentTime > time); } - AddUntilStep("wait for results", () => multiplayerScreenStack.CurrentScreen is ResultsScreen); + AddUntilStep("wait for results", () => multiplayerComponents.CurrentScreen is ResultsScreen); } [Test] @@ -646,7 +646,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("join room", () => InputManager.Key(Key.Enter)); AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); - AddUntilStep("wait for join", () => roomManager.RoomJoined); + AddUntilStep("wait for join", () => client.RoomJoined); AddAssert("local room has correct settings", () => { @@ -680,15 +680,15 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("set other user ready", () => client.ChangeUserState(1234, MultiplayerUserState.Ready)); pressReadyButton(1234); - AddUntilStep("wait for gameplay", () => (multiplayerScreenStack.CurrentScreen as MultiSpectatorScreen)?.IsLoaded == true); + AddUntilStep("wait for gameplay", () => (multiplayerComponents.CurrentScreen as MultiSpectatorScreen)?.IsLoaded == true); AddStep("press back button and exit", () => { - multiplayerScreenStack.OnBackButton(); - multiplayerScreenStack.Exit(); + multiplayerComponents.OnBackButton(); + multiplayerComponents.Exit(); }); - AddUntilStep("wait for return to match subscreen", () => multiplayerScreenStack.MultiplayerScreen.IsCurrentScreen()); + AddUntilStep("wait for return to match subscreen", () => multiplayerComponents.MultiplayerScreen.IsCurrentScreen()); AddUntilStep("user state is idle", () => client.LocalUser?.State == MultiplayerUserState.Idle); } @@ -716,17 +716,17 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("set other user ready", () => client.ChangeUserState(1234, MultiplayerUserState.Ready)); pressReadyButton(1234); - AddUntilStep("wait for gameplay", () => (multiplayerScreenStack.CurrentScreen as MultiSpectatorScreen)?.IsLoaded == true); + AddUntilStep("wait for gameplay", () => (multiplayerComponents.CurrentScreen as MultiSpectatorScreen)?.IsLoaded == true); AddStep("set other user loaded", () => client.ChangeUserState(1234, MultiplayerUserState.Loaded)); AddStep("set other user finished play", () => client.ChangeUserState(1234, MultiplayerUserState.FinishedPlay)); AddStep("press back button and exit", () => { - multiplayerScreenStack.OnBackButton(); - multiplayerScreenStack.Exit(); + multiplayerComponents.OnBackButton(); + multiplayerComponents.Exit(); }); - AddUntilStep("wait for return to match subscreen", () => multiplayerScreenStack.MultiplayerScreen.IsCurrentScreen()); + AddUntilStep("wait for return to match subscreen", () => multiplayerComponents.MultiplayerScreen.IsCurrentScreen()); AddWaitStep("wait for possible state change", 5); AddUntilStep("user state is spectating", () => client.LocalUser?.State == MultiplayerUserState.Spectating); } @@ -758,7 +758,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("item arrived in playlist", () => client.Room?.Playlist.Count == 2); - AddStep("exit gameplay as initial user", () => multiplayerScreenStack.MultiplayerScreen.MakeCurrent()); + AddStep("exit gameplay as initial user", () => multiplayerComponents.MultiplayerScreen.MakeCurrent()); AddUntilStep("queue contains item", () => this.ChildrenOfType().Single().Items.Single().ID == 2); } @@ -792,7 +792,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("delete item as other user", () => client.RemoveUserPlaylistItem(1234, 2)); AddUntilStep("item removed from playlist", () => client.Room?.Playlist.Count == 1); - AddStep("exit gameplay as initial user", () => multiplayerScreenStack.MultiplayerScreen.MakeCurrent()); + AddStep("exit gameplay as initial user", () => multiplayerComponents.MultiplayerScreen.MakeCurrent()); AddUntilStep("queue is empty", () => this.ChildrenOfType().Single().Items.Count == 0); } @@ -800,7 +800,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { pressReadyButton(); pressReadyButton(); - AddUntilStep("wait for player", () => multiplayerScreenStack.CurrentScreen is Player); + AddUntilStep("wait for player", () => multiplayerComponents.CurrentScreen is Player); } private ReadyButton readyButton => this.ChildrenOfType().Single(); @@ -826,8 +826,8 @@ namespace osu.Game.Tests.Visual.Multiplayer private void createRoom(Func room) { - AddUntilStep("wait for lounge", () => multiplayerScreenStack.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); - AddStep("open room", () => multiplayerScreenStack.ChildrenOfType().Single().Open(room())); + AddUntilStep("wait for lounge", () => multiplayerComponents.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); + AddStep("open room", () => multiplayerComponents.ChildrenOfType().Single().Open(room())); AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); AddWaitStep("wait for transition", 2); @@ -838,7 +838,7 @@ namespace osu.Game.Tests.Visual.Multiplayer InputManager.Click(MouseButton.Left); }); - AddUntilStep("wait for join", () => roomManager.RoomJoined); + AddUntilStep("wait for join", () => client.RoomJoined); } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs index 84b63a5733..81220e2527 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs @@ -163,10 +163,13 @@ namespace osu.Game.Tests.Visual.Multiplayer }); addClickButtonStep(); + AddUntilStep("user is ready", () => Client.Room?.Users[0].State == MultiplayerUserState.Ready); + AddStep("transfer host", () => Client.TransferHost(Client.Room?.Users[1].UserID ?? 0)); addClickButtonStep(); - AddAssert("match not started", () => Client.Room?.Users[0].State == MultiplayerUserState.Idle); + AddUntilStep("user is idle (match not started)", () => Client.Room?.Users[0].State == MultiplayerUserState.Idle); + AddAssert("ready button enabled", () => button.ChildrenOfType().Single().Enabled.Value); } [TestCase(true)] diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs index ccce26ad31..81c59b90f5 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs @@ -31,9 +31,9 @@ namespace osu.Game.Tests.Visual.Multiplayer private RulesetStore rulesets; private BeatmapSetInfo importedSet; - private TestMultiplayerScreenStack multiplayerScreenStack; + private TestMultiplayerComponents multiplayerComponents; - private TestMultiplayerClient client => multiplayerScreenStack.Client; + private TestMultiplayerClient client => multiplayerComponents.Client; [Cached(typeof(UserLookupCache))] private UserLookupCache lookupCache = new TestUserLookupCache(); @@ -55,8 +55,8 @@ namespace osu.Game.Tests.Visual.Multiplayer importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First(); }); - AddStep("load multiplayer", () => LoadScreen(multiplayerScreenStack = new TestMultiplayerScreenStack())); - AddUntilStep("wait for multiplayer to load", () => multiplayerScreenStack.IsLoaded); + AddStep("load multiplayer", () => LoadScreen(multiplayerComponents = new TestMultiplayerComponents())); + AddUntilStep("wait for multiplayer to load", () => multiplayerComponents.IsLoaded); AddUntilStep("wait for lounge to load", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); } @@ -103,7 +103,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("press own button", () => { - InputManager.MoveMouseTo(multiplayerScreenStack.ChildrenOfType().First()); + InputManager.MoveMouseTo(multiplayerComponents.ChildrenOfType().First()); InputManager.Click(MouseButton.Left); }); AddAssert("user on team 1", () => (client.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 1); @@ -113,7 +113,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("press other user's button", () => { - InputManager.MoveMouseTo(multiplayerScreenStack.ChildrenOfType().ElementAt(1)); + InputManager.MoveMouseTo(multiplayerComponents.ChildrenOfType().ElementAt(1)); InputManager.Click(MouseButton.Left); }); AddAssert("user still on team 0", () => (client.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 0); @@ -164,18 +164,18 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("room type is head to head", () => client.Room?.Settings.MatchType == MatchType.HeadToHead); - AddUntilStep("team displays are not displaying teams", () => multiplayerScreenStack.ChildrenOfType().All(d => d.DisplayedTeam == null)); + AddUntilStep("team displays are not displaying teams", () => multiplayerComponents.ChildrenOfType().All(d => d.DisplayedTeam == null)); AddStep("change to team vs", () => client.ChangeSettings(matchType: MatchType.TeamVersus)); AddUntilStep("room type is team vs", () => client.Room?.Settings.MatchType == MatchType.TeamVersus); - AddUntilStep("team displays are displaying teams", () => multiplayerScreenStack.ChildrenOfType().All(d => d.DisplayedTeam != null)); + AddUntilStep("team displays are displaying teams", () => multiplayerComponents.ChildrenOfType().All(d => d.DisplayedTeam != null)); } private void createRoom(Func room) { - AddStep("open room", () => multiplayerScreenStack.ChildrenOfType().Single().Open(room())); + AddStep("open room", () => multiplayerComponents.ChildrenOfType().Single().Open(room())); AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); AddWaitStep("wait for transition", 2); @@ -187,7 +187,7 @@ namespace osu.Game.Tests.Visual.Multiplayer InputManager.Click(MouseButton.Left); }); - AddUntilStep("wait for join", () => multiplayerScreenStack.RoomManager.RoomJoined); + AddUntilStep("wait for join", () => client.RoomJoined); } } } diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 664c186cf8..48ab643992 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -336,12 +336,12 @@ namespace osu.Game.Tests.Visual.Navigation [Test] public void TestPushMatchSubScreenAndPressBackButtonImmediately() { - TestMultiplayerScreenStack multiplayerScreenStack = null; + TestMultiplayerComponents multiplayerComponents = null; - PushAndConfirm(() => multiplayerScreenStack = new TestMultiplayerScreenStack()); + PushAndConfirm(() => multiplayerComponents = new TestMultiplayerComponents()); - AddUntilStep("wait for lounge", () => multiplayerScreenStack.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); - AddStep("open room", () => multiplayerScreenStack.ChildrenOfType().Single().Open()); + AddUntilStep("wait for lounge", () => multiplayerComponents.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); + AddStep("open room", () => multiplayerComponents.ChildrenOfType().Single().Open()); AddStep("press back button", () => Game.ChildrenOfType().First().Action()); AddWaitStep("wait two frames", 2); } diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs index 76997bded7..dda9543159 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs @@ -2,9 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; +using NUnit.Framework; using osu.Framework.Allocation; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests; +using osu.Framework.Testing; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Profile; @@ -14,72 +15,77 @@ namespace osu.Game.Tests.Visual.Online { public class TestSceneUserProfileHeader : OsuTestScene { - protected override bool UseOnlineAPI => true; - [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); - [Resolved] - private IAPIProvider api { get; set; } + private ProfileHeader header; - private readonly ProfileHeader header; - - public TestSceneUserProfileHeader() + [SetUpSteps] + public void SetUpSteps() { - header = new ProfileHeader(); - Add(header); + AddStep("create header", () => Child = header = new ProfileHeader()); + } - AddStep("Show test dummy", () => header.User.Value = TestSceneUserProfileOverlay.TEST_USER); + [Test] + public void TestBasic() + { + AddStep("Show example user", () => header.User.Value = TestSceneUserProfileOverlay.TEST_USER); + } - AddStep("Show null dummy", () => header.User.Value = new APIUser - { - Username = "Null" - }); - - AddStep("Show online dummy", () => header.User.Value = new APIUser + [Test] + public void TestOnlineState() + { + AddStep("Show online user", () => header.User.Value = new APIUser { + Id = 1001, Username = "IAmOnline", LastVisit = DateTimeOffset.Now, IsOnline = true, }); - AddStep("Show offline dummy", () => header.User.Value = new APIUser + AddStep("Show offline user", () => header.User.Value = new APIUser { + Id = 1002, Username = "IAmOffline", - LastVisit = DateTimeOffset.Now, + LastVisit = DateTimeOffset.Now.AddDays(-10), IsOnline = false, }); - - addOnlineStep("Show ppy", new APIUser - { - Username = @"peppy", - Id = 2, - IsSupporter = true, - Country = new Country { FullName = @"Australia", FlagName = @"AU" }, - CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg" - }); - - addOnlineStep("Show flyte", new APIUser - { - Username = @"flyte", - Id = 3103765, - Country = new Country { FullName = @"Japan", FlagName = @"JP" }, - CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg" - }); } - private void addOnlineStep(string name, APIUser fallback) + [Test] + public void TestRankedState() { - AddStep(name, () => + AddStep("Show ranked user", () => header.User.Value = new APIUser { - if (api.IsLoggedIn) + Id = 2001, + Username = "RankedUser", + Statistics = new UserStatistics { - var request = new GetUserRequest(fallback.Id); - request.Success += user => header.User.Value = user; - api.Queue(request); + IsRanked = true, + GlobalRank = 15000, + CountryRank = 1500, + RankHistory = new APIRankHistory + { + Mode = @"osu", + Data = Enumerable.Range(2345, 45).Concat(Enumerable.Range(2109, 40)).ToArray() + }, + } + }); + + AddStep("Show unranked user", () => header.User.Value = new APIUser + { + Id = 2002, + Username = "UnrankedUser", + Statistics = new UserStatistics + { + IsRanked = false, + // web will sometimes return non-empty rank history even for unranked users. + RankHistory = new APIRankHistory + { + Mode = @"osu", + Data = Enumerable.Range(2345, 85).ToArray() + }, } - else - header.User.Value = fallback; }); } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index 1c92bb1e38..78e2ceb45b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -29,6 +29,7 @@ namespace osu.Game.Tests.Visual.Online ProfileOrder = new[] { "me" }, Statistics = new UserStatistics { + IsRanked = true, GlobalRank = 2148, CountryRank = 1, PP = 4567.89m, diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs index 25ca1299ef..e9210496ca 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs @@ -168,12 +168,13 @@ namespace osu.Game.Tests.Visual.Playlists })); }); + AddUntilStep("wait for screen to load", () => resultsScreen.IsLoaded); waitForDisplay(); } private void waitForDisplay() { - AddUntilStep("wait for load to complete", () => + AddUntilStep("wait for scores loaded", () => requestComplete && resultsScreen.ScorePanelList.GetScorePanels().Count() == totalCount && resultsScreen.ScorePanelList.AllPanelsVisible); diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index be390742ea..912d3f838c 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -466,7 +466,9 @@ namespace osu.Game.Tests.Visual.SongSelect public void TestExternalBeatmapChangeWhileFiltered(bool differentRuleset) { createSongSelect(); - addManyTestMaps(); + // ensure there is at least 1 difficulty for each of the rulesets + // (catch is excluded inside of addManyTestMaps). + addManyTestMaps(3); changeRuleset(0); @@ -488,8 +490,9 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("select beatmap externally", () => { target = manager.GetAllUsableBeatmapSets() - .Where(b => b.Beatmaps.Any(bi => bi.RulesetID == targetRuleset)) - .ElementAt(5).Beatmaps.First(bi => bi.RulesetID == targetRuleset); + .First(b => b.Beatmaps.Any(bi => bi.RulesetID == targetRuleset)) + .Beatmaps + .First(bi => bi.RulesetID == targetRuleset); Beatmap.Value = manager.GetWorkingBeatmap(target); }); @@ -518,7 +521,9 @@ namespace osu.Game.Tests.Visual.SongSelect public void TestExternalBeatmapChangeWhileFilteredThenRefilter() { createSongSelect(); - addManyTestMaps(); + // ensure there is at least 1 difficulty for each of the rulesets + // (catch is excluded inside of addManyTestMaps). + addManyTestMaps(3); changeRuleset(0); @@ -534,8 +539,10 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("select beatmap externally", () => { - target = manager.GetAllUsableBeatmapSets().Where(b => b.Beatmaps.Any(bi => bi.RulesetID == 1)) - .ElementAt(5).Beatmaps.First(); + target = manager + .GetAllUsableBeatmapSets() + .First(b => b.Beatmaps.Any(bi => bi.RulesetID == 1)) + .Beatmaps.First(); Beatmap.Value = manager.GetWorkingBeatmap(target); }); @@ -877,14 +884,21 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("wait for carousel loaded", () => songSelect.Carousel.IsAlive); } - private void addManyTestMaps() + /// + /// Imports test beatmap sets to show in the carousel. + /// + /// + /// The exact count of difficulties to create for each beatmap set. + /// A value causes the count of difficulties to be selected randomly. + /// + private void addManyTestMaps(int? difficultyCountPerSet = null) { AddStep("import test maps", () => { var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray(); - for (int i = 0; i < 100; i += 10) - manager.Import(TestResources.CreateTestBeatmapSetInfo(rulesets: usableRulesets)).Wait(); + for (int i = 0; i < 10; i++) + manager.Import(TestResources.CreateTestBeatmapSetInfo(difficultyCountPerSet, usableRulesets)).Wait(); }); } diff --git a/osu.Game.Tests/Visual/TestMultiplayerScreenStack.cs b/osu.Game.Tests/Visual/TestMultiplayerComponents.cs similarity index 91% rename from osu.Game.Tests/Visual/TestMultiplayerScreenStack.cs rename to osu.Game.Tests/Visual/TestMultiplayerComponents.cs index 370f3bd0ae..cd7a936778 100644 --- a/osu.Game.Tests/Visual/TestMultiplayerScreenStack.cs +++ b/osu.Game.Tests/Visual/TestMultiplayerComponents.cs @@ -26,7 +26,7 @@ namespace osu.Game.Tests.Visual /// ///

/// - public class TestMultiplayerScreenStack : OsuScreen + public class TestMultiplayerComponents : OsuScreen { public Screens.OnlinePlay.Multiplayer.Multiplayer MultiplayerScreen => multiplayerScreen; @@ -42,14 +42,18 @@ namespace osu.Game.Tests.Visual private readonly OsuScreenStack screenStack; private readonly TestMultiplayer multiplayerScreen; - public TestMultiplayerScreenStack() + public TestMultiplayerComponents() { multiplayerScreen = new TestMultiplayer(); InternalChildren = new Drawable[] { Client = new TestMultiplayerClient(RoomManager), - screenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both } + screenStack = new OsuScreenStack + { + Name = nameof(TestMultiplayerComponents), + RelativeSizeAxes = Axes.Both + } }; screenStack.Push(multiplayerScreen); diff --git a/osu.Game/Database/RealmLiveUnmanaged.cs b/osu.Game/Database/RealmLiveUnmanaged.cs index 5a69898206..ea50ccc1ff 100644 --- a/osu.Game/Database/RealmLiveUnmanaged.cs +++ b/osu.Game/Database/RealmLiveUnmanaged.cs @@ -26,6 +26,8 @@ namespace osu.Game.Database public bool Equals(ILive? other) => ID == other?.ID; + public override string ToString() => Value.ToString(); + public Guid ID => Value.ID; public void PerformRead(Action perform) => perform(Value); diff --git a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs index d6e515d8a1..d195babcbf 100644 --- a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs +++ b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs @@ -42,7 +42,9 @@ namespace osu.Game.Overlays.Profile.Header.Components private void updateStatistics(UserStatistics statistics) { - int[] userRanks = statistics?.RankHistory?.Data; + // checking both IsRanked and RankHistory is required. + // see https://github.com/ppy/osu-web/blob/154ceafba0f35a1dd935df53ec98ae2ea5615f9f/resources/assets/lib/profile-page/rank-chart.tsx#L46 + int[] userRanks = statistics?.IsRanked == true ? statistics.RankHistory?.Data : null; Data = userRanks?.Select((x, index) => new KeyValuePair(index, x)).Where(x => x.Value != 0).ToArray(); } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs index c3190cd845..48f153ecbe 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs @@ -87,7 +87,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate gameplayContent.Child = new PlayerIsolationContainer(beatmapManager.GetWorkingBeatmap(Score.ScoreInfo.BeatmapInfo), Score.ScoreInfo.Ruleset, Score.ScoreInfo.Mods) { RelativeSizeAxes = Axes.Both, - Child = stack = new OsuScreenStack() + Child = stack = new OsuScreenStack + { + Name = nameof(PlayerArea), + } }; stack.Push(new MultiSpectatorPlayerLoader(Score, () => new MultiSpectatorPlayer(Score, GameplayClock))); diff --git a/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs index 5656704abf..7607122ef0 100644 --- a/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs +++ b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs @@ -24,7 +24,7 @@ namespace osu.Game.Tests.Visual.Multiplayer protected new MultiplayerTestSceneDependencies OnlinePlayDependencies => (MultiplayerTestSceneDependencies)base.OnlinePlayDependencies; - public bool RoomJoined => RoomManager.RoomJoined; + public bool RoomJoined => Client.RoomJoined; private readonly bool joinRoom; diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 4e0cfe405e..5b08b6b835 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -31,9 +31,10 @@ namespace osu.Game.Tests.Visual.Multiplayer private readonly Bindable isConnected = new Bindable(true); public new Room? APIRoom => base.APIRoom; - public Action? RoomSetupAction; + public bool RoomJoined { get; private set; } + [Resolved] private IAPIProvider api { get; set; } = null!; @@ -49,7 +50,6 @@ namespace osu.Game.Tests.Visual.Multiplayer private MultiplayerPlaylistItem? currentItem => Room?.Playlist[currentIndex]; private int currentIndex; - private long lastPlaylistItemId; public TestMultiplayerClient(TestMultiplayerRoomManager roomManager) @@ -217,9 +217,15 @@ namespace osu.Game.Tests.Visual.Multiplayer // emulate the server sending this after the join room. scheduler required to make sure the join room event is fired first (in Join). changeMatchType(Room.Settings.MatchType).Wait(); + + RoomJoined = true; } - protected override Task LeaveRoomInternal() => Task.CompletedTask; + protected override Task LeaveRoomInternal() + { + RoomJoined = false; + return Task.CompletedTask; + } public override Task TransferHost(int userId) => ((IMultiplayerClient)this).HostChanged(userId); diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs index a1f010f082..296db3152d 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs @@ -17,8 +17,6 @@ namespace osu.Game.Tests.Visual.Multiplayer /// public class TestMultiplayerRoomManager : MultiplayerRoomManager { - public bool RoomJoined { get; private set; } - private readonly TestRoomRequestsHandler requestsHandler; public TestMultiplayerRoomManager(TestRoomRequestsHandler requestsHandler) @@ -29,28 +27,10 @@ namespace osu.Game.Tests.Visual.Multiplayer public IReadOnlyList ServerSideRooms => requestsHandler.ServerSideRooms; public override void CreateRoom(Room room, Action onSuccess = null, Action onError = null) - { - base.CreateRoom(room, r => - { - onSuccess?.Invoke(r); - RoomJoined = true; - }, onError); - } + => base.CreateRoom(room, r => onSuccess?.Invoke(r), onError); public override void JoinRoom(Room room, string password = null, Action onSuccess = null, Action onError = null) - { - base.JoinRoom(room, password, r => - { - onSuccess?.Invoke(r); - RoomJoined = true; - }, onError); - } - - public override void PartRoom() - { - base.PartRoom(); - RoomJoined = false; - } + => base.JoinRoom(room, password, r => onSuccess?.Invoke(r), onError); /// /// Adds a room to a local "server-side" list that's returned when a is fired. diff --git a/osu.Game/Tests/Visual/ScreenTestScene.cs b/osu.Game/Tests/Visual/ScreenTestScene.cs index aa46b516bf..c44a848275 100644 --- a/osu.Game/Tests/Visual/ScreenTestScene.cs +++ b/osu.Game/Tests/Visual/ScreenTestScene.cs @@ -29,7 +29,11 @@ namespace osu.Game.Tests.Visual { base.Content.AddRange(new Drawable[] { - Stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }, + Stack = new OsuScreenStack + { + Name = nameof(ScreenTestScene), + RelativeSizeAxes = Axes.Both + }, content = new Container { RelativeSizeAxes = Axes.Both }, DialogOverlay = new DialogOverlay() }); diff --git a/osu.Game/Users/UserStatistics.cs b/osu.Game/Users/UserStatistics.cs index c690447256..f8d26fe421 100644 --- a/osu.Game/Users/UserStatistics.cs +++ b/osu.Game/Users/UserStatistics.cs @@ -27,6 +27,9 @@ namespace osu.Game.Users public int Progress; } + [JsonProperty(@"is_ranked")] + public bool IsRanked; + [JsonProperty(@"global_rank")] public int? GlobalRank; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 0e8486cabc..6e6002bc8e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 42d8962c14..de359245d1 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -60,7 +60,7 @@ - + @@ -83,7 +83,7 @@ - +