1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-15 11:47:18 +08:00

Merge branch 'master' into ui-scaling-keybind

This commit is contained in:
Bartłomiej Dach 2021-10-28 18:20:34 +02:00 committed by GitHub
commit 9199f2b337
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 579 additions and 437 deletions

View File

@ -15,7 +15,7 @@
]
},
"smoogipoo.nvika": {
"version": "1.0.1",
"version": "1.0.3",
"commands": [
"nvika"
]
@ -33,4 +33,4 @@
]
}
}
}
}

View File

@ -145,7 +145,7 @@ namespace osu.Game.Rulesets.Catch.Objects
public double Distance => Path.Distance;
public List<IList<HitSampleInfo>> NodeSamples { get; set; } = new List<IList<HitSampleInfo>>();
public IList<IList<HitSampleInfo>> NodeSamples { get; set; } = new List<IList<HitSampleInfo>>();
public double? LegacyLastTickOffset { get; set; }
}

View File

@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Tests
private IList<string> getSampleNames(IList<HitSampleInfo> hitSampleInfo)
=> hitSampleInfo.Select(sample => sample.LookupNames.First()).ToList();
private IList<IList<string>> getNodeSampleNames(List<IList<HitSampleInfo>> hitSampleInfo)
private IList<IList<string>> getNodeSampleNames(IList<IList<HitSampleInfo>> hitSampleInfo)
=> hitSampleInfo?.Select(getSampleNames)
.ToList();

View File

@ -488,7 +488,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// Retrieves the list of node samples that occur at time greater than or equal to <paramref name="time"/>.
/// </summary>
/// <param name="time">The time to retrieve node samples at.</param>
private List<IList<HitSampleInfo>> nodeSamplesAt(int time)
private IList<IList<HitSampleInfo>> nodeSamplesAt(int time)
{
if (!(HitObject is IHasPathWithRepeats curveData))
return null;

View File

@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Mania.Objects
}
}
public List<IList<HitSampleInfo>> NodeSamples { get; set; }
public IList<IList<HitSampleInfo>> NodeSamples { get; set; }
/// <summary>
/// The head note of the hold.

View File

@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Osu.Objects
/// </summary>
internal float LazyTravelDistance;
public List<IList<HitSampleInfo>> NodeSamples { get; set; } = new List<IList<HitSampleInfo>>();
public IList<IList<HitSampleInfo>> NodeSamples { get; set; } = new List<IList<HitSampleInfo>>();
[JsonIgnore]
public IList<HitSampleInfo> TailSamples { get; private set; }

View File

@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
{
if (shouldConvertSliderToHits(obj, beatmap, distanceData, out int taikoDuration, out double tickSpacing))
{
List<IList<HitSampleInfo>> allSamples = obj is IHasPathWithRepeats curveData ? curveData.NodeSamples : new List<IList<HitSampleInfo>>(new[] { samples });
IList<IList<HitSampleInfo>> allSamples = obj is IHasPathWithRepeats curveData ? curveData.NodeSamples : new List<IList<HitSampleInfo>>(new[] { samples });
int i = 0;

View File

@ -38,8 +38,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait();
}
[Test]
@ -204,7 +202,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestDownloadButtonHiddenWhenBeatmapExists()
{
createPlaylist(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo);
var beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
AddStep("import beatmap", () => manager.Import(beatmap.BeatmapSet).Wait());
createPlaylist(beatmap);
assertDownloadButtonVisible(false);

View File

@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneLoungeRoomsContainer : OnlinePlayTestScene
{
protected new TestRequestHandlingRoomManager RoomManager => (TestRequestHandlingRoomManager)base.RoomManager;
protected new TestRoomManager RoomManager => (TestRoomManager)base.RoomManager;
private RoomsContainer container;

View File

@ -23,8 +23,6 @@ using osu.Game.Overlays.Mods;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Lounge;
using osu.Game.Screens.OnlinePlay.Lounge.Components;
using osu.Game.Screens.OnlinePlay.Match;
@ -32,6 +30,7 @@ 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.Screens.Spectate;
using osu.Game.Tests.Resources;
using osu.Game.Users;
using osuTK.Input;
@ -44,11 +43,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
private RulesetStore rulesets;
private BeatmapSetInfo importedSet;
private DependenciesScreen dependenciesScreen;
private TestMultiplayer multiplayerScreen;
private TestMultiplayerClient client;
private TestMultiplayerScreenStack multiplayerScreenStack;
private TestRequestHandlingMultiplayerRoomManager roomManager => multiplayerScreen.RoomManager;
private TestMultiplayerClient client => multiplayerScreenStack.Client;
private TestMultiplayerRoomManager roomManager => multiplayerScreenStack.RoomManager;
[Cached(typeof(UserLookupCache))]
private UserLookupCache lookupCache = new TestUserLookupCache();
@ -70,22 +68,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
});
AddStep("create multiplayer screen", () => multiplayerScreen = new TestMultiplayer());
AddStep("load dependencies", () =>
{
client = new TestMultiplayerClient(roomManager);
// The screen gets suspended so it stops receiving updates.
Child = client;
LoadScreen(dependenciesScreen = new DependenciesScreen(client));
});
AddUntilStep("wait for dependencies to load", () => dependenciesScreen.IsLoaded);
AddStep("load multiplayer", () => LoadScreen(multiplayerScreen));
AddUntilStep("wait for multiplayer to load", () => multiplayerScreen.IsLoaded);
AddStep("load multiplayer", () => LoadScreen(multiplayerScreenStack = new TestMultiplayerScreenStack()));
AddUntilStep("wait for multiplayer to load", () => multiplayerScreenStack.IsLoaded);
AddUntilStep("wait for lounge to load", () => this.ChildrenOfType<MultiplayerLoungeSubScreen>().FirstOrDefault()?.IsLoaded == true);
}
@ -441,7 +425,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("start match externally", () => client.StartMatch());
AddAssert("play not started", () => multiplayerScreen.IsCurrentScreen());
AddAssert("play not started", () => multiplayerScreenStack.IsCurrentScreen());
}
[Test]
@ -485,7 +469,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
});
AddUntilStep("play started", () => !multiplayerScreen.IsCurrentScreen());
AddUntilStep("play started", () => multiplayerScreenStack.CurrentScreen is SpectatorScreen);
}
[Test]
@ -527,16 +511,16 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("open mod overlay", () => this.ChildrenOfType<RoomSubScreen.UserModSelectButton>().Single().TriggerClick());
AddStep("invoke on back button", () => multiplayerScreen.OnBackButton());
AddStep("invoke on back button", () => multiplayerScreenStack.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", () => multiplayerScreen.OnBackButton());
testLeave("back button", () => multiplayerScreenStack.OnBackButton());
// mimics home button and OS window close
testLeave("forced exit", () => multiplayerScreen.Exit());
testLeave("forced exit", () => multiplayerScreenStack.Exit());
void testLeave(string actionName, Action action)
{
@ -577,7 +561,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("click start button", () => InputManager.Click(MouseButton.Left));
AddUntilStep("wait for player", () => Stack.CurrentScreen is Player);
AddUntilStep("wait for player", () => multiplayerScreenStack.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)
@ -586,15 +570,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep($"wait for time > {i}", () => this.ChildrenOfType<GameplayClockContainer>().SingleOrDefault()?.GameplayClock.CurrentTime > time);
}
AddUntilStep("wait for results", () => Stack.CurrentScreen is ResultsScreen);
AddUntilStep("wait for results", () => multiplayerScreenStack.CurrentScreen is ResultsScreen);
}
private MultiplayerReadyButton readyButton => this.ChildrenOfType<MultiplayerReadyButton>().Single();
private void createRoom(Func<Room> room)
{
AddUntilStep("wait for lounge", () => multiplayerScreen.ChildrenOfType<LoungeSubScreen>().SingleOrDefault()?.IsLoaded == true);
AddStep("open room", () => multiplayerScreen.ChildrenOfType<LoungeSubScreen>().Single().Open(room()));
AddUntilStep("wait for lounge", () => multiplayerScreenStack.ChildrenOfType<LoungeSubScreen>().SingleOrDefault()?.IsLoaded == true);
AddStep("open room", () => multiplayerScreenStack.ChildrenOfType<LoungeSubScreen>().Single().Open(room()));
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
AddWaitStep("wait for transition", 2);
@ -607,26 +591,5 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for join", () => client.Room != null);
}
/// <summary>
/// Used for the sole purpose of adding <see cref="TestMultiplayerClient"/> as a resolvable dependency.
/// </summary>
private class DependenciesScreen : OsuScreen
{
[Cached(typeof(MultiplayerClient))]
public readonly TestMultiplayerClient Client;
public DependenciesScreen(TestMultiplayerClient client)
{
Client = client;
}
}
private class TestMultiplayer : Screens.OnlinePlay.Multiplayer.Multiplayer
{
public new TestRequestHandlingMultiplayerRoomManager RoomManager { get; private set; }
protected override RoomManager CreateRoomManager() => RoomManager = new TestRequestHandlingMultiplayerRoomManager();
}
}
}

View File

