1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-13 19:43:22 +08:00

Merge branch 'master' into beatmap-card/extra

This commit is contained in:
Bartłomiej Dach 2021-12-20 15:49:00 +01:00
commit f1a03aced5
No known key found for this signature in database
GPG Key ID: BCECCD4FA41F6497
23 changed files with 179 additions and 150 deletions

View File

@ -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.

View File

@ -52,7 +52,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1215.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1217.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1220.0" />
</ItemGroup>
<ItemGroup Label="Transitive Dependencies">
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->

View File

@ -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);

View File

@ -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<MultiplayerLoungeSubScreen>().FirstOrDefault()?.IsLoaded == true);
AddUntilStep("wait for lounge", () => multiplayerScreenStack.ChildrenOfType<LoungeSubScreen>().SingleOrDefault()?.IsLoaded == true);
AddStep("open room", () => multiplayerScreenStack.ChildrenOfType<LoungeSubScreen>().Single().Open(new Room
AddUntilStep("wait for lounge", () => multiplayerComponents.ChildrenOfType<LoungeSubScreen>().SingleOrDefault()?.IsLoaded == true);
AddStep("open room", () => multiplayerComponents.ChildrenOfType<LoungeSubScreen>().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()

View File

@ -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<MultiplayerLoungeSubScreen>().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<MultiplayerMatchSubScreen>().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<MultiplayerMatchSubScreen>().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<OsuButton>().First().TriggerClick());
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().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<RoomSubScreen.UserModSelectButton>().Single().TriggerClick());
AddStep("invoke on back button", () => multiplayerScreenStack.OnBackButton());
AddStep("invoke on back button", () => multiplayerComponents.OnBackButton());
AddAssert("mod overlay is hidden", () => this.ChildrenOfType<UserModSelectOverlay>().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<GameplayClockContainer>().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<MultiplayerMatchSubScreen>().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<MultiplayerQueueList>().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<MultiplayerQueueList>().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<ReadyButton>().Single();
@ -826,8 +826,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void createRoom(Func<Room> room)
{
AddUntilStep("wait for lounge", () => multiplayerScreenStack.ChildrenOfType<LoungeSubScreen>().SingleOrDefault()?.IsLoaded == true);
AddStep("open room", () => multiplayerScreenStack.ChildrenOfType<LoungeSubScreen>().Single().Open(room()));
AddUntilStep("wait for lounge", () => multiplayerComponents.ChildrenOfType<LoungeSubScreen>().SingleOrDefault()?.IsLoaded == true);
AddStep("open room", () => multiplayerComponents.ChildrenOfType<LoungeSubScreen>().Single().Open(room()));
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().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);
}
}
}

View File

@ -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<OsuButton>().Single().Enabled.Value);
}
[TestCase(true)]

View File

@ -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<MultiplayerLoungeSubScreen>().FirstOrDefault()?.IsLoaded == true);
}
@ -103,7 +103,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("press own button", () =>
{
InputManager.MoveMouseTo(multiplayerScreenStack.ChildrenOfType<TeamDisplay>().First());
InputManager.MoveMouseTo(multiplayerComponents.ChildrenOfType<TeamDisplay>().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<TeamDisplay>().ElementAt(1));
InputManager.MoveMouseTo(multiplayerComponents.ChildrenOfType<TeamDisplay>().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<TeamDisplay>().All(d => d.DisplayedTeam == null));
AddUntilStep("team displays are not displaying teams", () => multiplayerComponents.ChildrenOfType<TeamDisplay>().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<TeamDisplay>().All(d => d.DisplayedTeam != null));
AddUntilStep("team displays are displaying teams", () => multiplayerComponents.ChildrenOfType<TeamDisplay>().All(d => d.DisplayedTeam != null));
}
private void createRoom(Func<Room> room)
{
AddStep("open room", () => multiplayerScreenStack.ChildrenOfType<LoungeSubScreen>().Single().Open(room()));
AddStep("open room", () => multiplayerComponents.ChildrenOfType<LoungeSubScreen>().Single().Open(room()));
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().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);
}
}
}

View File

@ -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<LoungeSubScreen>().SingleOrDefault()?.IsLoaded == true);
AddStep("open room", () => multiplayerScreenStack.ChildrenOfType<LoungeSubScreen>().Single().Open());
AddUntilStep("wait for lounge", () => multiplayerComponents.ChildrenOfType<LoungeSubScreen>().SingleOrDefault()?.IsLoaded == true);
AddStep("open room", () => multiplayerComponents.ChildrenOfType<LoungeSubScreen>().Single().Open());
AddStep("press back button", () => Game.ChildrenOfType<BackButton>().First().Action());
AddWaitStep("wait two frames", 2);
}

View File

@ -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;
});
}
}

View File

@ -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,

View File

@ -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);

View File

@ -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()
/// <summary>
/// Imports test beatmap sets to show in the carousel.
/// </summary>
/// <param name="difficultyCountPerSet">
/// The exact count of difficulties to create for each beatmap set.
/// A <see langword="null"/> value causes the count of difficulties to be selected randomly.
/// </param>
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();
});
}

View File

@ -26,7 +26,7 @@ namespace osu.Game.Tests.Visual
/// </list>
/// </p>
/// </summary>
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);

View File

@ -26,6 +26,8 @@ namespace osu.Game.Database
public bool Equals(ILive<T>? other) => ID == other?.ID;
public override string ToString() => Value.ToString();
public Guid ID => Value.ID;
public void PerformRead(Action<T> perform) => perform(Value);

View File

@ -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<int, int>(index, x)).Where(x => x.Value != 0).ToArray();
}

View File

@ -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)));

View File

@ -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;

View File

@ -31,9 +31,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
private readonly Bindable<bool> isConnected = new Bindable<bool>(true);
public new Room? APIRoom => base.APIRoom;
public Action<MultiplayerRoom>? 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);

View File

@ -17,8 +17,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
/// </summary>
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<Room> ServerSideRooms => requestsHandler.ServerSideRooms;
public override void CreateRoom(Room room, Action<Room> onSuccess = null, Action<string> 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<Room> onSuccess = null, Action<string> 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);
/// <summary>
/// Adds a room to a local "server-side" list that's returned when a <see cref="GetRoomsRequest"/> is fired.

View File

@ -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()
});

View File

@ -27,6 +27,9 @@ namespace osu.Game.Users
public int Progress;
}
[JsonProperty(@"is_ranked")]
public bool IsRanked;
[JsonProperty(@"global_rank")]
public int? GlobalRank;

View File

@ -36,7 +36,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Realm" Version="10.7.1" />
<PackageReference Include="ppy.osu.Framework" Version="2021.1217.0" />
<PackageReference Include="ppy.osu.Framework" Version="2021.1220.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1215.0" />
<PackageReference Include="Sentry" Version="3.12.1" />
<PackageReference Include="SharpCompress" Version="0.30.1" />

View File

@ -60,7 +60,7 @@
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.1217.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.1220.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1215.0" />
</ItemGroup>
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
@ -83,7 +83,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2021.1217.0" />
<PackageReference Include="ppy.osu.Framework" Version="2021.1220.0" />
<PackageReference Include="SharpCompress" Version="0.30.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="SharpRaven" Version="2.4.0" />