@ -8,7 +8,6 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Configuration;
using osu.Game.Online.API;
@ -40,9 +39,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
Dependencies.Cache(config = new OsuConfigManager(LocalStorage));
}
[SetUpSteps]
public override void SetUpSteps()
{
base.SetUpSteps();
AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = LookupCache.GetUserAsync(1).Result);
AddStep("create leaderboard", () =>

View File

@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Online.API;
using osu.Game.Online.Multiplayer;
@ -44,9 +43,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
return room;
}
[SetUpSteps]
public override void SetUpSteps()
{
base.SetUpSteps();
AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = LookupCache.GetUserAsync(1).Result);
AddStep("create leaderboard", () =>

View File

@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneMultiplayerLoungeSubScreen : OnlinePlayTestScene
{
protected new TestRequestHandlingRoomManager RoomManager => (TestRequestHandlingRoomManager)base.RoomManager;
protected new TestRoomManager RoomManager => (TestRoomManager)base.RoomManager;
private LoungeSubScreen loungeScreen;

View File

@ -4,7 +4,6 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
namespace osu.Game.Tests.Visual.Multiplayer
@ -14,8 +13,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
[SetUp]
public new void Setup() => Schedule(() =>
{
SelectedRoom.Value = new Room();
Child = new Container
{
Anchor = Anchor.Centre,

View File

@ -6,18 +6,14 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Graphics;
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.Multiplayer.MatchTypes.TeamVersus;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Lounge;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
@ -33,9 +29,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
private RulesetStore rulesets;
private BeatmapSetInfo importedSet;
private DependenciesScreen dependenciesScreen;
private TestMultiplayer multiplayerScreen;
private TestMultiplayerClient client;
private TestMultiplayerScreenStack multiplayerScreenStack;
private TestMultiplayerClient client => multiplayerScreenStack.Client;
[Cached(typeof(UserLookupCache))]
private UserLookupCache lookupCache = new TestUserLookupCache();
@ -57,24 +53,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
});
AddStep("create multiplayer screen", () => multiplayerScreen = new TestMultiplayer());
AddStep("load dependencies", () =>
{
client = new TestMultiplayerClient(multiplayerScreen.RoomManager);
// The screen gets suspended so it stops receiving updates.
Child = client;
LoadScreen(dependenciesScreen = new DependenciesScreen(client));
});
AddUntilStep("wait for dependencies screen", () => Stack.CurrentScreen is DependenciesScreen);
AddUntilStep("wait for dependencies to start load", () => dependenciesScreen.LoadState > LoadState.NotLoaded);
AddUntilStep("wait for dependencies to load", () => dependenciesScreen.IsLoaded);
AddStep("load multiplayer", () => LoadScreen(multiplayerScreen));
AddUntilStep("wait for multiplayer to load", () => multiplayerScreen.IsLoaded);
AddStep("load multiplayer", () => LoadScreen(multiplayerScreenStack = new TestMultiplayerScreenStack()));
AddUntilStep("wait for multiplayer to load", () => multiplayerScreenStack.IsLoaded);
AddUntilStep("wait for lounge to load", () => this.ChildrenOfType<MultiplayerLoungeSubScreen>().FirstOrDefault()?.IsLoaded == true);
}
@ -120,7 +100,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("press button", () =>
{
InputManager.MoveMouseTo(multiplayerScreen.ChildrenOfType<TeamDisplay>().First());
InputManager.MoveMouseTo(multiplayerScreenStack.ChildrenOfType<TeamDisplay>().First());
InputManager.Click(MouseButton.Left);
});
AddAssert("user on team 1", () => (client.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 1);
@ -154,7 +134,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void createRoom(Func<Room> room)
{
AddStep("open room", () => multiplayerScreen.ChildrenOfType<LoungeSubScreen>().Single().Open(room()));
AddStep("open room", () => multiplayerScreenStack.ChildrenOfType<LoungeSubScreen>().Single().Open(room()));
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
AddWaitStep("wait for transition", 2);
@ -167,26 +147,5 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for join", () => client.Room != null);
}
/// <summary>
/// Used for the sole purpose of adding <see cref="TestMultiplayerClient"/> as a resolvable dependency.
/// </summary>
private class DependenciesScreen : OsuScreen
{
[Cached(typeof(MultiplayerClient))]
public readonly TestMultiplayerClient Client;
public DependenciesScreen(TestMultiplayerClient client)
{
Client = client;
}
}
private class TestMultiplayer : Screens.OnlinePlay.Multiplayer.Multiplayer
{
public new TestRequestHandlingMultiplayerRoomManager RoomManager { get; private set; }
protected override RoomManager CreateRoomManager() => RoomManager = new TestRequestHandlingMultiplayerRoomManager();
}
}
}

View File

@ -9,21 +9,18 @@ using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
using osu.Game.Overlays;
using osu.Game.Overlays.Mods;
using osu.Game.Overlays.Toolbar;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Menu;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Lounge;
using osu.Game.Screens.Play;
using osu.Game.Screens.Ranking;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Options;
using osu.Game.Tests.Beatmaps.IO;
using osu.Game.Tests.Visual.Multiplayer;
using osuTK;
using osuTK.Input;
@ -333,12 +330,12 @@ namespace osu.Game.Tests.Visual.Navigation
[Test]
public void TestPushMatchSubScreenAndPressBackButtonImmediately()
{
TestMultiplayer multiplayer = null;
TestMultiplayerScreenStack multiplayerScreenStack = null;
PushAndConfirm(() => multiplayer = new TestMultiplayer());
PushAndConfirm(() => multiplayerScreenStack = new TestMultiplayerScreenStack());
AddUntilStep("wait for lounge", () => multiplayer.ChildrenOfType<LoungeSubScreen>().SingleOrDefault()?.IsLoaded == true);
AddStep("open room", () => multiplayer.ChildrenOfType<LoungeSubScreen>().Single().Open());
AddUntilStep("wait for lounge", () => multiplayerScreenStack.ChildrenOfType<LoungeSubScreen>().SingleOrDefault()?.IsLoaded == true);
AddStep("open room", () => multiplayerScreenStack.ChildrenOfType<LoungeSubScreen>().Single().Open());
AddStep("press back button", () => Game.ChildrenOfType<BackButton>().First().Action());
AddWaitStep("wait two frames", 2);
}
@ -453,18 +450,5 @@ namespace osu.Game.Tests.Visual.Navigation
protected override bool DisplayStableImportPrompt => false;
}
private class TestMultiplayer : Screens.OnlinePlay.Multiplayer.Multiplayer
{
[Cached(typeof(MultiplayerClient))]
public readonly TestMultiplayerClient Client;
public TestMultiplayer()
{
Client = new TestMultiplayerClient((TestRequestHandlingMultiplayerRoomManager)RoomManager);
}
protected override RoomManager CreateRoomManager() => new TestRequestHandlingMultiplayerRoomManager();
}
}
}

View File

@ -17,7 +17,7 @@ namespace osu.Game.Tests.Visual.Playlists
{
public class TestScenePlaylistsLoungeSubScreen : OnlinePlayTestScene
{
protected new TestRequestHandlingRoomManager RoomManager => (TestRequestHandlingRoomManager)base.RoomManager;
protected new TestRoomManager RoomManager => (TestRoomManager)base.RoomManager;
private TestLoungeSubScreen loungeScreen;

View File

@ -11,24 +11,27 @@ using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Screens.Play;
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Visual.OnlinePlay;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Playlists
{
public class TestScenePlaylistsRoomSubScreen : OnlinePlayTestScene
public class TestScenePlaylistsRoomCreation : OnlinePlayTestScene
{
private BeatmapManager manager;
private RulesetStore rulesets;
private TestPlaylistsRoomSubScreen match;
private ILive<BeatmapSetInfo> importedBeatmap;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
@ -40,7 +43,9 @@ namespace osu.Game.Tests.Visual.Playlists
public void SetupSteps()
{
AddStep("set room", () => SelectedRoom.Value = new Room());
AddStep("ensure has beatmap", () => manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait());
importBeatmap();
AddStep("load match", () => LoadScreen(match = new TestPlaylistsRoomSubScreen(SelectedRoom.Value)));
AddUntilStep("wait for load", () => match.IsCurrentScreen());
}
@ -48,44 +53,58 @@ namespace osu.Game.Tests.Visual.Playlists
[Test]
public void TestLoadSimpleMatch()
{
AddStep("set room properties", () =>
setupAndCreateRoom(room =>
{
SelectedRoom.Value.RoomID.Value = 1;
SelectedRoom.Value.Name.Value = "my awesome room";
SelectedRoom.Value.Host.Value = API.LocalUser.Value;
SelectedRoom.Value.RecentParticipants.Add(SelectedRoom.Value.Host.Value);
SelectedRoom.Value.EndDate.Value = DateTimeOffset.Now.AddMinutes(5);
SelectedRoom.Value.Playlist.Add(new PlaylistItem
room.Name.Value = "my awesome room";
room.Host.Value = API.LocalUser.Value;
room.RecentParticipants.Add(room.Host.Value);
room.EndDate.Value = DateTimeOffset.Now.AddMinutes(5);
room.Playlist.Add(new PlaylistItem
{
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
Beatmap = { Value = importedBeatmap.Value.Beatmaps.First() },
Ruleset = { Value = new OsuRuleset().RulesetInfo }
});
});
AddUntilStep("Progress details are hidden", () => match.ChildrenOfType<RoomLocalUserInfo>().FirstOrDefault()?.Parent.Alpha == 0);
AddStep("start match", () => match.ChildrenOfType<PlaylistsReadyButton>().First().TriggerClick());
AddUntilStep("player loader loaded", () => Stack.CurrentScreen is PlayerLoader);
}
[Test]
public void TestPlaylistItemSelectedOnCreate()
public void TestAttemptLimitedMatch()
{
AddStep("set room properties", () =>
setupAndCreateRoom(room =>
{
SelectedRoom.Value.Name.Value = "my awesome room";
SelectedRoom.Value.Host.Value = API.LocalUser.Value;
SelectedRoom.Value.Playlist.Add(new PlaylistItem
room.Name.Value = "my awesome room";
room.MaxAttempts.Value = 5;
room.Host.Value = API.LocalUser.Value;
room.RecentParticipants.Add(room.Host.Value);
room.EndDate.Value = DateTimeOffset.Now.AddMinutes(5);
room.Playlist.Add(new PlaylistItem
{
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
Beatmap = { Value = importedBeatmap.Value.Beatmaps.First() },
Ruleset = { Value = new OsuRuleset().RulesetInfo }
});
});
AddStep("move mouse to create button", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<PlaylistsRoomSettingsOverlay.CreateRoomButton>().Single());
});
AddUntilStep("Progress details are visible", () => match.ChildrenOfType<RoomLocalUserInfo>().FirstOrDefault()?.Parent.Alpha == 1);
}
AddStep("click", () => InputManager.Click(MouseButton.Left));
[Test]
public void TestPlaylistItemSelectedOnCreate()
{
setupAndCreateRoom(room =>
{
room.Name.Value = "my awesome room";
room.Host.Value = API.LocalUser.Value;
room.Playlist.Add(new PlaylistItem
{
Beatmap = { Value = importedBeatmap.Value.Beatmaps.First() },
Ruleset = { Value = new OsuRuleset().RulesetInfo }
});
});
AddAssert("first playlist item selected", () => match.SelectedItem.Value == SelectedRoom.Value.Playlist[0]);
}
@ -94,56 +113,51 @@ namespace osu.Game.Tests.Visual.Playlists
public void TestBeatmapUpdatedOnReImport()
{
BeatmapSetInfo importedSet = null;
TestBeatmap beatmap = null;
// this step is required to make sure the further imports actually get online IDs.
// all the playlist logic relies on online ID matching.
AddStep("remove all matching online IDs", () =>
{
beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo);
var existing = manager.QueryBeatmapSets(s => s.OnlineBeatmapSetID == beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID).ToList();
foreach (var s in existing)
{
s.OnlineBeatmapSetID = null;
foreach (var b in s.Beatmaps)
b.OnlineBeatmapID = null;
manager.Update(s);
}
});
AddStep("import altered beatmap", () =>
{
IBeatmap beatmap = CreateBeatmap(new OsuRuleset().RulesetInfo);
beatmap.BeatmapInfo.BaseDifficulty.CircleSize = 1;
// intentionally increment online IDs to clash with import below.
beatmap.BeatmapInfo.OnlineBeatmapID++;
beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID++;
importedSet = manager.Import(beatmap.BeatmapInfo.BeatmapSet).Result.Value;
});
AddStep("load room", () =>
setupAndCreateRoom(room =>
{
SelectedRoom.Value.Name.Value = "my awesome room";
SelectedRoom.Value.Host.Value = API.LocalUser.Value;
SelectedRoom.Value.Playlist.Add(new PlaylistItem
room.Name.Value = "my awesome room";
room.Host.Value = API.LocalUser.Value;
room.Playlist.Add(new PlaylistItem
{
Beatmap = { Value = importedSet.Beatmaps[0] },
Ruleset = { Value = new OsuRuleset().RulesetInfo }
});
});
AddStep("create room", () =>
{
InputManager.MoveMouseTo(match.ChildrenOfType<PlaylistsRoomSettingsOverlay.CreateRoomButton>().Single());
InputManager.Click(MouseButton.Left);
});
AddAssert("match has altered beatmap", () => match.Beatmap.Value.Beatmap.Difficulty.CircleSize == 1);
AddStep("re-import original beatmap", () => manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait());
importBeatmap();
AddAssert("match has original beatmap", () => match.Beatmap.Value.Beatmap.Difficulty.CircleSize != 1);
}
private void setupAndCreateRoom(Action<Room> room)
{
AddStep("setup room", () => room(SelectedRoom.Value));
AddStep("click create button", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<PlaylistsRoomSettingsOverlay.CreateRoomButton>().Single());
InputManager.Click(MouseButton.Left);
});
}
private void importBeatmap() => AddStep("import beatmap", () => importedBeatmap = manager.Import(CreateBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Result);
private class TestPlaylistsRoomSubScreen : PlaylistsRoomSubScreen
{
public new Bindable<PlaylistItem> SelectedItem => base.SelectedItem;

View File

@ -6,6 +6,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Configuration;
using osu.Game.Overlays.Settings;
using osuTK;
namespace osu.Game.Tests.Visual.Settings
@ -58,6 +59,13 @@ namespace osu.Game.Tests.Visual.Settings
Default = string.Empty,
Value = "Sample text"
};
[SettingSource("Sample number textbox", "Textbox number entry", SettingControlType = typeof(SettingsNumberBox))]
public Bindable<int?> IntTextboxBindable { get; } = new Bindable<int?>
{
Default = null,
Value = null
};
}
private enum TestEnum

View File

@ -0,0 +1,83 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Screens;
using osu.Game.Online.API;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Tests.Visual.Multiplayer;
using osu.Game.Tests.Visual.OnlinePlay;
namespace osu.Game.Tests.Visual
{
/// <summary>
/// An <see cref="OsuScreen"/> loadable into <see cref="ScreenTestScene"/>s via <see cref="ScreenTestScene.LoadScreen"/>,
/// which provides dependencies for and loads an isolated <see cref="Screens.OnlinePlay.Multiplayer.Multiplayer"/> screen.
/// <p>
/// This screen:
/// <list type="bullet">
/// <item>Provides a <see cref="TestMultiplayerClient"/> to be resolved as a dependency in the <see cref="Screens.OnlinePlay.Multiplayer.Multiplayer"/> screen,
/// which is typically a part of <see cref="OsuGameBase"/>.</item>
/// <item>Rebinds the <see cref="DummyAPIAccess"/> to handle requests via a <see cref="TestRoomRequestsHandler"/>.</item>
/// <item>Provides a <see cref="TestMultiplayerRoomManager"/> for the <see cref="Screens.OnlinePlay.Multiplayer.Multiplayer"/> screen.</item>
/// </list>
/// </p>
/// </summary>
public class TestMultiplayerScreenStack : OsuScreen
{
public Screens.OnlinePlay.Multiplayer.Multiplayer MultiplayerScreen => multiplayerScreen;
public TestMultiplayerRoomManager RoomManager => multiplayerScreen.RoomManager;
public IScreen CurrentScreen => screenStack.CurrentScreen;
public new bool IsLoaded => base.IsLoaded && MultiplayerScreen.IsLoaded;
[Cached(typeof(MultiplayerClient))]
public readonly TestMultiplayerClient Client;
private readonly OsuScreenStack screenStack;
private readonly TestMultiplayer multiplayerScreen;
public TestMultiplayerScreenStack()
{
multiplayerScreen = new TestMultiplayer();
InternalChildren = new Drawable[]
{
Client = new TestMultiplayerClient(RoomManager),
screenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }
};
screenStack.Push(multiplayerScreen);
}
[BackgroundDependencyLoader]
private void load(IAPIProvider api, OsuGameBase game)
{
((DummyAPIAccess)api).HandleRequest = request => multiplayerScreen.RequestsHandler.HandleRequest(request, api.LocalUser.Value, game);
}
public override bool OnBackButton() => multiplayerScreen.OnBackButton();
public override bool OnExiting(IScreen next)
{
if (screenStack.CurrentScreen == null)
return base.OnExiting(next);
screenStack.Exit();
return true;
}
private class TestMultiplayer : Screens.OnlinePlay.Multiplayer.Multiplayer
{
public new TestMultiplayerRoomManager RoomManager { get; private set; }
public TestRoomRequestsHandler RequestsHandler { get; private set; }
protected override RoomManager CreateRoomManager() => RoomManager = new TestMultiplayerRoomManager(RequestsHandler = new TestRoomRequestsHandler());
}
}
}

View File

@ -41,6 +41,44 @@ namespace osu.Game.Tests.Visual.UserInterface
notificationOverlay.UnreadCount.ValueChanged += count => { displayedCount.Text = $"displayed count: {count.NewValue}"; };
});
[Test]
public void TestCompleteProgress()
{
ProgressNotification notification = null;
AddStep("add progress notification", () =>
{
notification = new ProgressNotification
{
Text = @"Uploading to BSS...",
CompletionText = "Uploaded to BSS!",
};
notificationOverlay.Post(notification);
progressingNotifications.Add(notification);
});
AddUntilStep("wait completion", () => notification.State == ProgressNotificationState.Completed);
}
[Test]
public void TestCancelProgress()
{
ProgressNotification notification = null;
AddStep("add progress notification", () =>
{
notification = new ProgressNotification
{
Text = @"Uploading to BSS...",
CompletionText = "Uploaded to BSS!",
};
notificationOverlay.Post(notification);
progressingNotifications.Add(notification);
});
AddWaitStep("wait 3", 3);
AddStep("cancel notification", () => notification.State = ProgressNotificationState.Cancelled);
}
[Test]
public void TestBasicFlow()
{
@ -138,7 +176,7 @@ namespace osu.Game.Tests.Visual.UserInterface
foreach (var n in progressingNotifications.FindAll(n => n.State == ProgressNotificationState.Active))
{
if (n.Progress < 1)
n.Progress += (float)(Time.Elapsed / 400) * RNG.NextSingle();
n.Progress += (float)(Time.Elapsed / 2000);
else
n.State = ProgressNotificationState.Completed;
}

View File

@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{
AddStep("setup cover", () => Child = new UpdateableOnlineBeatmapSetCover(coverType)
{
BeatmapSet = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet,
OnlineInfo = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet.OnlineInfo,
RelativeSizeAxes = Axes.Both,
Masking = true,
});
@ -68,7 +68,7 @@ namespace osu.Game.Tests.Visual.UserInterface
var cover = new UpdateableOnlineBeatmapSetCover(coverType)
{
BeatmapSet = setInfo,
OnlineInfo = setInfo.OnlineInfo,
Height = 100,
Masking = true,
};
@ -99,12 +99,12 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("setup cover", () => Child = updateableCover = new TestUpdateableOnlineBeatmapSetCover
{
BeatmapSet = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet,
OnlineInfo = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet.OnlineInfo,
RelativeSizeAxes = Axes.Both,
Masking = true,
});
AddStep("change model", () => updateableCover.BeatmapSet = null);
AddStep("change model", () => updateableCover.OnlineInfo = null);
AddWaitStep("wait some", 5);
AddAssert("no cover added", () => !updateableCover.ChildrenOfType<DelayedLoadUnloadWrapper>().Any());
}
@ -117,7 +117,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("setup cover", () => Child = updateableCover = new TestUpdateableOnlineBeatmapSetCover(0)
{
BeatmapSet = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg"),
OnlineInfo = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg").OnlineInfo,
RelativeSizeAxes = Axes.Both,
Masking = true,
Alpha = 0.4f
@ -128,7 +128,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddUntilStep("wait for fade complete", () => initialCover.Alpha == 1);
AddStep("switch beatmap",
() => updateableCover.BeatmapSet = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1079428/covers/cover.jpg"));
() => updateableCover.OnlineInfo = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1079428/covers/cover.jpg").OnlineInfo);
AddUntilStep("new cover loaded", () => updateableCover.ChildrenOfType<OnlineBeatmapSetCover>().Except(new[] { initialCover }).Any());
}

View File

@ -3,7 +3,6 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
@ -23,14 +22,13 @@ namespace osu.Game.Tournament.Tests.Components
[BackgroundDependencyLoader]
private void load()
{
var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = 1091460 });
var req = new GetBeatmapRequest(new APIBeatmap { OnlineID = 1091460 });
req.Success += success;
api.Queue(req);
}
private void success(APIBeatmap apiBeatmap)
private void success(APIBeatmap beatmap)
{
var beatmap = apiBeatmap.ToBeatmapInfo(rulesets);
Add(new TournamentBeatmapPanel(beatmap)
{
Anchor = Anchor.Centre,

View File

@ -4,12 +4,12 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
using osu.Game.Tournament.Components;
using osuTK;
namespace osu.Game.Tournament.Tests.Components
{
@ -23,12 +23,10 @@ namespace osu.Game.Tournament.Tests.Components
private FillFlowContainer<TournamentBeatmapPanel> fillFlow;
private BeatmapInfo beatmapInfo;
[BackgroundDependencyLoader]
private void load()
{
var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = 490154 });
var req = new GetBeatmapRequest(new APIBeatmap { OnlineID = 490154 });
req.Success += success;
api.Queue(req);
@ -38,18 +36,17 @@ namespace osu.Game.Tournament.Tests.Components
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Direction = FillDirection.Full,
Spacing = new osuTK.Vector2(10)
Spacing = new Vector2(10)
});
}
private void success(APIBeatmap apiBeatmap)
private void success(APIBeatmap beatmap)
{
beatmapInfo = apiBeatmap.ToBeatmapInfo(rulesets);
var mods = rulesets.GetRuleset(Ladder.Ruleset.Value.ID ?? 0).CreateInstance().AllMods;
foreach (var mod in mods)
{
fillFlow.Add(new TournamentBeatmapPanel(beatmapInfo, mod.Acronym)
fillFlow.Add(new TournamentBeatmapPanel(beatmap, mod.Acronym)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre

View File

@ -44,8 +44,8 @@ namespace osu.Game.Tournament.Tests.NonVisual
{
Beatmaps =
{
new RoundBeatmap { BeatmapInfo = TournamentTestScene.CreateSampleBeatmapInfo() },
new RoundBeatmap { BeatmapInfo = TournamentTestScene.CreateSampleBeatmapInfo() },
new RoundBeatmap { Beatmap = TournamentTestScene.CreateSampleBeatmap() },
new RoundBeatmap { Beatmap = TournamentTestScene.CreateSampleBeatmap() },
}
}
},

View File

@ -132,7 +132,7 @@ namespace osu.Game.Tournament.Tests.Screens
{
Ladder.CurrentMatch.Value.Round.Value.Beatmaps.Add(new RoundBeatmap
{
BeatmapInfo = CreateSampleBeatmapInfo(),
Beatmap = CreateSampleBeatmap(),
Mods = mods
});
}

View File

@ -7,7 +7,6 @@ using osu.Framework.Allocation;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
using osu.Game.Tests.Visual;
@ -74,19 +73,19 @@ namespace osu.Game.Tournament.Tests
{
new SeedingBeatmap
{
BeatmapInfo = CreateSampleBeatmapInfo(),
Beatmap = CreateSampleBeatmap(),
Score = 12345672,
Seed = { Value = 24 },
},
new SeedingBeatmap
{
BeatmapInfo = CreateSampleBeatmapInfo(),
Beatmap = CreateSampleBeatmap(),
Score = 1234567,
Seed = { Value = 12 },
},
new SeedingBeatmap
{
BeatmapInfo = CreateSampleBeatmapInfo(),
Beatmap = CreateSampleBeatmap(),
Score = 1234567,
Seed = { Value = 16 },
}
@ -100,19 +99,19 @@ namespace osu.Game.Tournament.Tests
{
new SeedingBeatmap
{
BeatmapInfo = CreateSampleBeatmapInfo(),
Beatmap = CreateSampleBeatmap(),
Score = 234567,
Seed = { Value = 3 },
},
new SeedingBeatmap
{
BeatmapInfo = CreateSampleBeatmapInfo(),
Beatmap = CreateSampleBeatmap(),
Score = 234567,
Seed = { Value = 6 },
},
new SeedingBeatmap
{
BeatmapInfo = CreateSampleBeatmapInfo(),
Beatmap = CreateSampleBeatmap(),
Score = 234567,
Seed = { Value = 12 },
}
@ -152,16 +151,15 @@ namespace osu.Game.Tournament.Tests
}
};
public static BeatmapInfo CreateSampleBeatmapInfo() =>
new BeatmapInfo
public static APIBeatmap CreateSampleBeatmap() =>
new APIBeatmap
{
Metadata = new BeatmapMetadata
BeatmapSet = new APIBeatmapSet
{
Title = "Test Title",
Artist = "Test Artist",
ID = RNG.Next(0, 1000000)
},
OnlineInfo = new APIBeatmap(),
OnlineID = RNG.Next(0, 1000000),
};
protected override ITestSceneTestRunner CreateRunner() => new TournamentTestSceneTestRunner();

View File

@ -12,6 +12,7 @@ using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Extensions;
using osu.Game.Graphics;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
using osu.Game.Screens.Menu;
using osuTK;
@ -21,22 +22,21 @@ namespace osu.Game.Tournament.Components
{
public class SongBar : CompositeDrawable
{
private BeatmapInfo beatmapInfo;
private APIBeatmap beatmap;
public const float HEIGHT = 145 / 2f;
[Resolved]
private IBindable<RulesetInfo> ruleset { get; set; }
public BeatmapInfo BeatmapInfo
public APIBeatmap Beatmap
{
get => beatmapInfo;
set
{
if (beatmapInfo == value)
if (beatmap == value)
return;
beatmapInfo = value;
beatmap = value;
update();
}
}
@ -95,18 +95,18 @@ namespace osu.Game.Tournament.Components
private void update()
{
if (beatmapInfo == null)
if (beatmap == null)
{
flow.Clear();
return;
}
double bpm = beatmapInfo.BeatmapSet.OnlineInfo.BPM;
double length = beatmapInfo.Length;
double bpm = beatmap.BPM;
double length = beatmap.Length;
string hardRockExtra = "";
string srExtra = "";
float ar = beatmapInfo.BaseDifficulty.ApproachRate;
float ar = beatmap.Difficulty.ApproachRate;
if ((mods & LegacyMods.HardRock) > 0)
{
@ -132,9 +132,9 @@ namespace osu.Game.Tournament.Components
default:
stats = new (string heading, string content)[]
{
("CS", $"{beatmapInfo.BaseDifficulty.CircleSize:0.#}{hardRockExtra}"),
("CS", $"{beatmap.Difficulty.CircleSize:0.#}{hardRockExtra}"),
("AR", $"{ar:0.#}{hardRockExtra}"),
("OD", $"{beatmapInfo.BaseDifficulty.OverallDifficulty:0.#}{hardRockExtra}"),
("OD", $"{beatmap.Difficulty.OverallDifficulty:0.#}{hardRockExtra}"),
};
break;
@ -142,15 +142,15 @@ namespace osu.Game.Tournament.Components
case 3:
stats = new (string heading, string content)[]
{
("OD", $"{beatmapInfo.BaseDifficulty.OverallDifficulty:0.#}{hardRockExtra}"),
("HP", $"{beatmapInfo.BaseDifficulty.DrainRate:0.#}{hardRockExtra}")
("OD", $"{beatmap.Difficulty.OverallDifficulty:0.#}{hardRockExtra}"),
("HP", $"{beatmap.Difficulty.DrainRate:0.#}{hardRockExtra}")
};
break;
case 2:
stats = new (string heading, string content)[]
{
("CS", $"{beatmapInfo.BaseDifficulty.CircleSize:0.#}{hardRockExtra}"),
("CS", $"{beatmap.Difficulty.CircleSize:0.#}{hardRockExtra}"),
("AR", $"{ar:0.#}"),
};
break;
@ -186,7 +186,7 @@ namespace osu.Game.Tournament.Components
Children = new Drawable[]
{
new DiffPiece(stats),
new DiffPiece(("Star Rating", $"{beatmapInfo.StarDifficulty:0.#}{srExtra}"))
new DiffPiece(("Star Rating", $"{beatmap.StarRating:0.#}{srExtra}"))
}
},
new FillFlowContainer
@ -229,7 +229,7 @@ namespace osu.Game.Tournament.Components
}
}
},
new TournamentBeatmapPanel(beatmapInfo)
new TournamentBeatmapPanel(beatmap)
{
RelativeSizeAxes = Axes.X,
Width = 0.5f,

View File

@ -13,6 +13,7 @@ using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Tournament.Models;
using osuTK.Graphics;
@ -20,7 +21,7 @@ namespace osu.Game.Tournament.Components
{
public class TournamentBeatmapPanel : CompositeDrawable
{
public readonly IBeatmapInfo BeatmapInfo;
public readonly APIBeatmap Beatmap;
private readonly string mod;
@ -32,11 +33,11 @@ namespace osu.Game.Tournament.Components
private readonly Bindable<TournamentMatch> currentMatch = new Bindable<TournamentMatch>();
private Box flash;
public TournamentBeatmapPanel(IBeatmapInfo beatmapInfo, string mod = null)
public TournamentBeatmapPanel(APIBeatmap beatmap, string mod = null)
{
if (beatmapInfo == null) throw new ArgumentNullException(nameof(beatmapInfo));
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
BeatmapInfo = beatmapInfo;
Beatmap = beatmap;
this.mod = mod;
Width = 400;
@ -62,7 +63,7 @@ namespace osu.Game.Tournament.Components
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(0.5f),
BeatmapSet = BeatmapInfo.BeatmapSet as IBeatmapSetOnlineInfo,
OnlineInfo = Beatmap.BeatmapSet,
},
new FillFlowContainer
{
@ -75,7 +76,7 @@ namespace osu.Game.Tournament.Components
{
new TournamentSpriteText
{
Text = BeatmapInfo.GetDisplayTitleRomanisable(false),
Text = Beatmap.GetDisplayTitleRomanisable(false),
Font = OsuFont.Torus.With(weight: FontWeight.Bold),
},
new FillFlowContainer
@ -92,7 +93,7 @@ namespace osu.Game.Tournament.Components
},
new TournamentSpriteText
{
Text = BeatmapInfo.Metadata?.Author,
Text = Beatmap.Metadata.Author,
Padding = new MarginPadding { Right = 20 },
Font = OsuFont.Torus.With(weight: FontWeight.Bold, size: 14)
},
@ -104,7 +105,7 @@ namespace osu.Game.Tournament.Components
},
new TournamentSpriteText
{
Text = BeatmapInfo.DifficultyName,
Text = Beatmap.DifficultyName,
Font = OsuFont.Torus.With(weight: FontWeight.Bold, size: 14)
},
}
@ -148,7 +149,7 @@ namespace osu.Game.Tournament.Components
private void updateState()
{
var found = currentMatch.Value.PicksBans.FirstOrDefault(p => p.BeatmapID == BeatmapInfo.OnlineID);
var found = currentMatch.Value.PicksBans.FirstOrDefault(p => p.BeatmapID == Beatmap.OnlineID);
bool doFlash = found != choice;
choice = found;

View File

@ -11,10 +11,10 @@ using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Threading;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
using osu.Game.Tournament.Models;
@ -87,14 +87,14 @@ namespace osu.Game.Tournament.IPC
lastBeatmapId = beatmapId;
var existing = ladder.CurrentMatch.Value?.Round.Value?.Beatmaps.FirstOrDefault(b => b.ID == beatmapId && b.BeatmapInfo != null);
var existing = ladder.CurrentMatch.Value?.Round.Value?.Beatmaps.FirstOrDefault(b => b.ID == beatmapId && b.Beatmap != null);
if (existing != null)
Beatmap.Value = existing.BeatmapInfo;
Beatmap.Value = existing.Beatmap;
else
{
beatmapLookupRequest = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = beatmapId });
beatmapLookupRequest.Success += b => Beatmap.Value = b.ToBeatmapInfo(Rulesets);
beatmapLookupRequest = new GetBeatmapRequest(new APIBeatmap { OnlineID = beatmapId });
beatmapLookupRequest.Success += b => Beatmap.Value = b;
API.Queue(beatmapLookupRequest);
}
}

View File

@ -3,14 +3,14 @@
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Tournament.IPC
{
public class MatchIPCInfo : Component
{
public Bindable<BeatmapInfo> Beatmap { get; } = new Bindable<BeatmapInfo>();
public Bindable<APIBeatmap> Beatmap { get; } = new Bindable<APIBeatmap>();
public Bindable<LegacyMods> Mods { get; } = new Bindable<LegacyMods>();
public Bindable<TourneyState> State { get; } = new Bindable<TourneyState>();
public Bindable<string> ChatChannel { get; } = new Bindable<string>();

View File

@ -1,7 +1,8 @@
// 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 osu.Game.Beatmaps;
using Newtonsoft.Json;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Tournament.Models
{
@ -10,6 +11,7 @@ namespace osu.Game.Tournament.Models
public int ID;
public string Mods;
public BeatmapInfo BeatmapInfo;
[JsonProperty("BeatmapInfo")]
public APIBeatmap Beatmap;
}
}

View File

@ -1,8 +1,9 @@
// 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 Newtonsoft.Json;
using osu.Framework.Bindables;
using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Tournament.Models
{
@ -10,7 +11,8 @@ namespace osu.Game.Tournament.Models
{
public int ID;
public BeatmapInfo BeatmapInfo;
[JsonProperty("BeatmapInfo")]
public APIBeatmap Beatmap;
public long Score;

View File

@ -4,8 +4,8 @@
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.IPC;
@ -37,10 +37,10 @@ namespace osu.Game.Tournament.Screens
SongBar.Mods = mods.NewValue;
}
private void beatmapChanged(ValueChangedEvent<BeatmapInfo> beatmap)
private void beatmapChanged(ValueChangedEvent<APIBeatmap> beatmap)
{
SongBar.FadeInFromZero(300, Easing.OutQuint);
SongBar.BeatmapInfo = beatmap.NewValue;
SongBar.Beatmap = beatmap.NewValue;
}
}
}

View File

@ -7,10 +7,10 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets;
using osu.Game.Tournament.Components;
@ -226,25 +226,25 @@ namespace osu.Game.Tournament.Screens.Editors
Model.ID = id.NewValue ?? 0;
if (id.NewValue != id.OldValue)
Model.BeatmapInfo = null;
Model.Beatmap = null;
if (Model.BeatmapInfo != null)
if (Model.Beatmap != null)
{
updatePanel();
return;
}
var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = Model.ID });
var req = new GetBeatmapRequest(new APIBeatmap { OnlineID = Model.ID });
req.Success += res =>
{
Model.BeatmapInfo = res.ToBeatmapInfo(rulesets);
Model.Beatmap = res;
updatePanel();
};
req.Failure += _ =>
{
Model.BeatmapInfo = null;
Model.Beatmap = null;
updatePanel();
};
@ -259,9 +259,9 @@ namespace osu.Game.Tournament.Screens.Editors
{
drawableContainer.Clear();
if (Model.BeatmapInfo != null)
if (Model.Beatmap != null)
{
drawableContainer.Child = new TournamentBeatmapPanel(Model.BeatmapInfo, Model.Mods)
drawableContainer.Child = new TournamentBeatmapPanel(Model.Beatmap, Model.Mods)
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,

View File

@ -7,10 +7,10 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets;
using osu.Game.Tournament.Components;
@ -234,25 +234,25 @@ namespace osu.Game.Tournament.Screens.Editors
Model.ID = id.NewValue ?? 0;
if (id.NewValue != id.OldValue)
Model.BeatmapInfo = null;
Model.Beatmap = null;
if (Model.BeatmapInfo != null)
if (Model.Beatmap != null)
{
updatePanel();
return;
}
var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = Model.ID });
var req = new GetBeatmapRequest(new APIBeatmap { OnlineID = Model.ID });
req.Success += res =>
{
Model.BeatmapInfo = res.ToBeatmapInfo(rulesets);
Model.Beatmap = res;
updatePanel();
};
req.Failure += _ =>
{
Model.BeatmapInfo = null;
Model.Beatmap = null;
updatePanel();
};
@ -267,9 +267,9 @@ namespace osu.Game.Tournament.Screens.Editors
{
drawableContainer.Clear();
if (Model.BeatmapInfo != null)
if (Model.Beatmap != null)
{
drawableContainer.Child = new TournamentBeatmapPanel(Model.BeatmapInfo, result.Mod.Value)
drawableContainer.Child = new TournamentBeatmapPanel(Model.Beatmap, result.Mod.Value)
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,

View File

@ -8,8 +8,8 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Framework.Threading;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.IPC;
using osu.Game.Tournament.Models;
@ -105,14 +105,14 @@ namespace osu.Game.Tournament.Screens.MapPool
ipc.Beatmap.BindValueChanged(beatmapChanged);
}
private void beatmapChanged(ValueChangedEvent<BeatmapInfo> beatmap)
private void beatmapChanged(ValueChangedEvent<APIBeatmap> beatmap)
{
if (CurrentMatch.Value == null || CurrentMatch.Value.PicksBans.Count(p => p.Type == ChoiceType.Ban) < 2)
return;
// if bans have already been placed, beatmap changes result in a selection being made autoamtically
if (beatmap.NewValue.OnlineBeatmapID != null)
addForBeatmap(beatmap.NewValue.OnlineBeatmapID.Value);
if (beatmap.NewValue.OnlineID > 0)
addForBeatmap(beatmap.NewValue.OnlineID);
}
private void setMode(TeamColour colour, ChoiceType choiceType)
@ -147,11 +147,11 @@ namespace osu.Game.Tournament.Screens.MapPool
if (map != null)
{
if (e.Button == MouseButton.Left && map.BeatmapInfo.OnlineID > 0)
addForBeatmap(map.BeatmapInfo.OnlineID);
if (e.Button == MouseButton.Left && map.Beatmap.OnlineID > 0)
addForBeatmap(map.Beatmap.OnlineID);
else
{
var existing = CurrentMatch.Value.PicksBans.FirstOrDefault(p => p.BeatmapID == map.BeatmapInfo.OnlineID);
var existing = CurrentMatch.Value.PicksBans.FirstOrDefault(p => p.BeatmapID == map.Beatmap.OnlineID);
if (existing != null)
{
@ -179,7 +179,7 @@ namespace osu.Game.Tournament.Screens.MapPool
if (CurrentMatch.Value == null)
return;
if (CurrentMatch.Value.Round.Value.Beatmaps.All(b => b.BeatmapInfo.OnlineBeatmapID != beatmapId))
if (CurrentMatch.Value.Round.Value.Beatmaps.All(b => b.Beatmap.OnlineID != beatmapId))
// don't attempt to add if the beatmap isn't in our pool
return;
@ -245,7 +245,7 @@ namespace osu.Game.Tournament.Screens.MapPool
flowCount = 1;
}
currentFlow.Add(new TournamentBeatmapPanel(b.BeatmapInfo, b.Mods)
currentFlow.Add(new TournamentBeatmapPanel(b.Beatmap, b.Mods)
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,

View File

@ -141,9 +141,9 @@ namespace osu.Game.Tournament.Screens.TeamIntro
Spacing = new Vector2(5),
Children = new Drawable[]
{
new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Title, Colour = TournamentGame.TEXT_COLOUR, },
new TournamentSpriteText { Text = beatmap.Beatmap.Metadata.Title, Colour = TournamentGame.TEXT_COLOUR, },
new TournamentSpriteText { Text = "by", Colour = TournamentGame.TEXT_COLOUR, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Artist, Colour = TournamentGame.TEXT_COLOUR, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
new TournamentSpriteText { Text = beatmap.Beatmap.Metadata.Artist, Colour = TournamentGame.TEXT_COLOUR, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
}
},
new FillFlowContainer

View File

@ -7,12 +7,14 @@ using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Tournament.IO;
using osu.Game.Tournament.IPC;
using osu.Game.Tournament.Models;
@ -39,9 +41,18 @@ namespace osu.Game.Tournament
return dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
}
private TournamentSpriteText initialisationText;
[BackgroundDependencyLoader]
private void load(Storage baseStorage)
{
AddInternal(initialisationText = new TournamentSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.Torus.With(size: 32),
});
Resources.AddStore(new DllResourceStore(typeof(TournamentGameBase).Assembly));
dependencies.CacheAs<Storage>(storage = new TournamentStorage(baseStorage));
@ -123,7 +134,8 @@ namespace osu.Game.Tournament
}
addedInfo |= addPlayers();
addedInfo |= addBeatmaps();
addedInfo |= addRoundBeatmaps();
addedInfo |= addSeedingBeatmaps();
if (addedInfo)
SaveChanges();
@ -145,6 +157,8 @@ namespace osu.Game.Tournament
Add(ipc);
taskCompletionSource.SetResult(true);
initialisationText.Expire();
});
}
@ -153,81 +167,108 @@ namespace osu.Game.Tournament
/// </summary>
private bool addPlayers()
{
bool addedInfo = false;
var playersRequiringPopulation = ladder.Teams
.SelectMany(t => t.Players)
.Where(p => string.IsNullOrEmpty(p.Username)
|| p.Statistics?.GlobalRank == null
|| p.Statistics?.CountryRank == null).ToList();
foreach (var t in ladder.Teams)
if (playersRequiringPopulation.Count == 0)
return false;
for (int i = 0; i < playersRequiringPopulation.Count; i++)
{
foreach (var p in t.Players)
{
if (string.IsNullOrEmpty(p.Username)
|| p.Statistics?.GlobalRank == null
|| p.Statistics?.CountryRank == null)
{
PopulateUser(p, immediate: true);
addedInfo = true;
}
}
var p = playersRequiringPopulation[i];
PopulateUser(p, immediate: true);
updateLoadProgressMessage($"Populating user stats ({i} / {playersRequiringPopulation.Count})");
}
return addedInfo;
return true;
}
/// <summary>
/// Add missing beatmap info based on beatmap IDs
/// </summary>
private bool addBeatmaps()
private bool addRoundBeatmaps()
{
bool addedInfo = false;
var beatmapsRequiringPopulation = ladder.Rounds
.SelectMany(r => r.Beatmaps)
.Where(b => string.IsNullOrEmpty(b.Beatmap?.BeatmapSet?.Title) && b.ID > 0).ToList();
foreach (var r in ladder.Rounds)
if (beatmapsRequiringPopulation.Count == 0)
return false;
for (int i = 0; i < beatmapsRequiringPopulation.Count; i++)
{
foreach (var b in r.Beatmaps.ToList())
{
if (b.BeatmapInfo != null)
continue;
var b = beatmapsRequiringPopulation[i];
if (b.ID > 0)
{
var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = b.ID });
API.Perform(req);
b.BeatmapInfo = req.Response?.ToBeatmapInfo(RulesetStore);
var req = new GetBeatmapRequest(new APIBeatmap { OnlineID = b.ID });
API.Perform(req);
b.Beatmap = req.Response ?? new APIBeatmap();
addedInfo = true;
}
if (b.BeatmapInfo == null)
// if online population couldn't be performed, ensure we don't leave a null value behind
r.Beatmaps.Remove(b);
}
updateLoadProgressMessage($"Populating round beatmaps ({i} / {beatmapsRequiringPopulation.Count})");
}
foreach (var t in ladder.Teams)
{
foreach (var s in t.SeedingResults)
{
foreach (var b in s.Beatmaps)
{
if (b.BeatmapInfo == null && b.ID > 0)
{
var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = b.ID });
req.Perform(API);
b.BeatmapInfo = req.Response?.ToBeatmapInfo(RulesetStore);
addedInfo = true;
}
}
}
}
return addedInfo;
return true;
}
/// <summary>
/// Add missing beatmap info based on beatmap IDs
/// </summary>
private bool addSeedingBeatmaps()
{
var beatmapsRequiringPopulation = ladder.Teams
.SelectMany(r => r.SeedingResults)
.SelectMany(r => r.Beatmaps)
.Where(b => string.IsNullOrEmpty(b.Beatmap?.BeatmapSet?.Title) && b.ID > 0).ToList();
if (beatmapsRequiringPopulation.Count == 0)
return false;
for (int i = 0; i < beatmapsRequiringPopulation.Count; i++)
{
var b = beatmapsRequiringPopulation[i];
var req = new GetBeatmapRequest(new APIBeatmap { OnlineID = b.ID });
API.Perform(req);
b.Beatmap = req.Response ?? new APIBeatmap();
updateLoadProgressMessage($"Populating seeding beatmaps ({i} / {beatmapsRequiringPopulation.Count})");
}
return true;
}
private void updateLoadProgressMessage(string s) => Schedule(() => initialisationText.Text = s);
public void PopulateUser(User user, Action success = null, Action failure = null, bool immediate = false)
{
var req = new GetUserRequest(user.Id, Ruleset.Value);
req.Success += res =>
if (immediate)
{
API.Perform(req);
populate();
}
else
{
req.Success += res => { populate(); };
req.Failure += _ =>
{
user.Id = 1;
failure?.Invoke();
};
API.Queue(req);
}
void populate()
{
var res = req.Response;
if (res == null)
return;
user.Id = res.Id;
user.Username = res.Username;
@ -236,18 +277,7 @@ namespace osu.Game.Tournament
user.Cover = res.Cover;
success?.Invoke();
};
req.Failure += _ =>
{
user.Id = 1;
failure?.Invoke();
};
if (immediate)
API.Perform(req);
else
API.Queue(req);
}
}
protected override void LoadComplete()
@ -269,18 +299,19 @@ namespace osu.Game.Tournament
ladder.Matches.Where(p => p.LosersProgression.Value != null).Select(p => new TournamentProgression(p.ID, p.LosersProgression.Value.ID, true)))
.ToList();
// Serialise before opening stream for writing, so if there's a failure it will leave the file in the previous state.
string serialisedLadder = JsonConvert.SerializeObject(ladder,
new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore,
Converters = new JsonConverter[] { new JsonPointConverter() }
});
using (var stream = storage.GetStream(bracket_filename, FileAccess.Write, FileMode.Create))
using (var sw = new StreamWriter(stream))
{
sw.Write(JsonConvert.SerializeObject(ladder,
new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore,
Converters = new JsonConverter[] { new JsonPointConverter() }
}));
}
sw.Write(serialisedLadder);
}
protected override UserInputManager CreateUserInputManager() => new TournamentInputManager();

View File

@ -14,7 +14,7 @@ using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Beatmaps
{
[ExcludeFromDynamicCompile]
public class BeatmapSetInfo : IHasPrimaryKey, IHasFiles<BeatmapSetFileInfo>, ISoftDelete, IEquatable<BeatmapSetInfo>, IBeatmapSetInfo, IBeatmapSetOnlineInfo
public class BeatmapSetInfo : IHasPrimaryKey, IHasFiles<BeatmapSetFileInfo>, ISoftDelete, IEquatable<BeatmapSetInfo>, IBeatmapSetInfo
{
public int ID { get; set; }
@ -35,6 +35,7 @@ namespace osu.Game.Beatmaps
[NotNull]
public List<BeatmapSetFileInfo> Files { get; set; } = new List<BeatmapSetFileInfo>();
// This field is temporary and only used by `APIBeatmapSet.ToBeatmapSet` (soon to be removed) and tests (to be updated to provide APIBeatmapSet instead).
[NotMapped]
public APIBeatmapSet OnlineInfo { get; set; }

View File

@ -12,9 +12,9 @@ namespace osu.Game.Beatmaps.Drawables
/// <summary>
/// Display a beatmap background from a local source, but fallback to online source if not available.
/// </summary>
public class UpdateableBeatmapBackgroundSprite : ModelBackedDrawable<BeatmapInfo>
public class UpdateableBeatmapBackgroundSprite : ModelBackedDrawable<IBeatmapInfo>
{
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
public readonly Bindable<IBeatmapInfo> Beatmap = new Bindable<IBeatmapInfo>();
protected override double LoadDelay => 500;
@ -39,7 +39,7 @@ namespace osu.Game.Beatmaps.Drawables
protected override double TransformDuration => 400;
protected override Drawable CreateDrawable(BeatmapInfo model)
protected override Drawable CreateDrawable(IBeatmapInfo model)
{
var drawable = getDrawableForModel(model);
drawable.RelativeSizeAxes = Axes.Both;
@ -50,15 +50,21 @@ namespace osu.Game.Beatmaps.Drawables
return drawable;
}
private Drawable getDrawableForModel(BeatmapInfo model)
private Drawable getDrawableForModel(IBeatmapInfo model)
{
// prefer online cover where available.
if (model?.BeatmapSet?.OnlineInfo != null)
return new OnlineBeatmapSetCover(model.BeatmapSet, beatmapSetCoverType);
if (model?.BeatmapSet is IBeatmapSetOnlineInfo online)
return new OnlineBeatmapSetCover(online, beatmapSetCoverType);
return model?.ID > 0
? new BeatmapBackgroundSprite(beatmaps.GetWorkingBeatmap(model))
: new BeatmapBackgroundSprite(beatmaps.DefaultBeatmap);
if (model is BeatmapInfo localModel)
{
if (localModel.BeatmapSet?.OnlineInfo != null)
return new OnlineBeatmapSetCover(localModel.BeatmapSet.OnlineInfo, beatmapSetCoverType);
return new BeatmapBackgroundSprite(beatmaps.GetWorkingBeatmap(localModel));
}
return new BeatmapBackgroundSprite(beatmaps.DefaultBeatmap);
}
}
}

View File

@ -13,7 +13,7 @@ namespace osu.Game.Beatmaps.Drawables
{
private readonly BeatmapSetCoverType coverType;
public IBeatmapSetOnlineInfo BeatmapSet
public IBeatmapSetOnlineInfo OnlineInfo
{
get => Model;
set => Model = value;

View File

@ -164,7 +164,7 @@ namespace osu.Game.Online.API.Requests.Responses
IEnumerable<INamedFileUsage> IBeatmapSetInfo.Files => throw new NotImplementedException();
double IBeatmapSetInfo.MaxStarDifficulty => throw new NotImplementedException();
double IBeatmapSetInfo.MaxLength => throw new NotImplementedException();
double IBeatmapSetInfo.MaxBPM => throw new NotImplementedException();
double IBeatmapSetInfo.MaxBPM => BPM;
#endregion
}

View File

@ -59,7 +59,7 @@ namespace osu.Game.Overlays.BeatmapListing
return;
}
beatmapCover.BeatmapSet = value;
beatmapCover.OnlineInfo = value.OnlineInfo;
beatmapCover.FadeTo(0.1f, 200, Easing.OutQuint);
}
}

View File

@ -163,7 +163,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
protected Drawable CreateBackground() => new UpdateableOnlineBeatmapSetCover
{
RelativeSizeAxes = Axes.Both,
BeatmapSet = SetInfo,
OnlineInfo = SetInfo.OnlineInfo,
};
public class Statistic : FillFlowContainer

View File

@ -227,7 +227,7 @@ namespace osu.Game.Overlays.BeatmapSet
BeatmapSet.BindValueChanged(setInfo =>
{
Picker.BeatmapSet = rulesetSelector.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = setInfo.NewValue;
cover.BeatmapSet = setInfo.NewValue;
cover.OnlineInfo = setInfo.NewValue?.OnlineInfo;
if (setInfo.NewValue == null)
{

View File

@ -82,7 +82,7 @@ namespace osu.Game.Overlays.Dashboard.Home
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
BeatmapSet = SetInfo
OnlineInfo = SetInfo.OnlineInfo
}
},
new Container

View File

@ -4,11 +4,15 @@
using System;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osuTK;
using osuTK.Graphics;
@ -16,6 +20,8 @@ namespace osu.Game.Overlays.Notifications
{
public class ProgressNotification : Notification, IHasCompletionTarget
{
private const float loading_spinner_size = 22;
public string Text
{
set => Schedule(() => textDrawable.Text = value);
@ -65,29 +71,53 @@ namespace osu.Game.Overlays.Notifications
private void updateState()
{
const double colour_fade_duration = 200;
switch (state)
{
case ProgressNotificationState.Queued:
Light.Colour = colourQueued;
Light.Pulsate = false;
progressBar.Active = false;
iconBackground.FadeColour(ColourInfo.GradientVertical(colourQueued, colourQueued.Lighten(0.5f)), colour_fade_duration);
loadingSpinner.Show();
break;
case ProgressNotificationState.Active:
Light.Colour = colourActive;
Light.Pulsate = true;
progressBar.Active = true;
iconBackground.FadeColour(ColourInfo.GradientVertical(colourActive, colourActive.Lighten(0.5f)), colour_fade_duration);
loadingSpinner.Show();
break;
case ProgressNotificationState.Cancelled:
cancellationTokenSource.Cancel();
iconBackground.FadeColour(ColourInfo.GradientVertical(Color4.Gray, Color4.Gray.Lighten(0.5f)), colour_fade_duration);
loadingSpinner.Hide();
var icon = new SpriteIcon
{
Icon = FontAwesome.Solid.Ban,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(loading_spinner_size),
};
IconContent.Add(icon);
icon.FadeInFromZero(200, Easing.OutQuint);
Light.Colour = colourCancelled;
Light.Pulsate = false;
progressBar.Active = false;
break;
case ProgressNotificationState.Completed:
loadingSpinner.Hide();
NotificationContent.MoveToY(-DrawSize.Y / 2, 200, Easing.OutQuint);
this.FadeOut(200).Finally(d => Completed());
break;
@ -115,15 +145,13 @@ namespace osu.Game.Overlays.Notifications
private Color4 colourActive;
private Color4 colourCancelled;
private Box iconBackground;
private LoadingSpinner loadingSpinner;
private readonly TextFlowContainer textDrawable;
public ProgressNotification()
{
IconContent.Add(new Box
{
RelativeSizeAxes = Axes.Both,
});
Content.Add(textDrawable = new OsuTextFlowContainer
{
Colour = OsuColour.Gray(128),
@ -138,6 +166,9 @@ namespace osu.Game.Overlays.Notifications
RelativeSizeAxes = Axes.X,
});
// make some extra space for the progress bar.
IconContent.Margin = new MarginPadding { Bottom = 5 };
State = ProgressNotificationState.Queued;
// don't close on click by default.
@ -150,6 +181,19 @@ namespace osu.Game.Overlays.Notifications
colourQueued = colours.YellowDark;
colourActive = colours.Blue;
colourCancelled = colours.Red;
IconContent.AddRange(new Drawable[]
{
iconBackground = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.White,
},
loadingSpinner = new LoadingSpinner
{
Size = new Vector2(loading_spinner_size),
}
});
}
public override void Close()

View File

@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
{
RelativeSizeAxes = Axes.Y,
Width = cover_width,
BeatmapSet = mostPlayed.BeatmapSet,
OnlineInfo = mostPlayed.BeatmapSet,
},
new Container
{

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
}
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
List<IList<HitSampleInfo>> nodeSamples)
IList<IList<HitSampleInfo>> nodeSamples)
{
newCombo |= forceNewCombo;
comboOffset += extraComboOffset;

View File

@ -408,7 +408,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
/// <param name="nodeSamples">The samples to be played when the slider nodes are hit. This includes the head and tail of the slider.</param>
/// <returns>The hit object.</returns>
protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
List<IList<HitSampleInfo>> nodeSamples);
IList<IList<HitSampleInfo>> nodeSamples);
/// <summary>
/// Creates a legacy Spinner-type hit object.

View File

@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
public double Distance => Path.Distance;
public List<IList<HitSampleInfo>> NodeSamples { get; set; }
public IList<IList<HitSampleInfo>> NodeSamples { get; set; }
public int RepeatCount { get; set; }
[JsonIgnore]

View File

@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
}
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
List<IList<HitSampleInfo>> nodeSamples)
IList<IList<HitSampleInfo>> nodeSamples)
{
return new ConvertSlider
{

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
}
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
List<IList<HitSampleInfo>> nodeSamples)
IList<IList<HitSampleInfo>> nodeSamples)
{
newCombo |= forceNewCombo;
comboOffset += extraComboOffset;

View File

@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
}
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
List<IList<HitSampleInfo>> nodeSamples)
IList<IList<HitSampleInfo>> nodeSamples)
{
return new ConvertSlider
{

View File

@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Objects.Types
/// n-1: The last repeat.<br />
/// n: The last node.
/// </summary>
List<IList<HitSampleInfo>> NodeSamples { get; }
IList<IList<HitSampleInfo>> NodeSamples { get; }
}
public static class HasRepeatsExtensions

View File

@ -333,13 +333,14 @@ namespace osu.Game.Screens.OnlinePlay
public PanelBackground()
{
UpdateableBeatmapBackgroundSprite backgroundSprite;
InternalChildren = new Drawable[]
{
new UpdateableBeatmapBackgroundSprite
backgroundSprite = new UpdateableBeatmapBackgroundSprite
{
RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fill,
Beatmap = { BindTarget = Beatmap }
},
new FillFlowContainer
{
@ -374,6 +375,10 @@ namespace osu.Game.Screens.OnlinePlay
}
}
};
// manual binding required as playlists don't expose IBeatmapInfo currently.
// may be removed in the future if this changes.
Beatmap.BindValueChanged(beatmap => backgroundSprite.Beatmap.Value = beatmap.NewValue);
}
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using osu.Framework.Extensions;
using osu.Game.Beatmaps;
using osu.Game.IO;
@ -16,6 +17,9 @@ namespace osu.Game.Tests.Beatmaps
{
public class TestBeatmap : Beatmap
{
private static int onlineSetID;
private static int onlineBeatmapID;
public TestBeatmap(RulesetInfo ruleset, bool withHitObjects = true)
{
var baseBeatmap = CreateBeatmap();
@ -31,8 +35,10 @@ namespace osu.Game.Tests.Beatmaps
BeatmapInfo.RulesetID = ruleset.ID ?? 0;
BeatmapInfo.BeatmapSet.Metadata = BeatmapInfo.Metadata;
BeatmapInfo.BeatmapSet.Beatmaps = new List<BeatmapInfo> { BeatmapInfo };
BeatmapInfo.BeatmapSet.OnlineBeatmapSetID = Interlocked.Increment(ref onlineSetID);
BeatmapInfo.Length = 75000;
BeatmapInfo.OnlineInfo = new APIBeatmap();
BeatmapInfo.OnlineBeatmapID = Interlocked.Increment(ref onlineBeatmapID);
BeatmapInfo.BeatmapSet.OnlineInfo = new APIBeatmapSet
{
Status = BeatmapSetOnlineStatus.Ranked,

View File

@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
/// <summary>
/// The cached <see cref="IRoomManager"/>.
/// </summary>
new TestRequestHandlingMultiplayerRoomManager RoomManager { get; }
new TestMultiplayerRoomManager RoomManager { get; }
/// <summary>
/// The cached <see cref="UserLookupCache"/>.

View File

@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
public const int PLAYER_2_ID = 56;
public TestMultiplayerClient Client => OnlinePlayDependencies.Client;
public new TestRequestHandlingMultiplayerRoomManager RoomManager => OnlinePlayDependencies.RoomManager;
public new TestMultiplayerRoomManager RoomManager => OnlinePlayDependencies.RoomManager;
public TestUserLookupCache LookupCache => OnlinePlayDependencies?.LookupCache;
public TestSpectatorClient SpectatorClient => OnlinePlayDependencies?.SpectatorClient;
@ -35,12 +35,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
public new void Setup() => Schedule(() =>
{
if (joinRoom)
{
var room = CreateRoom();
RoomManager.CreateRoom(room);
SelectedRoom.Value = room;
}
SelectedRoom.Value = CreateRoom();
});
protected virtual Room CreateRoom()
@ -64,7 +59,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
base.SetUpSteps();
if (joinRoom)
{
AddStep("join room", () => RoomManager.CreateRoom(SelectedRoom.Value));
AddUntilStep("wait for room join", () => Client.Room != null);
}
}
protected override OnlinePlayTestSceneDependencies CreateOnlinePlayDependencies() => new MultiplayerTestSceneDependencies();

View File

@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
public TestMultiplayerClient Client { get; }
public TestUserLookupCache LookupCache { get; }
public TestSpectatorClient SpectatorClient { get; }
public new TestRequestHandlingMultiplayerRoomManager RoomManager => (TestRequestHandlingMultiplayerRoomManager)base.RoomManager;
public new TestMultiplayerRoomManager RoomManager => (TestMultiplayerRoomManager)base.RoomManager;
public MultiplayerTestSceneDependencies()
{
@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
CacheAs<SpectatorClient>(SpectatorClient);
}
protected override IRoomManager CreateRoomManager() => new TestRequestHandlingMultiplayerRoomManager();
protected override IRoomManager CreateRoomManager() => new TestMultiplayerRoomManager(RequestsHandler);
protected virtual TestSpectatorClient CreateSpectatorClient() => new TestSpectatorClient();
}

View File

@ -39,9 +39,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Resolved]
private BeatmapManager beatmaps { get; set; } = null!;
private readonly TestRequestHandlingMultiplayerRoomManager roomManager;
private readonly TestMultiplayerRoomManager roomManager;
public TestMultiplayerClient(TestRequestHandlingMultiplayerRoomManager roomManager)
public TestMultiplayerClient(TestMultiplayerRoomManager roomManager)
{
this.roomManager = roomManager;
}

View File

@ -2,8 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Multiplayer;
@ -12,25 +10,24 @@ using osu.Game.Tests.Visual.OnlinePlay;
namespace osu.Game.Tests.Visual.Multiplayer
{
/// <summary>
/// A <see cref="RoomManager"/> for use in multiplayer test scenes, backed by a <see cref="TestRoomRequestsHandler"/>.
/// A <see cref="RoomManager"/> for use in multiplayer test scenes.
/// Should generally not be used by itself outside of a <see cref="MultiplayerTestScene"/>.
/// </summary>
public class TestRequestHandlingMultiplayerRoomManager : MultiplayerRoomManager
public class TestMultiplayerRoomManager : MultiplayerRoomManager
{
public IReadOnlyList<Room> ServerSideRooms => handler.ServerSideRooms;
private readonly TestRoomRequestsHandler requestsHandler;
private readonly TestRoomRequestsHandler handler = new TestRoomRequestsHandler();
[BackgroundDependencyLoader]
private void load(IAPIProvider api, OsuGameBase game)
public TestMultiplayerRoomManager(TestRoomRequestsHandler requestsHandler)
{
((DummyAPIAccess)api).HandleRequest = request => handler.HandleRequest(request, api.LocalUser.Value, game);
this.requestsHandler = requestsHandler;
}
public IReadOnlyList<Room> ServerSideRooms => requestsHandler.ServerSideRooms;
/// <summary>
/// Adds a room to a local "server-side" list that's returned when a <see cref="GetRoomsRequest"/> is fired.
/// </summary>
/// <param name="room">The room.</param>
public void AddServerSideRoom(Room room) => handler.AddServerSideRoom(room);
public void AddServerSideRoom(Room room) => requestsHandler.AddServerSideRoom(room);
}
}

View File

@ -7,6 +7,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay;
@ -27,11 +28,14 @@ namespace osu.Game.Tests.Visual.OnlinePlay
/// </summary>
protected OnlinePlayTestSceneDependencies OnlinePlayDependencies => dependencies?.OnlinePlayDependencies;
private DelegatedDependencyContainer dependencies;
protected override Container<Drawable> Content => content;
[Resolved]
private OsuGameBase game { get; set; }
private readonly Container content;
private readonly Container drawableDependenciesContainer;
private DelegatedDependencyContainer dependencies;
protected OnlinePlayTestScene()
{
@ -57,6 +61,17 @@ namespace osu.Game.Tests.Visual.OnlinePlay
drawableDependenciesContainer.AddRange(OnlinePlayDependencies.DrawableComponents);
});
public override void SetUpSteps()
{
base.SetUpSteps();
AddStep("setup API", () =>
{
var handler = OnlinePlayDependencies.RequestsHandler;
((DummyAPIAccess)API).HandleRequest = request => handler.HandleRequest(request, API.LocalUser.Value, game);
});
}
/// <summary>
/// Creates the room dependencies. Called every <see cref="Setup"/>.
/// </summary>

View File

@ -21,6 +21,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay
public IRoomManager RoomManager { get; }
public OngoingOperationTracker OngoingOperationTracker { get; }
public OnlinePlayBeatmapAvailabilityTracker AvailabilityTracker { get; }
public TestRoomRequestsHandler RequestsHandler { get; }
/// <summary>
/// All cached dependencies which are also <see cref="Drawable"/> components.
@ -33,12 +34,14 @@ namespace osu.Game.Tests.Visual.OnlinePlay
public OnlinePlayTestSceneDependencies()
{
SelectedRoom = new Bindable<Room>();
RoomManager = CreateRoomManager();
RequestsHandler = new TestRoomRequestsHandler();
OngoingOperationTracker = new OngoingOperationTracker();
AvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker();
RoomManager = CreateRoomManager();
dependencies = new DependencyContainer(new CachedModelDependencyContainer<Room>(null) { Model = { BindTarget = SelectedRoom } });
CacheAs(RequestsHandler);
CacheAs(SelectedRoom);
CacheAs(RoomManager);
CacheAs(OngoingOperationTracker);
@ -71,6 +74,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay
drawableComponents.Add(drawable);
}
protected virtual IRoomManager CreateRoomManager() => new TestRequestHandlingRoomManager();
protected virtual IRoomManager CreateRoomManager() => new TestRoomManager();
}
}

View File

@ -2,9 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Screens.OnlinePlay.Components;
@ -15,20 +13,12 @@ namespace osu.Game.Tests.Visual.OnlinePlay
/// <summary>
/// A very simple <see cref="RoomManager"/> for use in online play test scenes.
/// </summary>
public class TestRequestHandlingRoomManager : RoomManager
public class TestRoomManager : RoomManager
{
public Action<Room, string> JoinRoomRequested;
private int currentRoomId;
private readonly TestRoomRequestsHandler handler = new TestRoomRequestsHandler();
[BackgroundDependencyLoader]
private void load(IAPIProvider api, OsuGameBase game)
{
((DummyAPIAccess)api).HandleRequest = request => handler.HandleRequest(request, api.LocalUser.Value, game);
}
public override void JoinRoom(Room room, string password = null, Action<Room> onSuccess = null, Action<string> onError = null)
{
JoinRoomRequested?.Invoke(room, password);