From dd6c9173da8b4d44f001cb057efa67c71e2d14a6 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Tue, 14 Apr 2020 18:42:00 +0300 Subject: [PATCH 001/328] Move DifficultyRecommender to OsuGameBase --- osu.Game/OsuGameBase.cs | 5 +++++ osu.Game/Screens/Select/SongSelect.cs | 5 +---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 5487bd9320..4b79e9f24c 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -33,6 +33,7 @@ using osu.Game.Resources; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; +using osu.Game.Screens.Select; using osu.Game.Skinning; using osuTK.Input; @@ -240,6 +241,10 @@ namespace osu.Game dependencies.Cache(previewTrackManager = new PreviewTrackManager()); Add(previewTrackManager); + DifficultyRecommender difficultyRecommender; + dependencies.Cache(difficultyRecommender = new DifficultyRecommender()); + Add(difficultyRecommender); + Ruleset.BindValueChanged(onRulesetChanged); } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index f164056ede..7f35011379 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -81,8 +81,6 @@ namespace osu.Game.Screens.Select protected BeatmapCarousel Carousel { get; private set; } - private DifficultyRecommender recommender; - private BeatmapInfoWedge beatmapInfoWedge; private DialogOverlay dialogOverlay; @@ -104,14 +102,13 @@ namespace osu.Game.Screens.Select private MusicController music { get; set; } [BackgroundDependencyLoader(true)] - private void load(AudioManager audio, DialogOverlay dialog, OsuColour colours, SkinManager skins, ScoreManager scores) + private void load(AudioManager audio, DialogOverlay dialog, OsuColour colours, SkinManager skins, ScoreManager scores, DifficultyRecommender recommender) { // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). transferRulesetValue(); AddRangeInternal(new Drawable[] { - recommender = new DifficultyRecommender(), new ResetScrollContainer(() => Carousel.ScrollToSelected()) { RelativeSizeAxes = Axes.Y, From 00d1cf1ce2b693348633919d649a15388f955072 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Tue, 14 Apr 2020 18:42:18 +0300 Subject: [PATCH 002/328] Recommend from all rulesets --- .../Screens/Select/DifficultyRecommender.cs | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index 20cdca858a..76b1188298 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -44,16 +44,27 @@ namespace osu.Game.Screens.Select /// The recommended difficulty, or null if a recommendation could not be provided. public BeatmapInfo GetRecommendedBeatmap(IEnumerable beatmaps) { - if (recommendedStarDifficulty.TryGetValue(ruleset.Value, out var stars)) + if (!recommendedStarDifficulty.Any()) + return null; + + BeatmapInfo beatmap = null; + + foreach (var r in getBestRulesetOrder()) { - return beatmaps.OrderBy(b => + if (!recommendedStarDifficulty.TryGetValue(ruleset.Value, out var stars)) + break; + + beatmap = beatmaps.Where(b => b.Ruleset.Equals(r)).OrderBy(b => { var difference = b.StarDifficulty - stars; return difference >= 0 ? difference * 2 : difference * -1; // prefer easier over harder }).FirstOrDefault(); + + if (beatmap != null) + break; } - return null; + return beatmap; } private void calculateRecommendedDifficulties() @@ -72,6 +83,26 @@ namespace osu.Game.Screens.Select }); } + private IEnumerable bestRulesetOrder; + + private IEnumerable getBestRulesetOrder() + { + if (bestRulesetOrder != null) + return bestRulesetOrder; + + var otherRulesets = recommendedStarDifficulty.ToList() + .Where(pair => !pair.Key.Equals(ruleset.Value)) + .OrderBy(pair => pair.Value) + .Select(pair => pair.Key) + .Reverse(); + + var rulesetList = new List(new[] { ruleset.Value }); + rulesetList.AddRange(otherRulesets); + + bestRulesetOrder = rulesetList; + return rulesetList; + } + public void APIStateChanged(IAPIProvider api, APIState state) { switch (state) From bbef94b4df15fd3e1b2f0f51f5c16e2243920a45 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Tue, 14 Apr 2020 18:56:20 +0300 Subject: [PATCH 003/328] Reset best order on ruleset change --- osu.Game/Screens/Select/DifficultyRecommender.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index 76b1188298..bdc81ad066 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -32,6 +32,8 @@ namespace osu.Game.Screens.Select private void load() { api.Register(this); + + ruleset.ValueChanged += _ => bestRulesetOrder = null; } /// From 872551733f3b4c9e8fe4c7f21a4d0b8edf4ae3bb Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Tue, 14 Apr 2020 19:39:14 +0300 Subject: [PATCH 004/328] Present recommended beatmaps --- osu.Game/OsuGame.cs | 14 +++++++++----- osu.Game/OsuGameBase.cs | 7 ++++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 5e93d760e3..64fe0f6733 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -322,7 +322,7 @@ namespace osu.Game /// public void PresentBeatmap(BeatmapSetInfo beatmap, Predicate difficultyCriteria = null) { - difficultyCriteria ??= b => b.Ruleset.Equals(Ruleset.Value); + difficultyCriteria ??= _ => true; var databasedSet = beatmap.OnlineBeatmapSetID != null ? BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmap.OnlineBeatmapSetID) @@ -346,11 +346,15 @@ namespace osu.Game return; } - // Find first beatmap that matches our predicate. - var first = databasedSet.Beatmaps.Find(difficultyCriteria) ?? databasedSet.Beatmaps.First(); + // Find beatmaps that match our predicate. + var beatmaps = databasedSet.Beatmaps.Where(b => difficultyCriteria(b)); + if (!beatmaps.Any()) + beatmaps = databasedSet.Beatmaps; - Ruleset.Value = first.Ruleset; - Beatmap.Value = BeatmapManager.GetWorkingBeatmap(first); + var selection = DifficultyRecommender.GetRecommendedBeatmap(beatmaps); + + Ruleset.Value = selection.Ruleset; + Beatmap.Value = BeatmapManager.GetWorkingBeatmap(selection); }, validScreens: new[] { typeof(PlaySongSelect) }); } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 4b79e9f24c..0c86017974 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -100,6 +100,9 @@ namespace osu.Game public bool IsDeployedBuild => AssemblyVersion.Major > 0; + [Cached] + protected readonly DifficultyRecommender DifficultyRecommender = new DifficultyRecommender(); + public virtual string Version { get @@ -241,9 +244,7 @@ namespace osu.Game dependencies.Cache(previewTrackManager = new PreviewTrackManager()); Add(previewTrackManager); - DifficultyRecommender difficultyRecommender; - dependencies.Cache(difficultyRecommender = new DifficultyRecommender()); - Add(difficultyRecommender); + Add(DifficultyRecommender); Ruleset.BindValueChanged(onRulesetChanged); } From 80949e89b934f0eaee7705da8e8f62f0dc47b6b3 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Tue, 14 Apr 2020 19:49:42 +0300 Subject: [PATCH 005/328] Offline fallback and commenting --- osu.Game/OsuGame.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 64fe0f6733..e64ca3ad87 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -316,8 +316,8 @@ namespace osu.Game /// /// The beatmap to select. /// - /// Optional predicate used to try and find a difficulty to select. - /// If omitted, this will try to present the first beatmap from the current ruleset. + /// Optional predicate used to filter which difficulties to select. + /// If omitted, this will try to present a recommended beatmap from the current ruleset. /// In case of failure the first difficulty of the set will be presented, ignoring the predicate. /// public void PresentBeatmap(BeatmapSetInfo beatmap, Predicate difficultyCriteria = null) @@ -351,7 +351,10 @@ namespace osu.Game if (!beatmaps.Any()) beatmaps = databasedSet.Beatmaps; - var selection = DifficultyRecommender.GetRecommendedBeatmap(beatmaps); + var selection = DifficultyRecommender.GetRecommendedBeatmap(beatmaps) ?? ( + // fallback if a difficulty can't be recommended, maybe we are offline + databasedSet.Beatmaps.Find(b => b.Ruleset.Equals(Ruleset.Value)) ?? databasedSet.Beatmaps.First() + ); Ruleset.Value = selection.Ruleset; Beatmap.Value = BeatmapManager.GetWorkingBeatmap(selection); From 58e122a7cb1c0b47365e1fe28c16f24d85ce0681 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Tue, 14 Apr 2020 19:56:41 +0300 Subject: [PATCH 006/328] Better fallback logic --- osu.Game/OsuGame.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e64ca3ad87..fea89155f5 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -322,8 +322,6 @@ namespace osu.Game /// public void PresentBeatmap(BeatmapSetInfo beatmap, Predicate difficultyCriteria = null) { - difficultyCriteria ??= _ => true; - var databasedSet = beatmap.OnlineBeatmapSetID != null ? BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmap.OnlineBeatmapSetID) : BeatmapManager.QueryBeatmapSet(s => s.Hash == beatmap.Hash); @@ -347,14 +345,20 @@ namespace osu.Game } // Find beatmaps that match our predicate. - var beatmaps = databasedSet.Beatmaps.Where(b => difficultyCriteria(b)); + var beatmaps = databasedSet.Beatmaps.Where(b => difficultyCriteria?.Invoke(b) ?? true); if (!beatmaps.Any()) beatmaps = databasedSet.Beatmaps; - var selection = DifficultyRecommender.GetRecommendedBeatmap(beatmaps) ?? ( - // fallback if a difficulty can't be recommended, maybe we are offline - databasedSet.Beatmaps.Find(b => b.Ruleset.Equals(Ruleset.Value)) ?? databasedSet.Beatmaps.First() - ); + var selection = DifficultyRecommender.GetRecommendedBeatmap(beatmaps); + + // fallback if a difficulty can't be recommended, maybe we are offline + if (selection == null) + { + if (difficultyCriteria != null) + selection = beatmaps.First(); + else + selection = databasedSet.Beatmaps.Find(b => b.Ruleset.Equals(Ruleset.Value)) ?? databasedSet.Beatmaps.First(); + } Ruleset.Value = selection.Ruleset; Beatmap.Value = BeatmapManager.GetWorkingBeatmap(selection); From 47187ec14cbbcfe9ebb8157150cae30e1346c2aa Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Wed, 15 Apr 2020 18:04:23 +0300 Subject: [PATCH 007/328] Simplify recommended beatmap presenting --- osu.Game/OsuGame.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index fea89155f5..68bf9c822f 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -346,19 +346,18 @@ namespace osu.Game // Find beatmaps that match our predicate. var beatmaps = databasedSet.Beatmaps.Where(b => difficultyCriteria?.Invoke(b) ?? true); + + // Use all beatmaps if predicate matched nothing if (!beatmaps.Any()) beatmaps = databasedSet.Beatmaps; - var selection = DifficultyRecommender.GetRecommendedBeatmap(beatmaps); - - // fallback if a difficulty can't be recommended, maybe we are offline - if (selection == null) - { - if (difficultyCriteria != null) - selection = beatmaps.First(); - else - selection = databasedSet.Beatmaps.Find(b => b.Ruleset.Equals(Ruleset.Value)) ?? databasedSet.Beatmaps.First(); - } + // Try to select recommended beatmap + // This should give us a beatmap from current ruleset if there are any in our matched beatmaps + var selection = DifficultyRecommender.GetRecommendedBeatmap(beatmaps) ?? ( + // Fallback if a difficulty can't be recommended, maybe we are offline + // First try to find a beatmap in current ruleset, otherwise use first beatmap + beatmaps.FirstOrDefault(b => b.Ruleset.Equals(Ruleset.Value)) ?? beatmaps.First() + ); Ruleset.Value = selection.Ruleset; Beatmap.Value = BeatmapManager.GetWorkingBeatmap(selection); From b5c1752f0a40a731bdefc4c328c2b9cb05a953bf Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Wed, 15 Apr 2020 18:14:51 +0300 Subject: [PATCH 008/328] Calculate best ruleset order only once --- .../Screens/Select/DifficultyRecommender.cs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index bdc81ad066..e7536db356 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -32,8 +32,6 @@ namespace osu.Game.Screens.Select private void load() { api.Register(this); - - ruleset.ValueChanged += _ => bestRulesetOrder = null; } /// @@ -90,19 +88,22 @@ namespace osu.Game.Screens.Select private IEnumerable getBestRulesetOrder() { if (bestRulesetOrder != null) - return bestRulesetOrder; + return moveCurrentRulesetToFirst(); - var otherRulesets = recommendedStarDifficulty.ToList() - .Where(pair => !pair.Key.Equals(ruleset.Value)) - .OrderBy(pair => pair.Value) - .Select(pair => pair.Key) - .Reverse(); + bestRulesetOrder = recommendedStarDifficulty.ToList() + .OrderBy(pair => pair.Value) + .Select(pair => pair.Key) + .Reverse(); - var rulesetList = new List(new[] { ruleset.Value }); - rulesetList.AddRange(otherRulesets); + return moveCurrentRulesetToFirst(); + } - bestRulesetOrder = rulesetList; - return rulesetList; + private IEnumerable moveCurrentRulesetToFirst() + { + var orderedRulesets = bestRulesetOrder.ToList(); + orderedRulesets.Remove(ruleset.Value); + orderedRulesets.Insert(0, ruleset.Value); + return orderedRulesets; } public void APIStateChanged(IAPIProvider api, APIState state) From da9bd74e2eef2f08b85e6e8e15501f70299c4218 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Wed, 15 Apr 2020 20:19:17 +0300 Subject: [PATCH 009/328] Very basic testing --- .../TestSceneBeatmapRecommendations.cs | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs new file mode 100644 index 0000000000..80a00ac9a1 --- /dev/null +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -0,0 +1,130 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Logging; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Select; +using osu.Game.Tests.Visual.Navigation; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual.SongSelect +{ + public class TestSceneBeatmapRecommendations : OsuGameTestScene + { + [Resolved] + private DifficultyRecommender recommender { get; set; } + + [SetUpSteps] + public new void SetUpSteps() + { + AddStep("register request handling", () => + { + Logger.Log($"Registering request handling for {(DummyAPIAccess)API}"); + ((DummyAPIAccess)API).HandleRequest = req => + { + Logger.Log($"New request {req}"); + + switch (req) + { + case GetUserRequest userRequest: + userRequest.TriggerSuccess(new User + { + Username = @"Dummy", + Id = 1001, + Statistics = new UserStatistics + { + PP = 928 // Expected recommended star difficulty is 2.999 + } + }); + break; + } + }; + // Force recommender to calculate its star ratings again + recommender.APIStateChanged(API, APIState.Online); + }); + } + + [Test] + public void TestPresentedBeatmapIsRecommended() + { + var importFunctions = importBeatmaps(5); + + for (int i = 0; i < 5; i++) + { + presentAndConfirm(importFunctions[i], i); + } + } + + private List> importBeatmaps(int amount, RulesetInfo ruleset = null) + { + var importFunctions = new List>(); + + for (int i = 0; i < amount; i++) + { + importFunctions.Add(importBeatmap(i, ruleset)); + } + + return importFunctions; + } + + private Func importBeatmap(int i, RulesetInfo ruleset = null) + { + BeatmapSetInfo imported = null; + AddStep($"import beatmap {i * 1000}", () => + { + var difficulty = new BeatmapDifficulty(); + var metadata = new BeatmapMetadata + { + Artist = "SomeArtist", + AuthorString = "SomeAuthor", + Title = $"import {i * 1000}" + }; + + var beatmaps = new List(); + + for (int j = 1; j <= 5; j++) + { + beatmaps.Add(new BeatmapInfo + { + OnlineBeatmapID = j * 1024 + i * 5, + Metadata = metadata, + BaseDifficulty = difficulty, + Ruleset = ruleset ?? new OsuRuleset().RulesetInfo, + StarDifficulty = j, + }); + } + + imported = Game.BeatmapManager.Import(new BeatmapSetInfo + { + Hash = Guid.NewGuid().ToString(), + OnlineBeatmapSetID = i, + Metadata = metadata, + Beatmaps = beatmaps, + }).Result; + }); + + AddAssert($"import {i * 1000} succeeded", () => imported != null); + + return () => imported; + } + + private void presentAndConfirm(Func getImport, int importedID) + { + AddStep("present beatmap", () => Game.PresentBeatmap(getImport())); + + AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect); + AddUntilStep("recommended beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineBeatmapID == importedID * 5 + 1024 * 3); + AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Beatmaps.First().Ruleset.ID); + } + } +} From 1ac9ee599088d893211bd6dbcdba16662275e745 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Fri, 17 Apr 2020 18:15:11 +0300 Subject: [PATCH 010/328] Optimize recommender (for custom rulesets) --- .../Screens/Select/DifficultyRecommender.cs | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index e7536db356..07dfc3a85e 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -51,8 +51,7 @@ namespace osu.Game.Screens.Select foreach (var r in getBestRulesetOrder()) { - if (!recommendedStarDifficulty.TryGetValue(ruleset.Value, out var stars)) - break; + recommendedStarDifficulty.TryGetValue(ruleset.Value, out var stars); beatmap = beatmaps.Where(b => b.Ruleset.Equals(r)).OrderBy(b => { @@ -75,6 +74,7 @@ namespace osu.Game.Screens.Select req.Success += result => { + bestRulesetOrder = null; // algorithm taken from https://github.com/ppy/osu-web/blob/e6e2825516449e3d0f3f5e1852c6bdd3428c3437/app/Models/User.php#L1505 recommendedStarDifficulty[rulesetInfo] = Math.Pow((double)(result.Statistics.PP ?? 0), 0.4) * 0.195; }; @@ -87,22 +87,30 @@ namespace osu.Game.Screens.Select private IEnumerable getBestRulesetOrder() { - if (bestRulesetOrder != null) - return moveCurrentRulesetToFirst(); - - bestRulesetOrder = recommendedStarDifficulty.ToList() - .OrderBy(pair => pair.Value) - .Select(pair => pair.Key) - .Reverse(); + bestRulesetOrder ??= recommendedStarDifficulty.ToList() + .OrderBy(pair => pair.Value) + .Select(pair => pair.Key) + .Reverse(); return moveCurrentRulesetToFirst(); } private IEnumerable moveCurrentRulesetToFirst() { - var orderedRulesets = bestRulesetOrder.ToList(); - orderedRulesets.Remove(ruleset.Value); - orderedRulesets.Insert(0, ruleset.Value); + List orderedRulesets = null; + + if (bestRulesetOrder.Contains(ruleset.Value)) + { + orderedRulesets = bestRulesetOrder.ToList(); + orderedRulesets.Remove(ruleset.Value); + orderedRulesets.Insert(0, ruleset.Value); + } + else + { + orderedRulesets = new List { ruleset.Value }; + orderedRulesets.AddRange(bestRulesetOrder); + } + return orderedRulesets; } From 90fa58b3b65c7221990bfbc12237577a489c4741 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Fri, 17 Apr 2020 19:55:51 +0300 Subject: [PATCH 011/328] More testing --- .../TestSceneBeatmapRecommendations.cs | 96 +++++++++++++------ .../Online/API/Requests/GetUserRequest.cs | 6 +- 2 files changed, 70 insertions(+), 32 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index 80a00ac9a1..ec5fe65fdd 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -6,44 +6,53 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; -using osu.Framework.Logging; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Rulesets; -using osu.Game.Rulesets.Osu; using osu.Game.Screens.Select; using osu.Game.Tests.Visual.Navigation; using osu.Game.Users; namespace osu.Game.Tests.Visual.SongSelect { + [HeadlessTest] public class TestSceneBeatmapRecommendations : OsuGameTestScene { [Resolved] private DifficultyRecommender recommender { get; set; } + [Resolved] + private RulesetStore rulesets { get; set; } + [SetUpSteps] public new void SetUpSteps() { AddStep("register request handling", () => { - Logger.Log($"Registering request handling for {(DummyAPIAccess)API}"); ((DummyAPIAccess)API).HandleRequest = req => { - Logger.Log($"New request {req}"); - switch (req) { case GetUserRequest userRequest: + + decimal pp = userRequest.Ruleset.ID switch + { + 0 => 336, // Expected recommended star difficulty 2* + 1 => 928, // Expected recommended star difficulty 3* + 2 => 1905, // Expected recommended star difficulty 4* + 3 => 3329, // Expected recommended star difficulty 5* + _ => 0 + }; + userRequest.TriggerSuccess(new User { Username = @"Dummy", Id = 1001, Statistics = new UserStatistics { - PP = 928 // Expected recommended star difficulty is 2.999 + PP = pp } }); break; @@ -57,74 +66,103 @@ namespace osu.Game.Tests.Visual.SongSelect [Test] public void TestPresentedBeatmapIsRecommended() { - var importFunctions = importBeatmaps(5); + var importFunctions = new List>(); for (int i = 0; i < 5; i++) { - presentAndConfirm(importFunctions[i], i); + importFunctions.Add(importBeatmap(i, new List { null, null, null, null, null })); } - } - private List> importBeatmaps(int amount, RulesetInfo ruleset = null) - { - var importFunctions = new List>(); - - for (int i = 0; i < amount; i++) + for (int i = 0; i < 5; i++) { - importFunctions.Add(importBeatmap(i, ruleset)); + presentAndConfirm(importFunctions[i], i, 2); } - - return importFunctions; } - private Func importBeatmap(int i, RulesetInfo ruleset = null) + [Test] + public void TestBestRulesetIsRecommended() + { + var osuRuleset = rulesets.AvailableRulesets.First(r => r.ID == 0); + var taikoRuleset = rulesets.AvailableRulesets.First(r => r.ID == 1); + var catchRuleset = rulesets.AvailableRulesets.First(r => r.ID == 2); + var maniaRuleset = rulesets.AvailableRulesets.First(r => r.ID == 3); + + var osuImport = importBeatmap(0, new List { osuRuleset }); + var mixedImport = importBeatmap(1, new List { taikoRuleset, catchRuleset, maniaRuleset }); + + // Make sure we are on standard ruleset + presentAndConfirm(osuImport, 0, 1); + + // Present mixed difficulty set, expect ruleset with highest star difficulty + presentAndConfirm(mixedImport, 1, 3); + } + + [Test] + public void TestSecondBestRulesetIsRecommended() + { + var osuRuleset = rulesets.AvailableRulesets.First(r => r.ID == 0); + var taikoRuleset = rulesets.AvailableRulesets.First(r => r.ID == 1); + var catchRuleset = rulesets.AvailableRulesets.First(r => r.ID == 2); + + var osuImport = importBeatmap(0, new List { osuRuleset }); + var mixedImport = importBeatmap(1, new List { taikoRuleset, catchRuleset, taikoRuleset }); + + // Make sure we are on standard ruleset + presentAndConfirm(osuImport, 0, 1); + + // Present mixed difficulty set, expect ruleset with highest star difficulty + presentAndConfirm(mixedImport, 1, 2); + } + + private Func importBeatmap(int importID, List rulesets) { BeatmapSetInfo imported = null; - AddStep($"import beatmap {i * 1000}", () => + AddStep($"import beatmap {importID}", () => { var difficulty = new BeatmapDifficulty(); var metadata = new BeatmapMetadata { Artist = "SomeArtist", AuthorString = "SomeAuthor", - Title = $"import {i * 1000}" + Title = $"import {importID}" }; var beatmaps = new List(); + int difficultyID = 1; - for (int j = 1; j <= 5; j++) + foreach (RulesetInfo r in rulesets) { beatmaps.Add(new BeatmapInfo { - OnlineBeatmapID = j * 1024 + i * 5, + OnlineBeatmapID = importID + 1024 * difficultyID, Metadata = metadata, BaseDifficulty = difficulty, - Ruleset = ruleset ?? new OsuRuleset().RulesetInfo, - StarDifficulty = j, + Ruleset = r ?? rulesets.First(), + StarDifficulty = difficultyID, }); + difficultyID++; } imported = Game.BeatmapManager.Import(new BeatmapSetInfo { Hash = Guid.NewGuid().ToString(), - OnlineBeatmapSetID = i, + OnlineBeatmapSetID = importID, Metadata = metadata, Beatmaps = beatmaps, }).Result; }); - AddAssert($"import {i * 1000} succeeded", () => imported != null); + AddAssert($"import {importID} succeeded", () => imported != null); return () => imported; } - private void presentAndConfirm(Func getImport, int importedID) + private void presentAndConfirm(Func getImport, int importedID, int expextedDiff) { AddStep("present beatmap", () => Game.PresentBeatmap(getImport())); AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect); - AddUntilStep("recommended beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineBeatmapID == importedID * 5 + 1024 * 3); - AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Beatmaps.First().Ruleset.ID); + AddUntilStep("recommended beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineBeatmapID == importedID + 1024 * expextedDiff); } } } diff --git a/osu.Game/Online/API/Requests/GetUserRequest.cs b/osu.Game/Online/API/Requests/GetUserRequest.cs index 31b7e95b39..42aad6f9eb 100644 --- a/osu.Game/Online/API/Requests/GetUserRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRequest.cs @@ -9,14 +9,14 @@ namespace osu.Game.Online.API.Requests public class GetUserRequest : APIRequest { private readonly long? userId; - private readonly RulesetInfo ruleset; + public readonly RulesetInfo Ruleset; public GetUserRequest(long? userId = null, RulesetInfo ruleset = null) { this.userId = userId; - this.ruleset = ruleset; + Ruleset = ruleset; } - protected override string Target => userId.HasValue ? $@"users/{userId}/{ruleset?.ShortName}" : $@"me/{ruleset?.ShortName}"; + protected override string Target => userId.HasValue ? $@"users/{userId}/{Ruleset?.ShortName}" : $@"me/{Ruleset?.ShortName}"; } } From 4aaa00e3219611c387dcdf20dc4f04103bb7af07 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Fri, 17 Apr 2020 20:33:12 +0300 Subject: [PATCH 012/328] Fix CI complaints --- osu.Game/Screens/Select/DifficultyRecommender.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index 07dfc3a85e..4d48cc3fe7 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -97,7 +97,7 @@ namespace osu.Game.Screens.Select private IEnumerable moveCurrentRulesetToFirst() { - List orderedRulesets = null; + List orderedRulesets; if (bestRulesetOrder.Contains(ruleset.Value)) { From ce47b7ca932f85b2ac323b0c220da2eaa88dd3ef Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Sat, 25 Apr 2020 10:21:01 +0300 Subject: [PATCH 013/328] Unnest in SetUpSteps --- .../TestSceneBeatmapRecommendations.cs | 59 ++++++++++++------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index ec5fe65fdd..3f2117a4f8 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -36,31 +36,48 @@ namespace osu.Game.Tests.Visual.SongSelect switch (req) { case GetUserRequest userRequest: - - decimal pp = userRequest.Ruleset.ID switch - { - 0 => 336, // Expected recommended star difficulty 2* - 1 => 928, // Expected recommended star difficulty 3* - 2 => 1905, // Expected recommended star difficulty 4* - 3 => 3329, // Expected recommended star difficulty 5* - _ => 0 - }; - - userRequest.TriggerSuccess(new User - { - Username = @"Dummy", - Id = 1001, - Statistics = new UserStatistics - { - PP = pp - } - }); + userRequest.TriggerSuccess(getUser(userRequest.Ruleset.ID)); break; } }; - // Force recommender to calculate its star ratings again - recommender.APIStateChanged(API, APIState.Online); }); + + // Force recommender to calculate its star ratings again + AddStep("calculate recommended SRs", () => recommender.APIStateChanged(API, APIState.Online)); + + User getUser(int? rulesetID) + { + return new User + { + Username = @"Dummy", + Id = 1001, + Statistics = new UserStatistics + { + PP = getNecessaryPP(rulesetID) + } + }; + } + + decimal getNecessaryPP(int? rulesetID) + { + switch (rulesetID) + { + case 0: + return 336; + + case 1: + return 928; + + case 2: + return 1905; + + case 3: + return 3329; + + default: + return 0; + } + } } [Test] From 52416ea90a49f2632a2173ab1c55ca458883b4bc Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Sat, 25 Apr 2020 10:22:19 +0300 Subject: [PATCH 014/328] Use GetRuleset --- .../SongSelect/TestSceneBeatmapRecommendations.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index 3f2117a4f8..aed1729d7d 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -99,10 +99,10 @@ namespace osu.Game.Tests.Visual.SongSelect [Test] public void TestBestRulesetIsRecommended() { - var osuRuleset = rulesets.AvailableRulesets.First(r => r.ID == 0); - var taikoRuleset = rulesets.AvailableRulesets.First(r => r.ID == 1); - var catchRuleset = rulesets.AvailableRulesets.First(r => r.ID == 2); - var maniaRuleset = rulesets.AvailableRulesets.First(r => r.ID == 3); + var osuRuleset = rulesets.GetRuleset(0); + var taikoRuleset = rulesets.GetRuleset(1); + var catchRuleset = rulesets.GetRuleset(2); + var maniaRuleset = rulesets.GetRuleset(3); var osuImport = importBeatmap(0, new List { osuRuleset }); var mixedImport = importBeatmap(1, new List { taikoRuleset, catchRuleset, maniaRuleset }); @@ -117,9 +117,9 @@ namespace osu.Game.Tests.Visual.SongSelect [Test] public void TestSecondBestRulesetIsRecommended() { - var osuRuleset = rulesets.AvailableRulesets.First(r => r.ID == 0); - var taikoRuleset = rulesets.AvailableRulesets.First(r => r.ID == 1); - var catchRuleset = rulesets.AvailableRulesets.First(r => r.ID == 2); + var osuRuleset = rulesets.GetRuleset(0); + var taikoRuleset = rulesets.GetRuleset(1); + var catchRuleset = rulesets.GetRuleset(2); var osuImport = importBeatmap(0, new List { osuRuleset }); var mixedImport = importBeatmap(1, new List { taikoRuleset, catchRuleset, taikoRuleset }); From e906ec4d92d8d75467684630a80c606053ff7484 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Sat, 25 Apr 2020 10:25:07 +0300 Subject: [PATCH 015/328] Fix typo --- .../Visual/SongSelect/TestSceneBeatmapRecommendations.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index aed1729d7d..f3a118572f 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -174,12 +174,12 @@ namespace osu.Game.Tests.Visual.SongSelect return () => imported; } - private void presentAndConfirm(Func getImport, int importedID, int expextedDiff) + private void presentAndConfirm(Func getImport, int importedID, int expectedDiff) { AddStep("present beatmap", () => Game.PresentBeatmap(getImport())); AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect); - AddUntilStep("recommended beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineBeatmapID == importedID + 1024 * expextedDiff); + AddUntilStep("recommended beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineBeatmapID == importedID + 1024 * expectedDiff); } } } From e65acc34018df7f77594ae8fff8c369a62a01ef8 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Sat, 25 Apr 2020 10:36:19 +0300 Subject: [PATCH 016/328] Other review suggestions --- .../TestSceneBeatmapRecommendations.cs | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index f3a118572f..f49dae4033 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -87,12 +87,12 @@ namespace osu.Game.Tests.Visual.SongSelect for (int i = 0; i < 5; i++) { - importFunctions.Add(importBeatmap(i, new List { null, null, null, null, null })); + importFunctions.Add(importBeatmap(i, Enumerable.Repeat(rulesets.GetRuleset(0), 5))); } for (int i = 0; i < 5; i++) { - presentAndConfirm(importFunctions[i], i, 2); + presentAndConfirm(importFunctions[i], 2); } } @@ -108,10 +108,10 @@ namespace osu.Game.Tests.Visual.SongSelect var mixedImport = importBeatmap(1, new List { taikoRuleset, catchRuleset, maniaRuleset }); // Make sure we are on standard ruleset - presentAndConfirm(osuImport, 0, 1); + presentAndConfirm(osuImport, 1); // Present mixed difficulty set, expect ruleset with highest star difficulty - presentAndConfirm(mixedImport, 1, 3); + presentAndConfirm(mixedImport, 3); } [Test] @@ -125,13 +125,13 @@ namespace osu.Game.Tests.Visual.SongSelect var mixedImport = importBeatmap(1, new List { taikoRuleset, catchRuleset, taikoRuleset }); // Make sure we are on standard ruleset - presentAndConfirm(osuImport, 0, 1); + presentAndConfirm(osuImport, 1); // Present mixed difficulty set, expect ruleset with highest star difficulty - presentAndConfirm(mixedImport, 1, 2); + presentAndConfirm(mixedImport, 2); } - private Func importBeatmap(int importID, List rulesets) + private Func importBeatmap(int importID, IEnumerable rulesetEnumerable) { BeatmapSetInfo imported = null; AddStep($"import beatmap {importID}", () => @@ -147,14 +147,14 @@ namespace osu.Game.Tests.Visual.SongSelect var beatmaps = new List(); int difficultyID = 1; - foreach (RulesetInfo r in rulesets) + foreach (RulesetInfo r in rulesetEnumerable) { beatmaps.Add(new BeatmapInfo { OnlineBeatmapID = importID + 1024 * difficultyID, Metadata = metadata, BaseDifficulty = difficulty, - Ruleset = r ?? rulesets.First(), + Ruleset = r ?? rulesets.AvailableRulesets.First(), StarDifficulty = difficultyID, }); difficultyID++; @@ -174,12 +174,16 @@ namespace osu.Game.Tests.Visual.SongSelect return () => imported; } - private void presentAndConfirm(Func getImport, int importedID, int expectedDiff) + private void presentAndConfirm(Func getImport, int expectedDiff) { AddStep("present beatmap", () => Game.PresentBeatmap(getImport())); AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect); - AddUntilStep("recommended beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineBeatmapID == importedID + 1024 * expectedDiff); + AddUntilStep("recommended beatmap displayed", () => + { + int? expectedID = getImport().Beatmaps[expectedDiff - 1].OnlineBeatmapID; + return Game.Beatmap.Value.BeatmapInfo.OnlineBeatmapID == expectedID; + }); } } } From f68a7401b9577ca357ac931129133306b632a159 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Sat, 25 Apr 2020 10:37:18 +0300 Subject: [PATCH 017/328] Fix comment --- .../Visual/SongSelect/TestSceneBeatmapRecommendations.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index f49dae4033..a6e3e0c1c6 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -127,7 +127,7 @@ namespace osu.Game.Tests.Visual.SongSelect // Make sure we are on standard ruleset presentAndConfirm(osuImport, 1); - // Present mixed difficulty set, expect ruleset with highest star difficulty + // Present mixed difficulty set, expect ruleset with second highest star difficulty presentAndConfirm(mixedImport, 2); } From cea582992fa9075899d36d0a4792c7fe13db4bce Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Sat, 25 Apr 2020 10:47:12 +0300 Subject: [PATCH 018/328] Fix early return check --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index eb86ef4116..9707475cc7 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -339,7 +339,7 @@ namespace osu.Game menuScreen.LoadToSolo(); // we might even already be at the song - if (Beatmap.Value.BeatmapSetInfo.Hash == databasedSet.Hash && difficultyCriteria(Beatmap.Value.BeatmapInfo)) + if (Beatmap.Value.BeatmapSetInfo.Hash == databasedSet.Hash && (difficultyCriteria?.Invoke(Beatmap.Value.BeatmapInfo) ?? true)) { return; } From 16f53991a898e4b7aae75c8bbfc4935b6876cf57 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Sat, 25 Apr 2020 10:50:00 +0300 Subject: [PATCH 019/328] Test presenting same beatmap more than once --- osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs index 27f5b29738..eb73fded2f 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs @@ -55,8 +55,14 @@ namespace osu.Game.Tests.Visual.Navigation var secondimport = importBeatmap(3); presentAndConfirm(secondimport); + // Test presenting same beatmap more than once + presentAndConfirm(secondimport); + presentSecondDifficultyAndConfirm(firstImport, 1); presentSecondDifficultyAndConfirm(secondimport, 3); + + // Test presenting same beatmap more than once + presentSecondDifficultyAndConfirm(secondimport, 3); } [Test] From 2913a8183538f823858aace50834f9e38a74b726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 1 May 2020 16:59:45 +0200 Subject: [PATCH 020/328] Improve test code quality & safety --- .../Visual/Navigation/OsuGameTestScene.cs | 2 +- .../TestSceneBeatmapRecommendations.cs | 122 +++++++++--------- 2 files changed, 60 insertions(+), 64 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs b/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs index 31afce86ae..a3ef33b916 100644 --- a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs +++ b/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs @@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.Navigation } [SetUpSteps] - public void SetUpSteps() + public virtual void SetUpSteps() { AddStep("Create new game instance", () => { diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index a6e3e0c1c6..5fb4e80b51 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -11,23 +11,25 @@ using osu.Game.Beatmaps; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Rulesets; +using osu.Game.Rulesets.Catch; +using osu.Game.Rulesets.Mania; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Taiko; using osu.Game.Screens.Select; using osu.Game.Tests.Visual.Navigation; using osu.Game.Users; namespace osu.Game.Tests.Visual.SongSelect { - [HeadlessTest] public class TestSceneBeatmapRecommendations : OsuGameTestScene { + protected override bool UseOnlineAPI => false; + [Resolved] private DifficultyRecommender recommender { get; set; } - [Resolved] - private RulesetStore rulesets { get; set; } - [SetUpSteps] - public new void SetUpSteps() + public override void SetUpSteps() { AddStep("register request handling", () => { @@ -42,6 +44,8 @@ namespace osu.Game.Tests.Visual.SongSelect }; }); + base.SetUpSteps(); + // Force recommender to calculate its star ratings again AddStep("calculate recommended SRs", () => recommender.APIStateChanged(API, APIState.Online)); @@ -83,97 +87,89 @@ namespace osu.Game.Tests.Visual.SongSelect [Test] public void TestPresentedBeatmapIsRecommended() { - var importFunctions = new List>(); + List beatmapSets = null; + const int import_count = 5; - for (int i = 0; i < 5; i++) + AddStep("import 5 maps", () => { - importFunctions.Add(importBeatmap(i, Enumerable.Repeat(rulesets.GetRuleset(0), 5))); - } + beatmapSets = new List(); - for (int i = 0; i < 5; i++) - { - presentAndConfirm(importFunctions[i], 2); - } + for (int i = 0; i < import_count; ++i) + { + beatmapSets.Add(importBeatmapSet(i, Enumerable.Repeat(new OsuRuleset().RulesetInfo, 5))); + } + }); + + AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(beatmapSets)); + + presentAndConfirm(() => beatmapSets[3], 2); } [Test] public void TestBestRulesetIsRecommended() { - var osuRuleset = rulesets.GetRuleset(0); - var taikoRuleset = rulesets.GetRuleset(1); - var catchRuleset = rulesets.GetRuleset(2); - var maniaRuleset = rulesets.GetRuleset(3); + BeatmapSetInfo osuSet = null, mixedSet = null; - var osuImport = importBeatmap(0, new List { osuRuleset }); - var mixedImport = importBeatmap(1, new List { taikoRuleset, catchRuleset, maniaRuleset }); + AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(0, new[] { new OsuRuleset().RulesetInfo })); + AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(1, + new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new ManiaRuleset().RulesetInfo })); + + AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, mixedSet })); // Make sure we are on standard ruleset - presentAndConfirm(osuImport, 1); + presentAndConfirm(() => osuSet, 1); // Present mixed difficulty set, expect ruleset with highest star difficulty - presentAndConfirm(mixedImport, 3); + presentAndConfirm(() => mixedSet, 3); } [Test] public void TestSecondBestRulesetIsRecommended() { - var osuRuleset = rulesets.GetRuleset(0); - var taikoRuleset = rulesets.GetRuleset(1); - var catchRuleset = rulesets.GetRuleset(2); + BeatmapSetInfo osuSet = null, mixedSet = null; - var osuImport = importBeatmap(0, new List { osuRuleset }); - var mixedImport = importBeatmap(1, new List { taikoRuleset, catchRuleset, taikoRuleset }); + AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(0, new[] { new OsuRuleset().RulesetInfo })); + AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(1, + new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new TaikoRuleset().RulesetInfo })); + + AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, mixedSet })); // Make sure we are on standard ruleset - presentAndConfirm(osuImport, 1); + presentAndConfirm(() => osuSet, 1); // Present mixed difficulty set, expect ruleset with second highest star difficulty - presentAndConfirm(mixedImport, 2); + presentAndConfirm(() => mixedSet, 2); } - private Func importBeatmap(int importID, IEnumerable rulesetEnumerable) + private BeatmapSetInfo importBeatmapSet(int importID, IEnumerable difficultyRulesets) { - BeatmapSetInfo imported = null; - AddStep($"import beatmap {importID}", () => + var metadata = new BeatmapMetadata { - var difficulty = new BeatmapDifficulty(); - var metadata = new BeatmapMetadata - { - Artist = "SomeArtist", - AuthorString = "SomeAuthor", - Title = $"import {importID}" - }; + Artist = "SomeArtist", + AuthorString = "SomeAuthor", + Title = $"import {importID}" + }; - var beatmaps = new List(); - int difficultyID = 1; - - foreach (RulesetInfo r in rulesetEnumerable) + var beatmapSet = new BeatmapSetInfo + { + Hash = Guid.NewGuid().ToString(), + OnlineBeatmapSetID = importID, + Metadata = metadata, + Beatmaps = difficultyRulesets.Select((ruleset, difficultyIndex) => new BeatmapInfo { - beatmaps.Add(new BeatmapInfo - { - OnlineBeatmapID = importID + 1024 * difficultyID, - Metadata = metadata, - BaseDifficulty = difficulty, - Ruleset = r ?? rulesets.AvailableRulesets.First(), - StarDifficulty = difficultyID, - }); - difficultyID++; - } - - imported = Game.BeatmapManager.Import(new BeatmapSetInfo - { - Hash = Guid.NewGuid().ToString(), - OnlineBeatmapSetID = importID, + OnlineBeatmapID = importID * 1024 + difficultyIndex, Metadata = metadata, - Beatmaps = beatmaps, - }).Result; - }); + BaseDifficulty = new BeatmapDifficulty(), + Ruleset = ruleset, + StarDifficulty = difficultyIndex + 1 + }).ToList() + }; - AddAssert($"import {importID} succeeded", () => imported != null); - - return () => imported; + return Game.BeatmapManager.Import(beatmapSet).Result; } + private bool ensureAllBeatmapSetsImported(IEnumerable beatmapSets) => beatmapSets.All(set => set != null); + private void presentAndConfirm(Func getImport, int expectedDiff) { AddStep("present beatmap", () => Game.PresentBeatmap(getImport())); From 9f091f3a5635cdca80c15511a7e888c70f0536f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 1 May 2020 17:02:28 +0200 Subject: [PATCH 021/328] Do not query API for custom rulesets --- osu.Game/Screens/Select/DifficultyRecommender.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index 4d48cc3fe7..e9c7f6c464 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -68,7 +68,8 @@ namespace osu.Game.Screens.Select private void calculateRecommendedDifficulties() { - rulesets.AvailableRulesets.ForEach(rulesetInfo => + // only query API for built-in rulesets + rulesets.AvailableRulesets.Where(ruleset => ruleset.ID <= 3).ForEach(rulesetInfo => { var req = new GetUserRequest(api.LocalUser.Value.Id, rulesetInfo); From 623611d9dc03e210f75615a260cde554aaef2a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 1 May 2020 17:15:35 +0200 Subject: [PATCH 022/328] Simplify ruleset ordering --- osu.Game/Screens/Select/DifficultyRecommender.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index e9c7f6c464..0dc4ff95ca 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -88,10 +88,9 @@ namespace osu.Game.Screens.Select private IEnumerable getBestRulesetOrder() { - bestRulesetOrder ??= recommendedStarDifficulty.ToList() - .OrderBy(pair => pair.Value) + bestRulesetOrder ??= recommendedStarDifficulty.OrderByDescending(pair => pair.Value) .Select(pair => pair.Key) - .Reverse(); + .ToList(); return moveCurrentRulesetToFirst(); } From 3cf60e6e00483b9fd39c001073e29517f2e2ed9e Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Fri, 1 May 2020 19:08:56 +0300 Subject: [PATCH 023/328] Add failing test --- .../TestSceneBeatmapRecommendations.cs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index 5fb4e80b51..68f31c5c73 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -141,6 +141,23 @@ namespace osu.Game.Tests.Visual.SongSelect presentAndConfirm(() => mixedSet, 2); } + [Test] + public void TestCorrectStarRatingIsUsed() + { + BeatmapSetInfo osuSet = null, maniaSet = null; + + AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(0, new[] { new OsuRuleset().RulesetInfo })); + AddStep("create mania beatmapset", () => maniaSet = importBeatmapSet(1, Enumerable.Repeat(new ManiaRuleset().RulesetInfo, 10))); + + AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, maniaSet })); + + // Make sure we are on standard ruleset + presentAndConfirm(() => osuSet, 1); + + // Present mania set, expect the difficulty that matches recommended mania star rating + presentAndConfirm(() => maniaSet, 5); + } + private BeatmapSetInfo importBeatmapSet(int importID, IEnumerable difficultyRulesets) { var metadata = new BeatmapMetadata @@ -161,7 +178,8 @@ namespace osu.Game.Tests.Visual.SongSelect Metadata = metadata, BaseDifficulty = new BeatmapDifficulty(), Ruleset = ruleset, - StarDifficulty = difficultyIndex + 1 + StarDifficulty = difficultyIndex + 1, + Version = $"SR{difficultyIndex + 1}" }).ToList() }; From 1c04d58d6e55f2a09a237c53a4a2b700ecf0d74d Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Fri, 1 May 2020 19:44:35 +0300 Subject: [PATCH 024/328] Fix recommender's incorrect usage of current ruleset --- osu.Game/Screens/Select/DifficultyRecommender.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index 0dc4ff95ca..0753bbc5bd 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Select foreach (var r in getBestRulesetOrder()) { - recommendedStarDifficulty.TryGetValue(ruleset.Value, out var stars); + recommendedStarDifficulty.TryGetValue(r, out var stars); beatmap = beatmaps.Where(b => b.Ruleset.Equals(r)).OrderBy(b => { From d30e4061cce9ef69ffeb08b342a9f77109b8935e Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Fri, 1 May 2020 19:46:49 +0300 Subject: [PATCH 025/328] Add clarifying comment about pp choice --- .../Visual/SongSelect/TestSceneBeatmapRecommendations.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index 68f31c5c73..fc14af3ab5 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -67,16 +67,16 @@ namespace osu.Game.Tests.Visual.SongSelect switch (rulesetID) { case 0: - return 336; + return 336; // recommended star rating of 2 case 1: - return 928; + return 928; // SR 3 case 2: - return 1905; + return 1905; // SR 4 case 3: - return 3329; + return 3329; // SR 5 default: return 0; From 6c5a6b42e59b53825fa73f29fb8de2a7eda42f08 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Sat, 21 Nov 2020 14:09:32 +0200 Subject: [PATCH 026/328] Only calculate recommended SR once --- osu.Game/Screens/Select/DifficultyRecommender.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index 2baabebdad..0e02b45650 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -69,8 +69,11 @@ namespace osu.Game.Screens.Select return beatmap; } - private void calculateRecommendedDifficulties() + private void calculateRecommendedDifficulties(bool onlyIfNoPreviousValues = false) { + if (recommendedStarDifficulty.Any() && onlyIfNoPreviousValues) + return; + // only query API for built-in rulesets rulesets.AvailableRulesets.Where(ruleset => ruleset.ID <= 3).ForEach(rulesetInfo => { @@ -122,7 +125,7 @@ namespace osu.Game.Screens.Select switch (state.NewValue) { case APIState.Online: - calculateRecommendedDifficulties(); + calculateRecommendedDifficulties(true); break; } }); From 72d9da5fac22583df2f275b1d5af65b1deb6e505 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Sat, 21 Nov 2020 14:26:09 +0200 Subject: [PATCH 027/328] Apply review suggestions --- osu.Game/OsuGame.cs | 25 +++++++++++-------- .../Screens/Select/DifficultyRecommender.cs | 14 +++-------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e5a299d4b0..acc42bb660 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -335,11 +335,15 @@ namespace osu.Game /// The user should have already requested this interactively. /// /// The beatmap to select. - /// - /// Optional predicate used to filter which difficulties to select. - /// If omitted, this will try to present a recommended beatmap from the current ruleset. - /// In case of failure the first difficulty of the set will be presented, ignoring the predicate. - /// + /// Optional predicate used to narrow the set of difficulties to select from when presenting. + /// + /// Among items satisfying the predicate, the order of preference is: + /// + /// beatmap with recommended difficulty, as provided by , + /// first beatmap from the current ruleset, + /// first beatmap from any ruleset. + /// + /// public void PresentBeatmap(BeatmapSetInfo beatmap, Predicate difficultyCriteria = null) { var databasedSet = beatmap.OnlineBeatmapSetID != null @@ -373,11 +377,12 @@ namespace osu.Game // Try to select recommended beatmap // This should give us a beatmap from current ruleset if there are any in our matched beatmaps - var selection = DifficultyRecommender.GetRecommendedBeatmap(beatmaps) ?? ( - // Fallback if a difficulty can't be recommended, maybe we are offline - // First try to find a beatmap in current ruleset, otherwise use first beatmap - beatmaps.FirstOrDefault(b => b.Ruleset.Equals(Ruleset.Value)) ?? beatmaps.First() - ); + var selection = DifficultyRecommender.GetRecommendedBeatmap(beatmaps); + // Fallback if a difficulty can't be recommended, maybe we are offline + // First try to find a beatmap in current ruleset + selection ??= beatmaps.FirstOrDefault(b => b.Ruleset.Equals(Ruleset.Value)); + // Otherwise use first beatmap + selection ??= beatmaps.First(); Ruleset.Value = selection.Ruleset; Beatmap.Value = BeatmapManager.GetWorkingBeatmap(selection); diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index 0e02b45650..ab64513ecb 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -81,7 +81,6 @@ namespace osu.Game.Screens.Select req.Success += result => { - bestRulesetOrder = null; // algorithm taken from https://github.com/ppy/osu-web/blob/e6e2825516449e3d0f3f5e1852c6bdd3428c3437/app/Models/User.php#L1505 recommendedStarDifficulty[rulesetInfo] = Math.Pow((double)(result.Statistics.PP ?? 0), 0.4) * 0.195; }; @@ -90,19 +89,12 @@ namespace osu.Game.Screens.Select }); } - private IEnumerable bestRulesetOrder; - private IEnumerable getBestRulesetOrder() { - bestRulesetOrder ??= recommendedStarDifficulty.OrderByDescending(pair => pair.Value) - .Select(pair => pair.Key) - .ToList(); + IEnumerable bestRulesetOrder = recommendedStarDifficulty.OrderByDescending(pair => pair.Value) + .Select(pair => pair.Key) + .ToList(); - return moveCurrentRulesetToFirst(); - } - - private IEnumerable moveCurrentRulesetToFirst() - { List orderedRulesets; if (bestRulesetOrder.Contains(ruleset.Value)) From 07db977af5a61d0f45f80352f183f8db50f616c4 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Sat, 21 Nov 2020 14:36:43 +0200 Subject: [PATCH 028/328] Remove no longer necessary force calculation Is no longer necessary because recommender uses bindable state value changes, compared to when the test was written, and runs the state change once on load --- .../Visual/SongSelect/TestSceneBeatmapRecommendations.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index fc14af3ab5..8a4914a31b 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -46,9 +46,6 @@ namespace osu.Game.Tests.Visual.SongSelect base.SetUpSteps(); - // Force recommender to calculate its star ratings again - AddStep("calculate recommended SRs", () => recommender.APIStateChanged(API, APIState.Online)); - User getUser(int? rulesetID) { return new User From 48dad61a46494a588da1078e39295648b3c84dc0 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Thu, 3 Dec 2020 19:38:45 +0200 Subject: [PATCH 029/328] Apply review suggestions --- .../SongSelect/TestSceneBeatmapRecommendations.cs | 2 -- osu.Game/Rulesets/ILegacyRuleset.cs | 2 ++ osu.Game/Screens/Select/DifficultyRecommender.cs | 12 ++++++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index 8a4914a31b..6c19206802 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -23,8 +23,6 @@ namespace osu.Game.Tests.Visual.SongSelect { public class TestSceneBeatmapRecommendations : OsuGameTestScene { - protected override bool UseOnlineAPI => false; - [Resolved] private DifficultyRecommender recommender { get; set; } diff --git a/osu.Game/Rulesets/ILegacyRuleset.cs b/osu.Game/Rulesets/ILegacyRuleset.cs index 06a85b5261..f4b03baccd 100644 --- a/osu.Game/Rulesets/ILegacyRuleset.cs +++ b/osu.Game/Rulesets/ILegacyRuleset.cs @@ -5,6 +5,8 @@ namespace osu.Game.Rulesets { public interface ILegacyRuleset { + const int MAX_LEGACY_RULESET_ID = 3; + /// /// Identifies the server-side ID of a legacy ruleset. /// diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index ab64513ecb..f8aaf5c0fd 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -26,6 +26,8 @@ namespace osu.Game.Screens.Select [Resolved] private Bindable ruleset { get; set; } + private int storedUserId; + private readonly Dictionary recommendedStarDifficulty = new Dictionary(); private readonly IBindable apiState = new Bindable(); @@ -69,13 +71,15 @@ namespace osu.Game.Screens.Select return beatmap; } - private void calculateRecommendedDifficulties(bool onlyIfNoPreviousValues = false) + private void calculateRecommendedDifficulties() { - if (recommendedStarDifficulty.Any() && onlyIfNoPreviousValues) + if (recommendedStarDifficulty.Any() && api.LocalUser.Value.Id == storedUserId) return; + storedUserId = api.LocalUser.Value.Id; + // only query API for built-in rulesets - rulesets.AvailableRulesets.Where(ruleset => ruleset.ID <= 3).ForEach(rulesetInfo => + rulesets.AvailableRulesets.Where(ruleset => ruleset.ID <= ILegacyRuleset.MAX_LEGACY_RULESET_ID).ForEach(rulesetInfo => { var req = new GetUserRequest(api.LocalUser.Value.Id, rulesetInfo); @@ -117,7 +121,7 @@ namespace osu.Game.Screens.Select switch (state.NewValue) { case APIState.Online: - calculateRecommendedDifficulties(true); + calculateRecommendedDifficulties(); break; } }); From 4cd2e207ac8b8353fd46019d0f446e8e258faf54 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Thu, 3 Dec 2020 19:53:06 +0200 Subject: [PATCH 030/328] Document getBestRulesetOrder --- osu.Game/Screens/Select/DifficultyRecommender.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index f8aaf5c0fd..21e6629add 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -93,6 +93,9 @@ namespace osu.Game.Screens.Select }); } + /// + /// Rulesets ordered by highest recommended star difficulty, except currently selected ruleset first + /// private IEnumerable getBestRulesetOrder() { IEnumerable bestRulesetOrder = recommendedStarDifficulty.OrderByDescending(pair => pair.Value) From 49be4978bd400fc4ffb1036eb4f9cc23cfd79a07 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Thu, 3 Dec 2020 19:53:41 +0200 Subject: [PATCH 031/328] Avoid calling ToList twice --- osu.Game/Screens/Select/DifficultyRecommender.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index 21e6629add..fa48316e9d 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -99,8 +99,7 @@ namespace osu.Game.Screens.Select private IEnumerable getBestRulesetOrder() { IEnumerable bestRulesetOrder = recommendedStarDifficulty.OrderByDescending(pair => pair.Value) - .Select(pair => pair.Key) - .ToList(); + .Select(pair => pair.Key); List orderedRulesets; From e792f070840bc3857467a3a3a74b00e0e7a075d3 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Thu, 3 Dec 2020 20:07:42 +0200 Subject: [PATCH 032/328] Add test for recommending current ruleset --- .../TestSceneBeatmapRecommendations.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index 6c19206802..75a33af247 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -100,6 +100,24 @@ namespace osu.Game.Tests.Visual.SongSelect presentAndConfirm(() => beatmapSets[3], 2); } + [Test] + public void TestCurrentRulesetIsRecommended() + { + BeatmapSetInfo catchSet = null, mixedSet = null; + + AddStep("create catch beatmapset", () => catchSet = importBeatmapSet(0, new[] { new CatchRuleset().RulesetInfo })); + AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(1, + new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new ManiaRuleset().RulesetInfo })); + + AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { catchSet, mixedSet })); + + // Switch to catch + presentAndConfirm(() => catchSet, 1); + + // Present mixed difficulty set, expect current ruleset to be selected + presentAndConfirm(() => mixedSet, 2); + } + [Test] public void TestBestRulesetIsRecommended() { From fb795f6bfdbb0638c21ae33e2f02e025ca38d780 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 16 Dec 2020 13:00:19 +0900 Subject: [PATCH 033/328] Add initial hook-up to spectator backend --- .../Visual/Gameplay/TestSceneSpectator.cs | 2 +- .../TestSceneSpectatorDrivenLeaderboard.cs | 74 +++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs index 3e5b561a6f..1fdff99da6 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs @@ -232,7 +232,7 @@ namespace osu.Game.Tests.Visual.Gameplay public class TestSpectatorStreamingClient : SpectatorStreamingClient { - public readonly User StreamingUser = new User { Id = 1234, Username = "Test user" }; + public readonly User StreamingUser = new User { Id = 55, Username = "Test user" }; public new BindableList PlayingUsers => (BindableList)base.PlayingUsers; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs new file mode 100644 index 0000000000..7211755ba6 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs @@ -0,0 +1,74 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Database; +using osu.Game.Online.API; +using osu.Game.Online.Spectator; +using osu.Game.Rulesets.Osu.Scoring; +using osu.Game.Screens.Play.HUD; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneSpectatorDrivenLeaderboard : OsuTestScene + { + [Cached(typeof(SpectatorStreamingClient))] + private TestSceneSpectator.TestSpectatorStreamingClient testSpectatorStreamingClient = new TestSceneSpectator.TestSpectatorStreamingClient(); + + // used just to show beatmap card for the time being. + protected override bool UseOnlineAPI => true; + + [SetUp] + public void SetUp() => Schedule(() => + { + OsuScoreProcessor scoreProcessor; + + testSpectatorStreamingClient.StartPlay(55); + + Children = new Drawable[] + { + scoreProcessor = new OsuScoreProcessor(), + new MultiplayerGameplayLeaderboard(scoreProcessor) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + }); + } + + public class MultiplayerGameplayLeaderboard : GameplayLeaderboard + { + private readonly OsuScoreProcessor scoreProcessor; + + public MultiplayerGameplayLeaderboard(OsuScoreProcessor scoreProcessor) + { + this.scoreProcessor = scoreProcessor; + + AddPlayer(new BindableDouble(), new GuestUser()); + } + + [Resolved] + private SpectatorStreamingClient streamingClient { get; set; } + + [Resolved] + private UserLookupCache userLookupCache { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + Console.WriteLine("got here"); + + foreach (var user in streamingClient.PlayingUsers) + { + streamingClient.WatchUser(user); + var resolvedUser = userLookupCache.GetUserAsync(user).Result; + AddPlayer(new BindableDouble(), resolvedUser); + } + } + } +} From 2954218897e90eb54a692063c0e4af5cf882d28c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 16 Dec 2020 15:25:20 +0900 Subject: [PATCH 034/328] Add method to ScoreProcessor to calculate score and accuracy from statistics --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 39 +++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 499673619f..b4f29d7a6e 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -68,7 +68,12 @@ namespace osu.Game.Rulesets.Scoring private readonly double comboPortion; private int maxAchievableCombo; - private double maxBaseScore; + + /// + /// The maximum achievable base score. + /// + public double MaxBaseScore { get; private set; } + private double rollingMaxBaseScore; private double baseScore; @@ -196,7 +201,7 @@ namespace osu.Game.Rulesets.Scoring private double getScore(ScoringMode mode) { return GetScore(mode, maxAchievableCombo, - maxBaseScore > 0 ? baseScore / maxBaseScore : 0, + MaxBaseScore > 0 ? baseScore / MaxBaseScore : 0, maxAchievableCombo > 0 ? (double)HighestCombo.Value / maxAchievableCombo : 1, scoreResultCounts); } @@ -227,6 +232,34 @@ namespace osu.Game.Rulesets.Scoring } } + /// + /// Given a minimal set of inputs, return the computed score and accuracy for the tracked beatmap / mods combination. + /// + /// The to compute the total score in. + /// The maximum combo achievable in the beatmap. + /// Statistics to be used for calculating accuracy, bonus score, etc. + /// The computed score and accuracy for provided inputs. + public (double score, double accuracy) GetScoreAndAccuracy(ScoringMode mode, int maxCombo, Dictionary statistics) + { + // calculate base score from statistics pairs + int computedBaseScore = 0; + + foreach (var pair in statistics) + { + if (!pair.Key.AffectsAccuracy()) + continue; + + computedBaseScore += Judgement.ToNumericResult(pair.Key) * pair.Value; + } + + double accuracy = MaxBaseScore > 0 ? computedBaseScore / MaxBaseScore : 0; + double comboRatio = maxAchievableCombo > 0 ? (double)HighestCombo.Value / maxAchievableCombo : 1; + + double score = GetScore(mode, maxAchievableCombo, accuracy, comboRatio, scoreResultCounts); + + return (score, accuracy); + } + private double getBonusScore(Dictionary statistics) => statistics.GetOrDefault(HitResult.SmallBonus) * Judgement.SMALL_BONUS_SCORE + statistics.GetOrDefault(HitResult.LargeBonus) * Judgement.LARGE_BONUS_SCORE; @@ -266,7 +299,7 @@ namespace osu.Game.Rulesets.Scoring if (storeResults) { maxAchievableCombo = HighestCombo.Value; - maxBaseScore = baseScore; + MaxBaseScore = baseScore; } baseScore = 0; From d009a0be51defe7890002ca501d666c40e29fbd9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 16 Dec 2020 15:25:27 +0900 Subject: [PATCH 035/328] Move class to final location --- .../HUD/MultiplayerGameplayLeaderboard.cs | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs new file mode 100644 index 0000000000..1d9fdd9ded --- /dev/null +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -0,0 +1,98 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Configuration; +using osu.Game.Database; +using osu.Game.Online.API; +using osu.Game.Online.Spectator; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Screens.Play.HUD +{ + public class MultiplayerGameplayLeaderboard : GameplayLeaderboard + { + private readonly ScoreProcessor scoreProcessor; + + /// + /// Construct a new leaderboard. + /// + /// A score processor instance to handle score calculation for scores of users in the match. + public MultiplayerGameplayLeaderboard(ScoreProcessor scoreProcessor) + { + this.scoreProcessor = scoreProcessor; + + AddPlayer(new BindableDouble(), new GuestUser()); + } + + [Resolved] + private SpectatorStreamingClient streamingClient { get; set; } + + [Resolved] + private UserLookupCache userLookupCache { get; set; } + + private readonly Dictionary userScores = new Dictionary(); + + private Bindable scoringMode; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + streamingClient.OnNewFrames += handleIncomingFrames; + + foreach (var user in streamingClient.PlayingUsers) + { + streamingClient.WatchUser(user); + var resolvedUser = userLookupCache.GetUserAsync(user).Result; + + var trackedUser = new TrackedUserData(); + + userScores[user] = trackedUser; + AddPlayer(trackedUser.Score, resolvedUser); + } + + scoringMode = config.GetBindable(OsuSetting.ScoreDisplayMode); + scoringMode.BindValueChanged(updateAllScores, true); + } + + private void updateAllScores(ValueChangedEvent mode) + { + foreach (var trackedData in userScores.Values) + trackedData.UpdateScore(scoreProcessor, mode.NewValue); + } + + private void handleIncomingFrames(int userId, FrameDataBundle bundle) + { + if (userScores.TryGetValue(userId, out var trackedData)) + { + trackedData.LastHeader = bundle.Header; + trackedData.UpdateScore(scoreProcessor, scoringMode.Value); + } + } + + private class TrackedUserData + { + public readonly BindableDouble Score = new BindableDouble(); + + public readonly BindableDouble Accuracy = new BindableDouble(); + + public readonly BindableInt CurrentCombo = new BindableInt(); + + [CanBeNull] + public FrameHeader LastHeader; + + public void UpdateScore(ScoreProcessor processor, ScoringMode mode) + { + if (LastHeader == null) + return; + + (Score.Value, Accuracy.Value) = processor.GetScoreAndAccuracy(mode, LastHeader.MaxCombo, LastHeader.Statistics.ToDictionary(s => s.Result, s => s.Count)); + CurrentCombo.Value = LastHeader.Combo; + } + } + } +} From 09d0ceb7668e115170437c1d2063ed883897ed02 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 16 Dec 2020 15:26:03 +0900 Subject: [PATCH 036/328] Add testing setup to get a better visual idea of how scoreboard will work fixup! Add method to ScoreProcessor to calculate score and accuracy from statistics --- .../TestSceneSpectatorDrivenLeaderboard.cs | 109 +++++++++++++----- .../HUD/MultiplayerGameplayLeaderboard.cs | 4 +- 2 files changed, 85 insertions(+), 28 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs index 7211755ba6..e7ebf6e92c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs @@ -2,14 +2,18 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; +using System.Threading.Tasks; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Game.Database; -using osu.Game.Online.API; +using osu.Framework.Utils; using osu.Game.Online.Spectator; +using osu.Game.Replays.Legacy; using osu.Game.Rulesets.Osu.Scoring; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; using osu.Game.Screens.Play.HUD; namespace osu.Game.Tests.Visual.Gameplay @@ -17,7 +21,7 @@ namespace osu.Game.Tests.Visual.Gameplay public class TestSceneSpectatorDrivenLeaderboard : OsuTestScene { [Cached(typeof(SpectatorStreamingClient))] - private TestSceneSpectator.TestSpectatorStreamingClient testSpectatorStreamingClient = new TestSceneSpectator.TestSpectatorStreamingClient(); + private TestMultiplayerStreaming streamingClient = new TestMultiplayerStreaming(16); // used just to show beatmap card for the time being. protected override bool UseOnlineAPI => true; @@ -27,7 +31,7 @@ namespace osu.Game.Tests.Visual.Gameplay { OsuScoreProcessor scoreProcessor; - testSpectatorStreamingClient.StartPlay(55); + streamingClient.Start(Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0); Children = new Drawable[] { @@ -38,37 +42,90 @@ namespace osu.Game.Tests.Visual.Gameplay Origin = Anchor.Centre, } }; + + Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value); + + var playable = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value); + + scoreProcessor.ApplyBeatmap(playable); }); - } - public class MultiplayerGameplayLeaderboard : GameplayLeaderboard - { - private readonly OsuScoreProcessor scoreProcessor; - - public MultiplayerGameplayLeaderboard(OsuScoreProcessor scoreProcessor) + [Test] + public void TestScoreUpdates() { - this.scoreProcessor = scoreProcessor; - - AddPlayer(new BindableDouble(), new GuestUser()); + AddRepeatStep("update state", () => streamingClient.RandomlyUpdateState(), 100); } - [Resolved] - private SpectatorStreamingClient streamingClient { get; set; } - - [Resolved] - private UserLookupCache userLookupCache { get; set; } - - [BackgroundDependencyLoader] - private void load() + public class TestMultiplayerStreaming : SpectatorStreamingClient { - Console.WriteLine("got here"); + public new BindableList PlayingUsers => (BindableList)base.PlayingUsers; - foreach (var user in streamingClient.PlayingUsers) + private readonly int totalUsers; + + public TestMultiplayerStreaming(int totalUsers) { - streamingClient.WatchUser(user); - var resolvedUser = userLookupCache.GetUserAsync(user).Result; - AddPlayer(new BindableDouble(), resolvedUser); + this.totalUsers = totalUsers; } + + public void Start(int beatmapId) + { + for (int i = 0; i < totalUsers; i++) + { + ((ISpectatorClient)this).UserBeganPlaying(i, new SpectatorState + { + BeatmapID = beatmapId, + RulesetID = 0, + }); + } + } + + private readonly Dictionary lastHeaders = new Dictionary(); + + public void RandomlyUpdateState() + { + foreach (var userId in PlayingUsers) + { + if (RNG.Next(0, 1) == 1) + continue; + + if (!lastHeaders.TryGetValue(userId, out var header)) + { + lastHeaders[userId] = header = new FrameHeader(new ScoreInfo + { + Statistics = new Dictionary(new[] + { + new KeyValuePair(HitResult.Miss, 0), + new KeyValuePair(HitResult.Meh, 0), + new KeyValuePair(HitResult.Great, 0) + }) + }); + } + + switch (RNG.Next(0, 3)) + { + case 0: + header.Combo = 0; + header.Statistics[HitResult.Miss]++; + break; + + case 1: + header.Combo++; + header.MaxCombo = Math.Max(header.MaxCombo, header.Combo); + header.Statistics[HitResult.Meh]++; + break; + + default: + header.Combo++; + header.MaxCombo = Math.Max(header.MaxCombo, header.Combo); + header.Statistics[HitResult.Great]++; + break; + } + + ((ISpectatorClient)this).UserSentFrames(userId, new FrameDataBundle(header, Array.Empty())); + } + } + + protected override Task Connect() => Task.CompletedTask; } } } diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 1d9fdd9ded..b3621f42c2 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -90,7 +89,8 @@ namespace osu.Game.Screens.Play.HUD if (LastHeader == null) return; - (Score.Value, Accuracy.Value) = processor.GetScoreAndAccuracy(mode, LastHeader.MaxCombo, LastHeader.Statistics.ToDictionary(s => s.Result, s => s.Count)); + (Score.Value, Accuracy.Value) = processor.GetScoreAndAccuracy(mode, LastHeader.MaxCombo, LastHeader.Statistics); + CurrentCombo.Value = LastHeader.Combo; } } From c1ba0f46425e756177e6c383d7f2e42b9d176c80 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 16 Dec 2020 15:53:05 +0900 Subject: [PATCH 037/328] Use a local lookup cache for better usernames --- .../TestSceneSpectatorDrivenLeaderboard.cs | 7 +++++ .../TestSceneCurrentlyPlayingDisplay.cs | 28 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs index e7ebf6e92c..647d57b5fe 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs @@ -9,12 +9,14 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Utils; +using osu.Game.Database; using osu.Game.Online.Spectator; using osu.Game.Replays.Legacy; using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Play.HUD; +using osu.Game.Tests.Visual.Online; namespace osu.Game.Tests.Visual.Gameplay { @@ -23,6 +25,9 @@ namespace osu.Game.Tests.Visual.Gameplay [Cached(typeof(SpectatorStreamingClient))] private TestMultiplayerStreaming streamingClient = new TestMultiplayerStreaming(16); + [Cached(typeof(UserLookupCache))] + private UserLookupCache lookupCache = new TestSceneCurrentlyPlayingDisplay.TestUserLookupCache(); + // used just to show beatmap card for the time being. protected override bool UseOnlineAPI => true; @@ -35,6 +40,8 @@ namespace osu.Game.Tests.Visual.Gameplay Children = new Drawable[] { + streamingClient, + lookupCache, scoreProcessor = new OsuScoreProcessor(), new MultiplayerGameplayLeaderboard(scoreProcessor) { diff --git a/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs index 7eba64f418..4f0ca67e64 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs @@ -69,8 +69,34 @@ namespace osu.Game.Tests.Visual.Online internal class TestUserLookupCache : UserLookupCache { + private static readonly string[] usernames = + { + "fieryrage", + "Kerensa", + "MillhioreF", + "Player01", + "smoogipoo", + "Ephemeral", + "BTMC", + "Cilvery", + "m980", + "HappyStick", + "LittleEndu", + "frenzibyte", + "Zallius", + "BanchoBot", + "rocketminer210", + "pishifat" + }; + + private int id; + protected override Task ComputeValueAsync(int lookup, CancellationToken token = default) - => Task.FromResult(new User { Username = "peppy", Id = 2 }); + => Task.FromResult(new User + { + Id = id++, + Username = usernames[id % usernames.Length], + }); } } } From 6e2131c164ad2a2d45ec7bab53d58deae3279de7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 16 Dec 2020 15:53:15 +0900 Subject: [PATCH 038/328] Don't track local user score in any special way --- osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index b3621f42c2..f8fce0825f 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -7,7 +7,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Configuration; using osu.Game.Database; -using osu.Game.Online.API; using osu.Game.Online.Spectator; using osu.Game.Rulesets.Scoring; @@ -24,8 +23,6 @@ namespace osu.Game.Screens.Play.HUD public MultiplayerGameplayLeaderboard(ScoreProcessor scoreProcessor) { this.scoreProcessor = scoreProcessor; - - AddPlayer(new BindableDouble(), new GuestUser()); } [Resolved] From 6bce587b599c04194589c8f3bd2716a44f886ea3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 16 Dec 2020 16:05:46 +0900 Subject: [PATCH 039/328] Pass users in via constructor and correctly unbind on disposal --- .../TestSceneSpectatorDrivenLeaderboard.cs | 3 +- .../HUD/MultiplayerGameplayLeaderboard.cs | 32 ++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs index 647d57b5fe..ffd02d247a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using NUnit.Framework; using osu.Framework.Allocation; @@ -43,7 +44,7 @@ namespace osu.Game.Tests.Visual.Gameplay streamingClient, lookupCache, scoreProcessor = new OsuScoreProcessor(), - new MultiplayerGameplayLeaderboard(scoreProcessor) + new MultiplayerGameplayLeaderboard(scoreProcessor, streamingClient.PlayingUsers.ToArray()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index f8fce0825f..93f258c507 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -16,13 +16,22 @@ namespace osu.Game.Screens.Play.HUD { private readonly ScoreProcessor scoreProcessor; + private readonly int[] userIds; + + private readonly Dictionary userScores = new Dictionary(); + /// /// Construct a new leaderboard. /// /// A score processor instance to handle score calculation for scores of users in the match. - public MultiplayerGameplayLeaderboard(ScoreProcessor scoreProcessor) + /// IDs of all users in this match. + public MultiplayerGameplayLeaderboard(ScoreProcessor scoreProcessor, int[] userIds) { + // todo: this will eventually need to be created per user to support different mod combinations. this.scoreProcessor = scoreProcessor; + + // todo: this will likely be passed in as User instances. + this.userIds = userIds; } [Resolved] @@ -31,8 +40,6 @@ namespace osu.Game.Screens.Play.HUD [Resolved] private UserLookupCache userLookupCache { get; set; } - private readonly Dictionary userScores = new Dictionary(); - private Bindable scoringMode; [BackgroundDependencyLoader] @@ -40,9 +47,11 @@ namespace osu.Game.Screens.Play.HUD { streamingClient.OnNewFrames += handleIncomingFrames; - foreach (var user in streamingClient.PlayingUsers) + foreach (var user in userIds) { streamingClient.WatchUser(user); + + // probably won't be required in the final implementation. var resolvedUser = userLookupCache.GetUserAsync(user).Result; var trackedUser = new TrackedUserData(); @@ -70,6 +79,21 @@ namespace osu.Game.Screens.Play.HUD } } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (streamingClient != null) + { + foreach (var user in userIds) + { + streamingClient.StopWatchingUser(user); + } + + streamingClient.OnNewFrames -= handleIncomingFrames; + } + } + private class TrackedUserData { public readonly BindableDouble Score = new BindableDouble(); From a01bb3d5a3a7ee33650de9b305addf61a1daa16f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 16 Dec 2020 16:08:44 +0900 Subject: [PATCH 040/328] Better limit bindable exposure of data class --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 2 +- .../Play/HUD/MultiplayerGameplayLeaderboard.cs | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index e53c56b390..3934a99221 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Play.HUD /// /// The bindable current score of the player. /// The player. - public void AddPlayer([NotNull] BindableDouble currentScore, [NotNull] User user) + public void AddPlayer([NotNull] IBindableNumber currentScore, [NotNull] User user) { var scoreItem = addScore(currentScore.Value, user); currentScore.ValueChanged += s => scoreItem.TotalScore = s.NewValue; diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 93f258c507..33bcf06aa7 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -96,11 +96,17 @@ namespace osu.Game.Screens.Play.HUD private class TrackedUserData { - public readonly BindableDouble Score = new BindableDouble(); + public IBindableNumber Score => score; - public readonly BindableDouble Accuracy = new BindableDouble(); + private readonly BindableDouble score = new BindableDouble(); - public readonly BindableInt CurrentCombo = new BindableInt(); + public IBindableNumber Accuracy => accuracy; + + private readonly BindableDouble accuracy = new BindableDouble(); + + public IBindableNumber CurrentCombo => currentCombo; + + private readonly BindableInt currentCombo = new BindableInt(); [CanBeNull] public FrameHeader LastHeader; @@ -110,9 +116,9 @@ namespace osu.Game.Screens.Play.HUD if (LastHeader == null) return; - (Score.Value, Accuracy.Value) = processor.GetScoreAndAccuracy(mode, LastHeader.MaxCombo, LastHeader.Statistics); + (score.Value, accuracy.Value) = processor.GetScoreAndAccuracy(mode, LastHeader.MaxCombo, LastHeader.Statistics); - CurrentCombo.Value = LastHeader.Combo; + currentCombo.Value = LastHeader.Combo; } } } From cda3bd2017180391786a46ef771c4b3e04dc4cb1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 16 Dec 2020 16:22:47 +0900 Subject: [PATCH 041/328] Rename test scene to match tested class name --- ...erboard.cs => TestSceneMultiplayerGameplayLeaderboard.cs} | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) rename osu.Game.Tests/Visual/Gameplay/{TestSceneSpectatorDrivenLeaderboard.cs => TestSceneMultiplayerGameplayLeaderboard.cs} (96%) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs similarity index 96% rename from osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs rename to osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs index ffd02d247a..78f9db57be 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorDrivenLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs @@ -21,7 +21,7 @@ using osu.Game.Tests.Visual.Online; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSpectatorDrivenLeaderboard : OsuTestScene + public class TestSceneMultiplayerGameplayLeaderboard : OsuTestScene { [Cached(typeof(SpectatorStreamingClient))] private TestMultiplayerStreaming streamingClient = new TestMultiplayerStreaming(16); @@ -29,9 +29,6 @@ namespace osu.Game.Tests.Visual.Gameplay [Cached(typeof(UserLookupCache))] private UserLookupCache lookupCache = new TestSceneCurrentlyPlayingDisplay.TestUserLookupCache(); - // used just to show beatmap card for the time being. - protected override bool UseOnlineAPI => true; - [SetUp] public void SetUp() => Schedule(() => { From 41d8b84bd7c7aff099593a034c8dd71ee1d0ae13 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Dec 2020 15:47:20 +0900 Subject: [PATCH 042/328] Revert MaxBaseScore to being a private field (no longe required to be public) --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index b4f29d7a6e..f4850d3325 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Scoring /// /// The maximum achievable base score. /// - public double MaxBaseScore { get; private set; } + private double maxBaseScore; private double rollingMaxBaseScore; private double baseScore; @@ -201,7 +201,7 @@ namespace osu.Game.Rulesets.Scoring private double getScore(ScoringMode mode) { return GetScore(mode, maxAchievableCombo, - MaxBaseScore > 0 ? baseScore / MaxBaseScore : 0, + maxBaseScore > 0 ? baseScore / maxBaseScore : 0, maxAchievableCombo > 0 ? (double)HighestCombo.Value / maxAchievableCombo : 1, scoreResultCounts); } @@ -252,7 +252,7 @@ namespace osu.Game.Rulesets.Scoring computedBaseScore += Judgement.ToNumericResult(pair.Key) * pair.Value; } - double accuracy = MaxBaseScore > 0 ? computedBaseScore / MaxBaseScore : 0; + double accuracy = maxBaseScore > 0 ? computedBaseScore / maxBaseScore : 0; double comboRatio = maxAchievableCombo > 0 ? (double)HighestCombo.Value / maxAchievableCombo : 1; double score = GetScore(mode, maxAchievableCombo, accuracy, comboRatio, scoreResultCounts); @@ -299,7 +299,7 @@ namespace osu.Game.Rulesets.Scoring if (storeResults) { maxAchievableCombo = HighestCombo.Value; - MaxBaseScore = baseScore; + maxBaseScore = baseScore; } baseScore = 0; From de9c21e7d19e265fbf776430d2708f860ed16bbf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Dec 2020 15:48:53 +0900 Subject: [PATCH 043/328] Tenatively mark leaderboard class as LongRunningLoad until final integration --- osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 33bcf06aa7..b2dc47ce61 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -12,6 +12,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.HUD { + [LongRunningLoad] public class MultiplayerGameplayLeaderboard : GameplayLeaderboard { private readonly ScoreProcessor scoreProcessor; From cc3dddf59fa432bad0fc2d36fe8810853223f48f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Dec 2020 16:02:06 +0900 Subject: [PATCH 044/328] Fix test scene crashing on second run of SetUp Also correctly support LongRunningLoad --- ...TestSceneMultiplayerGameplayLeaderboard.cs | 53 +++++++++++++------ 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs index 78f9db57be..0c8d8ca165 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs @@ -9,6 +9,8 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Database; using osu.Game.Online.Spectator; @@ -29,31 +31,48 @@ namespace osu.Game.Tests.Visual.Gameplay [Cached(typeof(UserLookupCache))] private UserLookupCache lookupCache = new TestSceneCurrentlyPlayingDisplay.TestUserLookupCache(); - [SetUp] - public void SetUp() => Schedule(() => + private MultiplayerGameplayLeaderboard leaderboard; + + protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both }; + + public TestSceneMultiplayerGameplayLeaderboard() { - OsuScoreProcessor scoreProcessor; - - streamingClient.Start(Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0); - - Children = new Drawable[] + base.Content.Children = new Drawable[] { streamingClient, lookupCache, - scoreProcessor = new OsuScoreProcessor(), - new MultiplayerGameplayLeaderboard(scoreProcessor, streamingClient.PlayingUsers.ToArray()) + Content + }; + } + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create leaderboard", () => + { + OsuScoreProcessor scoreProcessor; + Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value); + + var playable = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value); + + streamingClient.Start(Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0); + + Children = new Drawable[] + { + scoreProcessor = new OsuScoreProcessor(), + }; + + scoreProcessor.ApplyBeatmap(playable); + + LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(scoreProcessor, streamingClient.PlayingUsers.ToArray()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, - } - }; + }, Add); + }); - Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value); - - var playable = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value); - - scoreProcessor.ApplyBeatmap(playable); - }); + AddUntilStep("wait for load", () => leaderboard.IsLoaded); + } [Test] public void TestScoreUpdates() From f13683dc908e2f42b19d2a1fb6b05f808eb01b36 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Dec 2020 16:05:41 +0900 Subject: [PATCH 045/328] Correctly account for max combo of the input, rather than the global --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index f4850d3325..f5fb918ba3 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -253,7 +253,7 @@ namespace osu.Game.Rulesets.Scoring } double accuracy = maxBaseScore > 0 ? computedBaseScore / maxBaseScore : 0; - double comboRatio = maxAchievableCombo > 0 ? (double)HighestCombo.Value / maxAchievableCombo : 1; + double comboRatio = maxAchievableCombo > 0 ? (double)maxCombo / maxAchievableCombo : 1; double score = GetScore(mode, maxAchievableCombo, accuracy, comboRatio, scoreResultCounts); From 0faf3fdfd3fc4f96d137d1e8824398383e441ace Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 17 Dec 2020 15:12:32 +0300 Subject: [PATCH 046/328] Update gameplay leaderboard scores with the new design --- .../Gameplay/TestSceneGameplayLeaderboard.cs | 11 +- .../Screens/Play/HUD/GameplayLeaderboard.cs | 47 +-- .../Play/HUD/GameplayLeaderboardScore.cs | 268 ++++++++++++------ 3 files changed, 215 insertions(+), 111 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index df970c1c46..d0fdb3dd9c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -24,9 +24,8 @@ namespace osu.Game.Tests.Visual.Gameplay Add(leaderboard = new TestGameplayLeaderboard { Anchor = Anchor.Centre, - Origin = Anchor.Centre, + Origin = Anchor.TopCentre, Scale = new Vector2(2), - RelativeSizeAxes = Axes.X, }); } @@ -39,7 +38,7 @@ namespace osu.Game.Tests.Visual.Gameplay playerScore.Value = 1222333; }); - AddStep("add player user", () => leaderboard.AddPlayer(playerScore, new User { Username = "You" })); + AddStep("add player user", () => leaderboard.AddLocalUser(playerScore, new User { Username = "You" })); AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); } @@ -75,6 +74,12 @@ namespace osu.Game.Tests.Visual.Gameplay return scoreItem != null && scoreItem.ScorePosition == expectedPosition; } + + public void AddPlayer(BindableDouble totalScore, User user) => + base.AddPlayer(totalScore, new BindableDouble(1f), new BindableInt(1), user, false); + + public void AddLocalUser(BindableDouble totalScore, User user) => + base.AddPlayer(totalScore, new BindableDouble(1f), new BindableInt(1), user, true); } } } diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index e53c56b390..a2673e3097 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -15,8 +15,7 @@ namespace osu.Game.Screens.Play.HUD { public GameplayLeaderboard() { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; + AutoSizeAxes = Axes.Both; Direction = FillDirection.Vertical; @@ -29,32 +28,44 @@ namespace osu.Game.Screens.Play.HUD /// /// Adds a player to the leaderboard. /// - /// The bindable current score of the player. + /// A bindable of the player's total score. + /// A bindable of the player's accuracy. + /// A bindable of the player's current combo. /// The player. - public void AddPlayer([NotNull] BindableDouble currentScore, [NotNull] User user) + public void AddPlayer([NotNull] IBindableNumber totalScore, + [NotNull] IBindableNumber accuracy, + [NotNull] IBindableNumber combo, + [NotNull] User user) { - var scoreItem = addScore(currentScore.Value, user); - currentScore.ValueChanged += s => scoreItem.TotalScore = s.NewValue; + AddPlayer(totalScore, accuracy, combo, user, false); } - private GameplayLeaderboardScore addScore(double totalScore, User user) + /// + /// Adds a player to the leaderboard. + /// + /// A bindable of the player's total score. + /// A bindable of the player's accuracy. + /// A bindable of the player's current combo. + /// The player. + /// Whether the provided is the local user. + protected void AddPlayer([NotNull] IBindableNumber totalScore, + [NotNull] IBindableNumber accuracy, + [NotNull] IBindableNumber combo, + [NotNull] User user, bool localUser) => Schedule(() => { - var scoreItem = new GameplayLeaderboardScore + Add(new GameplayLeaderboardScore(user, localUser) { - User = user, - TotalScore = totalScore, - OnScoreChange = updateScores, - }; + TotalScore = { BindTarget = totalScore }, + Accuracy = { BindTarget = accuracy }, + Combo = { BindTarget = combo }, + }); - Add(scoreItem); - updateScores(); - - return scoreItem; - } + totalScore.BindValueChanged(_ => updateScores(), true); + }); private void updateScores() { - var orderedByScore = this.OrderByDescending(i => i.TotalScore).ToList(); + var orderedByScore = this.OrderByDescending(i => i.TotalScore.Value).ToList(); for (int i = 0; i < Count; i++) { diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 4c75f422c9..62ea5782e8 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -1,25 +1,35 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; +using System.Linq; using Humanizer; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Online.API; using osu.Game.Users; +using osu.Game.Utils; using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD { public class GameplayLeaderboardScore : CompositeDrawable { - private readonly OsuSpriteText positionText, positionSymbol, userString; - private readonly GlowingSpriteText scoreText; + private const float regular_width = 215f; + private const float extended_width = 235f; - public Action OnScoreChange; + private const float panel_height = 35f; + + private OsuSpriteText positionText, scoreText, accuracyText, comboText; + public readonly BindableDouble TotalScore = new BindableDouble(); + public readonly BindableDouble Accuracy = new BindableDouble(); + public readonly BindableInt Combo = new BindableInt(); private int? scorePosition; @@ -34,103 +44,181 @@ namespace osu.Game.Screens.Play.HUD positionText.Text = $"#{scorePosition.Value.ToMetric(decimals: scorePosition < 100000 ? 1 : 0)}"; positionText.FadeTo(scorePosition.HasValue ? 1 : 0); - positionSymbol.FadeTo(scorePosition.HasValue ? 1 : 0); } } - private double totalScore; + public User User { get; } - public double TotalScore + private readonly bool localUser; + + public GameplayLeaderboardScore(User user, bool localUser) { - get => totalScore; - set - { - totalScore = value; - scoreText.Text = totalScore.ToString("N0"); + User = user; + this.localUser = localUser; - OnScoreChange?.Invoke(); - } - } + AutoSizeAxes = Axes.Both; - private User user; - - public User User - { - get => user; - set - { - user = value; - userString.Text = user?.Username; - } - } - - public GameplayLeaderboardScore() - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - - InternalChild = new Container - { - Masking = true, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new FillFlowContainer - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Margin = new MarginPadding { Right = 2.5f }, - Spacing = new Vector2(2.5f), - Children = new[] - { - positionText = new OsuSpriteText - { - Alpha = 0, - Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), - }, - positionSymbol = new OsuSpriteText - { - Alpha = 0, - Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold), - Text = ">", - }, - } - }, - new FillFlowContainer - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopLeft, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Margin = new MarginPadding { Left = 2.5f }, - Spacing = new Vector2(2.5f), - Children = new Drawable[] - { - userString = new OsuSpriteText - { - Size = new Vector2(80, 16), - Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), - }, - scoreText = new GlowingSpriteText - { - GlowColour = Color4Extensions.FromHex(@"83ccfa"), - Font = OsuFont.Numeric.With(size: 14), - } - } - }, - }, - }; + Anchor = Anchor.TopRight; + Origin = Anchor.TopRight; } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(IAPIProvider api) { - positionText.Colour = colours.YellowLight; - positionSymbol.Colour = colours.Yellow; + const float panel_shear = 0.15f; + const float shear_width = panel_height * panel_shear; + + Color4 panelColour, textColour; + float panelWidth; + + if (localUser) + { + panelWidth = extended_width; + panelColour = Color4Extensions.FromHex("7fcc33"); + textColour = Color4.White; + } + else if (api.Friends.Any(f => User.Equals(f))) + { + panelWidth = extended_width; + panelColour = Color4Extensions.FromHex("ffd966"); + textColour = Color4Extensions.FromHex("2e576b"); + } + else + { + panelWidth = regular_width; + panelColour = Color4Extensions.FromHex("3399cc"); + textColour = Color4.White; + } + + InternalChildren = new Drawable[] + { + new Container + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Masking = true, + CornerRadius = 5f, + Shear = new Vector2(panel_shear, 0f), + Size = new Vector2(panelWidth, panel_height), + Child = new Box + { + Alpha = 0.5f, + RelativeSizeAxes = Axes.Both, + Colour = panelColour, + } + }, + new GridContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Size = new Vector2(regular_width, panel_height), + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.Absolute, 35f), + new Dimension(), + new Dimension(GridSizeMode.Absolute, 85f), + }, + Content = new[] + { + new Drawable[] + { + positionText = new OsuSpriteText + { + Padding = new MarginPadding { Right = shear_width / 2 }, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = textColour, + Font = OsuFont.Torus.With(size: 14, weight: FontWeight.Bold), + Shadow = false, + }, + new Container + { + Padding = new MarginPadding { Horizontal = shear_width / 3 }, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Container + { + Masking = true, + CornerRadius = 5f, + Shear = new Vector2(panel_shear, 0f), + RelativeSizeAxes = Axes.Both, + Children = new[] + { + new Box + { + Alpha = 0.5f, + RelativeSizeAxes = Axes.Both, + Colour = panelColour, + }, + } + }, + new OsuSpriteText + { + Padding = new MarginPadding { Left = shear_width }, + RelativeSizeAxes = Axes.X, + Width = 0.8f, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Colour = textColour, + Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold), + Text = User.Username, + Truncate = true, + Shadow = false, + } + } + }, + new Container + { + Padding = new MarginPadding { Top = 2f, Right = 17.5f, Bottom = 5f }, + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Colour = textColour, + Children = new Drawable[] + { + scoreText = new OsuSpriteText + { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + Spacing = new Vector2(0.5f, 0f), + Font = OsuFont.Torus.With(size: 16, weight: FontWeight.SemiBold), + Shadow = false, + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Children = new Drawable[] + { + accuracyText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold), + Shadow = false, + }, + comboText = new OsuSpriteText + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold), + Shadow = false, + }, + } + } + }, + } + } + } + } + }; + + TotalScore.BindValueChanged(v => scoreText.Text = v.NewValue.ToString("N0"), true); + Accuracy.BindValueChanged(v => accuracyText.Text = v.NewValue.FormatAccuracy(), true); + Combo.BindValueChanged(v => comboText.Text = $"{v.NewValue}x", true); } } } From a01ed1827a481fb8ac87aef1a1fda89ed5b33f4e Mon Sep 17 00:00:00 2001 From: Graham Johnson Date: Thu, 17 Dec 2020 19:34:16 -0500 Subject: [PATCH 047/328] Align the drag circles on the selction box in the editor to be on the center of the border --- .../Edit/Compose/Components/SelectionBox.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs index 347d9e3ba7..e4feceb987 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs @@ -235,6 +235,8 @@ namespace osu.Game.Screens.Edit.Compose.Components private void addDragHandle(Anchor anchor) => AddInternal(new SelectionBoxDragHandle { Anchor = anchor, + Y = getAdjustmentToCenterCircleOnBorder(anchor).Y, + X = getAdjustmentToCenterCircleOnBorder(anchor).X, HandleDrag = e => OnScale?.Invoke(e.Delta, anchor), OperationStarted = operationStarted, OperationEnded = operationEnded @@ -251,6 +253,45 @@ namespace osu.Game.Screens.Edit.Compose.Components return (endAngle - startAngle) * 180 / MathF.PI; } + /// + /// Adjust Drag circle to be centered on the center of the border instead of on the edge. + /// + /// The part of the rectangle to be adjusted. + private Vector2 getAdjustmentToCenterCircleOnBorder(Anchor anchor) + { + Vector2 adjustment = Vector2.Zero; + + switch (anchor) + { + case Anchor.TopLeft: + case Anchor.CentreLeft: + case Anchor.BottomLeft: + adjustment.X = BORDER_RADIUS / 2; + break; + case Anchor.TopRight: + case Anchor.CentreRight: + case Anchor.BottomRight: + adjustment.X = -BORDER_RADIUS / 2; + break; + } + + switch (anchor) + { + case Anchor.TopLeft: + case Anchor.TopCentre: + case Anchor.TopRight: + adjustment.Y = BORDER_RADIUS / 2; + break; + case Anchor.BottomLeft: + case Anchor.BottomCentre: + case Anchor.BottomRight: + adjustment.Y = -BORDER_RADIUS / 2; + break; + } + + return adjustment; + } + private void operationEnded() { if (--activeOperations == 0) From a8abefcd665adf869b97e45d89c0d85a6d979a7b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Dec 2020 03:34:33 +0300 Subject: [PATCH 048/328] Make GameplayLeaderboardScore a model class --- .../Gameplay/TestSceneGameplayLeaderboard.cs | 20 +++++---- .../Screens/Play/HUD/GameplayLeaderboard.cs | 41 ++----------------- .../Play/HUD/GameplayLeaderboardScore.cs | 5 ++- 3 files changed, 17 insertions(+), 49 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index d0fdb3dd9c..12bc918d45 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Gameplay playerScore.Value = 1222333; }); - AddStep("add player user", () => leaderboard.AddLocalUser(playerScore, new User { Username = "You" })); + AddStep("add local player", () => leaderboard.Add(createLeaderboardScore(playerScore, "You", true))); AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); } @@ -48,8 +48,8 @@ namespace osu.Game.Tests.Visual.Gameplay var player2Score = new BindableDouble(1234567); var player3Score = new BindableDouble(1111111); - AddStep("add player 2", () => leaderboard.AddPlayer(player2Score, new User { Username = "Player 2" })); - AddStep("add player 3", () => leaderboard.AddPlayer(player3Score, new User { Username = "Player 3" })); + AddStep("add player 2", () => leaderboard.Add(createLeaderboardScore(player2Score, "Player 2"))); + AddStep("add player 3", () => leaderboard.Add(createLeaderboardScore(player3Score, "Player 3"))); AddAssert("is player 2 position #1", () => leaderboard.CheckPositionByUsername("Player 2", 1)); AddAssert("is player position #2", () => leaderboard.CheckPositionByUsername("You", 2)); @@ -66,6 +66,14 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("is player 2 position #3", () => leaderboard.CheckPositionByUsername("Player 2", 3)); } + private static GameplayLeaderboardScore createLeaderboardScore(BindableDouble score, string username, bool localOrReplayPlayer = false) + { + return new GameplayLeaderboardScore(new User { Username = username }, localOrReplayPlayer) + { + TotalScore = { BindTarget = score }, + }; + } + private class TestGameplayLeaderboard : GameplayLeaderboard { public bool CheckPositionByUsername(string username, int? expectedPosition) @@ -74,12 +82,6 @@ namespace osu.Game.Tests.Visual.Gameplay return scoreItem != null && scoreItem.ScorePosition == expectedPosition; } - - public void AddPlayer(BindableDouble totalScore, User user) => - base.AddPlayer(totalScore, new BindableDouble(1f), new BindableInt(1), user, false); - - public void AddLocalUser(BindableDouble totalScore, User user) => - base.AddPlayer(totalScore, new BindableDouble(1f), new BindableInt(1), user, true); } } } diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index a2673e3097..573bf54b14 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -2,11 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using JetBrains.Annotations; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Users; using osuTK; namespace osu.Game.Screens.Play.HUD @@ -25,44 +22,12 @@ namespace osu.Game.Screens.Play.HUD LayoutEasing = Easing.OutQuint; } - /// - /// Adds a player to the leaderboard. - /// - /// A bindable of the player's total score. - /// A bindable of the player's accuracy. - /// A bindable of the player's current combo. - /// The player. - public void AddPlayer([NotNull] IBindableNumber totalScore, - [NotNull] IBindableNumber accuracy, - [NotNull] IBindableNumber combo, - [NotNull] User user) + public override void Add(GameplayLeaderboardScore drawable) { - AddPlayer(totalScore, accuracy, combo, user, false); + base.Add(drawable); + drawable?.TotalScore.BindValueChanged(_ => updateScores(), true); } - /// - /// Adds a player to the leaderboard. - /// - /// A bindable of the player's total score. - /// A bindable of the player's accuracy. - /// A bindable of the player's current combo. - /// The player. - /// Whether the provided is the local user. - protected void AddPlayer([NotNull] IBindableNumber totalScore, - [NotNull] IBindableNumber accuracy, - [NotNull] IBindableNumber combo, - [NotNull] User user, bool localUser) => Schedule(() => - { - Add(new GameplayLeaderboardScore(user, localUser) - { - TotalScore = { BindTarget = totalScore }, - Accuracy = { BindTarget = accuracy }, - Combo = { BindTarget = combo }, - }); - - totalScore.BindValueChanged(_ => updateScores(), true); - }); - private void updateScores() { var orderedByScore = this.OrderByDescending(i => i.TotalScore.Value).ToList(); diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 62ea5782e8..f94d6bd01f 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -27,8 +27,9 @@ namespace osu.Game.Screens.Play.HUD private const float panel_height = 35f; private OsuSpriteText positionText, scoreText, accuracyText, comboText; - public readonly BindableDouble TotalScore = new BindableDouble(); - public readonly BindableDouble Accuracy = new BindableDouble(); + + public readonly BindableDouble TotalScore = new BindableDouble(1000000); + public readonly BindableDouble Accuracy = new BindableDouble(1); public readonly BindableInt Combo = new BindableInt(); private int? scorePosition; From 92bf74ba29b3bc6c8ec645fe54d9c218d76ff6cf Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Dec 2020 03:37:24 +0300 Subject: [PATCH 049/328] localUser -> localOrReplayPlayer --- .../Screens/Play/HUD/GameplayLeaderboardScore.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index f94d6bd01f..285ed93341 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -50,12 +50,17 @@ namespace osu.Game.Screens.Play.HUD public User User { get; } - private readonly bool localUser; + private readonly bool localOrReplayPlayer; - public GameplayLeaderboardScore(User user, bool localUser) + /// + /// Creates a new . + /// + /// The score's player. + /// Whether the player is the local user or a replay player. + public GameplayLeaderboardScore(User user, bool localOrReplayPlayer) { User = user; - this.localUser = localUser; + this.localOrReplayPlayer = localOrReplayPlayer; AutoSizeAxes = Axes.Both; @@ -72,7 +77,7 @@ namespace osu.Game.Screens.Play.HUD Color4 panelColour, textColour; float panelWidth; - if (localUser) + if (localOrReplayPlayer) { panelWidth = extended_width; panelColour = Color4Extensions.FromHex("7fcc33"); From a0235a06e642319ce5108c21a3643e09bdc2031f Mon Sep 17 00:00:00 2001 From: Graham Johnson Date: Thu, 17 Dec 2020 19:40:21 -0500 Subject: [PATCH 050/328] update comment --- osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs index e4feceb987..4a0a925962 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs @@ -257,6 +257,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// Adjust Drag circle to be centered on the center of the border instead of on the edge. /// /// The part of the rectangle to be adjusted. + /// A 2d vector on how much to adjust the drag circle private Vector2 getAdjustmentToCenterCircleOnBorder(Anchor anchor) { Vector2 adjustment = Vector2.Zero; From 44f4ed4fd3001587378bae5ff90d4e4edfd5011a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 11:19:40 +0900 Subject: [PATCH 051/328] Fix spacing --- osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs index 4a0a925962..f50e599457 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs @@ -269,6 +269,7 @@ namespace osu.Game.Screens.Edit.Compose.Components case Anchor.BottomLeft: adjustment.X = BORDER_RADIUS / 2; break; + case Anchor.TopRight: case Anchor.CentreRight: case Anchor.BottomRight: @@ -283,6 +284,7 @@ namespace osu.Game.Screens.Edit.Compose.Components case Anchor.TopRight: adjustment.Y = BORDER_RADIUS / 2; break; + case Anchor.BottomLeft: case Anchor.BottomCentre: case Anchor.BottomRight: From 9079d33412207d9f3e18940d3d61c8d8f1a86137 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 11:20:21 +0900 Subject: [PATCH 052/328] X before Y for sanity --- osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs index f50e599457..8ccd4f71e9 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs @@ -235,8 +235,8 @@ namespace osu.Game.Screens.Edit.Compose.Components private void addDragHandle(Anchor anchor) => AddInternal(new SelectionBoxDragHandle { Anchor = anchor, - Y = getAdjustmentToCenterCircleOnBorder(anchor).Y, X = getAdjustmentToCenterCircleOnBorder(anchor).X, + Y = getAdjustmentToCenterCircleOnBorder(anchor).Y, HandleDrag = e => OnScale?.Invoke(e.Delta, anchor), OperationStarted = operationStarted, OperationEnded = operationEnded From 4af508235ee855cd0ac9be9d5aed56d416651f95 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 15:35:18 +0900 Subject: [PATCH 053/328] Rename long variable --- osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 285ed93341..1d548e8809 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -50,17 +50,17 @@ namespace osu.Game.Screens.Play.HUD public User User { get; } - private readonly bool localOrReplayPlayer; + private readonly bool trackedPlayer; /// /// Creates a new . /// /// The score's player. - /// Whether the player is the local user or a replay player. - public GameplayLeaderboardScore(User user, bool localOrReplayPlayer) + /// Whether the player is the local user or a replay player. + public GameplayLeaderboardScore(User user, bool trackedPlayer) { User = user; - this.localOrReplayPlayer = localOrReplayPlayer; + this.trackedPlayer = trackedPlayer; AutoSizeAxes = Axes.Both; @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Play.HUD Color4 panelColour, textColour; float panelWidth; - if (localOrReplayPlayer) + if (trackedPlayer) { panelWidth = extended_width; panelColour = Color4Extensions.FromHex("7fcc33"); From c80ecec0b418eedfa54931ef34d496984655cec1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 Dec 2020 15:36:24 +0900 Subject: [PATCH 054/328] Reorder methods --- osu.Game/Screens/Play/Player.cs | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index a54f9fc047..92c76ec2d2 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -531,29 +531,8 @@ namespace osu.Game.Screens.Play completionProgressDelegate = Schedule(GotoRanking); } - protected virtual ScoreInfo CreateScore() - { - var score = new ScoreInfo - { - Beatmap = Beatmap.Value.BeatmapInfo, - Ruleset = rulesetInfo, - Mods = Mods.Value.ToArray(), - }; - - if (DrawableRuleset.ReplayScore != null) - score.User = DrawableRuleset.ReplayScore.ScoreInfo?.User ?? new GuestUser(); - else - score.User = api.LocalUser.Value; - - ScoreProcessor.PopulateScore(score); - - return score; - } - protected override bool OnScroll(ScrollEvent e) => mouseWheelDisabled.Value && !GameplayClockContainer.IsPaused.Value; - protected virtual ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score, true); - #region Fail Logic protected FailOverlay FailOverlay { get; private set; } @@ -748,6 +727,25 @@ namespace osu.Game.Screens.Play return base.OnExiting(next); } + protected virtual ScoreInfo CreateScore() + { + var score = new ScoreInfo + { + Beatmap = Beatmap.Value.BeatmapInfo, + Ruleset = rulesetInfo, + Mods = Mods.Value.ToArray(), + }; + + if (DrawableRuleset.ReplayScore != null) + score.User = DrawableRuleset.ReplayScore.ScoreInfo?.User ?? new GuestUser(); + else + score.User = api.LocalUser.Value; + + ScoreProcessor.PopulateScore(score); + + return score; + } + protected virtual void GotoRanking() { if (DrawableRuleset.ReplayScore != null) @@ -781,6 +779,8 @@ namespace osu.Game.Screens.Play })); } + protected virtual ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score, true); + private void fadeOut(bool instant = false) { float fadeOutDuration = instant ? 0 : 250; From ceb2e4762d7c63efc3f9e044ae326447543c8528 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 16:20:42 +0900 Subject: [PATCH 055/328] Add test covering a more consistent spread of player scores --- .../Visual/Gameplay/TestSceneGameplayLeaderboard.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 12bc918d45..d596def98a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Testing; +using osu.Framework.Utils; using osu.Game.Screens.Play.HUD; using osu.Game.Users; using osuTK; @@ -66,6 +67,13 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("is player 2 position #3", () => leaderboard.CheckPositionByUsername("Player 2", 3)); } + [Test] + public void TestRandomScores() + { + int playerNumber = 1; + AddRepeatStep("add player with random score", () => leaderboard.Add(createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), $"Player {playerNumber++}")), 10); + } + private static GameplayLeaderboardScore createLeaderboardScore(BindableDouble score, string username, bool localOrReplayPlayer = false) { return new GameplayLeaderboardScore(new User { Username = username }, localOrReplayPlayer) From c84807ed5c0f09e47993666920d5374d561c5f9b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 16:20:54 +0900 Subject: [PATCH 056/328] Refactor implementation --- .../Play/HUD/GameplayLeaderboardScore.cs | 123 +++++++++++------- 1 file changed, 73 insertions(+), 50 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 1d548e8809..439210c944 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -11,7 +10,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Online.API; using osu.Game.Users; using osu.Game.Utils; using osuTK; @@ -26,7 +24,7 @@ namespace osu.Game.Screens.Play.HUD private const float panel_height = 35f; - private OsuSpriteText positionText, scoreText, accuracyText, comboText; + private OsuSpriteText positionText, scoreText, accuracyText, comboText, usernameText; public readonly BindableDouble TotalScore = new BindableDouble(1000000); public readonly BindableDouble Accuracy = new BindableDouble(1); @@ -45,6 +43,7 @@ namespace osu.Game.Screens.Play.HUD positionText.Text = $"#{scorePosition.Value.ToMetric(decimals: scorePosition < 100000 ? 1 : 0)}"; positionText.FadeTo(scorePosition.HasValue ? 1 : 0); + updateColour(); } } @@ -52,6 +51,9 @@ namespace osu.Game.Screens.Play.HUD private readonly bool trackedPlayer; + private Container mainFillContainer; + private Box centralFill; + /// /// Creates a new . /// @@ -62,62 +64,93 @@ namespace osu.Game.Screens.Play.HUD User = user; this.trackedPlayer = trackedPlayer; - AutoSizeAxes = Axes.Both; + AutoSizeAxes = Axes.X; + Height = panel_height; Anchor = Anchor.TopRight; Origin = Anchor.TopRight; } - [BackgroundDependencyLoader] - private void load(IAPIProvider api) + protected override void LoadComplete() { - const float panel_shear = 0.15f; - const float shear_width = panel_height * panel_shear; + base.LoadComplete(); - Color4 panelColour, textColour; - float panelWidth; + updateColour(); + FinishTransforms(true); + } - if (trackedPlayer) + private void updateColour() + { + if (scorePosition == 1) { - panelWidth = extended_width; + mainFillContainer.ResizeWidthTo(extended_width, 200, Easing.OutQuint); panelColour = Color4Extensions.FromHex("7fcc33"); textColour = Color4.White; } - else if (api.Friends.Any(f => User.Equals(f))) + else if (trackedPlayer) { - panelWidth = extended_width; + mainFillContainer.ResizeWidthTo(extended_width, 200, Easing.OutQuint); panelColour = Color4Extensions.FromHex("ffd966"); textColour = Color4Extensions.FromHex("2e576b"); } else { - panelWidth = regular_width; + mainFillContainer.ResizeWidthTo(regular_width, 200, Easing.OutQuint); panelColour = Color4Extensions.FromHex("3399cc"); textColour = Color4.White; } + } + + private Color4 panelColour + { + set + { + mainFillContainer.FadeColour(value, 200, Easing.OutQuint); + centralFill.FadeColour(value, 200, Easing.OutQuint); + } + } + + private Color4 textColour + { + set + { + scoreText.FadeColour(value, 200, Easing.OutQuint); + accuracyText.FadeColour(value, 200, Easing.OutQuint); + comboText.FadeColour(value, 200, Easing.OutQuint); + usernameText.FadeColour(value, 200, Easing.OutQuint); + positionText.FadeColour(value, 200, Easing.OutQuint); + } + } + + [BackgroundDependencyLoader] + private void load() + { + const float panel_shear = 0.15f; + const float shear_width = panel_height * panel_shear; InternalChildren = new Drawable[] { - new Container + mainFillContainer = new Container { + Width = regular_width, + RelativeSizeAxes = Axes.Y, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Masking = true, CornerRadius = 5f, Shear = new Vector2(panel_shear, 0f), - Size = new Vector2(panelWidth, panel_height), Child = new Box { Alpha = 0.5f, RelativeSizeAxes = Axes.Both, - Colour = panelColour, } }, new GridContainer { + Width = regular_width, + RelativeSizeAxes = Axes.Y, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Size = new Vector2(regular_width, panel_height), ColumnDimensions = new[] { new Dimension(GridSizeMode.Absolute, 35f), @@ -133,7 +166,7 @@ namespace osu.Game.Screens.Play.HUD Padding = new MarginPadding { Right = shear_width / 2 }, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Colour = textColour, + Colour = Color4.White, Font = OsuFont.Torus.With(size: 14, weight: FontWeight.Bold), Shadow = false, }, @@ -151,22 +184,22 @@ namespace osu.Game.Screens.Play.HUD RelativeSizeAxes = Axes.Both, Children = new[] { - new Box + centralFill = new Box { Alpha = 0.5f, RelativeSizeAxes = Axes.Both, - Colour = panelColour, + Colour = Color4Extensions.FromHex("3399cc"), }, } }, - new OsuSpriteText + usernameText = new OsuSpriteText { Padding = new MarginPadding { Left = shear_width }, RelativeSizeAxes = Axes.X, Width = 0.8f, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Colour = textColour, + Colour = Color4.White, Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold), Text = User.Username, Truncate = true, @@ -180,41 +213,31 @@ namespace osu.Game.Screens.Play.HUD RelativeSizeAxes = Axes.Both, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Colour = textColour, + Colour = Color4.White, Children = new Drawable[] { scoreText = new OsuSpriteText { - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft, - Spacing = new Vector2(0.5f, 0f), - Font = OsuFont.Torus.With(size: 16, weight: FontWeight.SemiBold), + Spacing = new Vector2(-1f, 0f), + Font = OsuFont.Torus.With(size: 16, weight: FontWeight.SemiBold, fixedWidth: true), Shadow = false, }, - new Container + accuracyText = new OsuSpriteText { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, - Children = new Drawable[] - { - accuracyText = new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold), - Shadow = false, - }, - comboText = new OsuSpriteText - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold), - Shadow = false, - }, - } - } + Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold, fixedWidth: true), + Spacing = new Vector2(-1f, 0f), + Shadow = false, + }, + comboText = new OsuSpriteText + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Spacing = new Vector2(-1f, 0f), + Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold, fixedWidth: true), + Shadow = false, + }, }, } } From 07a8ffa4aaefeeaa2da30aea60a94381826f7c13 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 16:50:25 +0900 Subject: [PATCH 057/328] Fix failing tests due to ignoring the lookup ID --- .../Visual/Online/TestSceneCurrentlyPlayingDisplay.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs index 4f0ca67e64..eaa881b02c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs @@ -89,13 +89,11 @@ namespace osu.Game.Tests.Visual.Online "pishifat" }; - private int id; - protected override Task ComputeValueAsync(int lookup, CancellationToken token = default) => Task.FromResult(new User { - Id = id++, - Username = usernames[id % usernames.Length], + Id = lookup++, + Username = usernames[lookup % usernames.Length], }); } } From 2db7433c0b11f5a90be103621af529a2c35f50e7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 Dec 2020 16:51:59 +0900 Subject: [PATCH 058/328] Refactor player score creation and submission process --- .../TestSceneCompletionCancellation.cs | 3 +- .../Screens/Multi/Play/TimeshiftPlayer.cs | 17 ++-- osu.Game/Screens/Play/Player.cs | 79 ++++++++++--------- osu.Game/Screens/Play/ReplayPlayer.cs | 13 +-- 4 files changed, 65 insertions(+), 47 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneCompletionCancellation.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneCompletionCancellation.cs index 6fd5511e5a..6e3b394057 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneCompletionCancellation.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneCompletionCancellation.cs @@ -10,6 +10,7 @@ using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Scoring; using osu.Game.Storyboards; using osuTK; @@ -117,7 +118,7 @@ namespace osu.Game.Tests.Visual.Gameplay { } - protected override void GotoRanking() + protected override void GotoRanking(ScoreInfo score) { GotoRankingInvoked = true; } diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs index 0efa9c5196..76e4a328e0 100644 --- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs +++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.Linq; using System.Threading; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Logging; @@ -95,19 +96,25 @@ namespace osu.Game.Screens.Multi.Play return new TimeshiftResultsScreen(score, roomId.Value.Value, playlistItem, true); } - protected override ScoreInfo CreateScore() + protected override Score CreateScore() { var score = base.CreateScore(); - score.TotalScore = (int)Math.Round(ScoreProcessor.GetStandardisedScore()); + score.ScoreInfo.TotalScore = (int)Math.Round(ScoreProcessor.GetStandardisedScore()); + return score; + } + + protected override async Task SubmitScore(Score score) + { + await base.SubmitScore(score); Debug.Assert(token != null); - var request = new SubmitRoomScoreRequest(token.Value, roomId.Value ?? 0, playlistItem.ID, score); - request.Success += s => score.OnlineScoreID = s.ID; + var request = new SubmitRoomScoreRequest(token.Value, roomId.Value ?? 0, playlistItem.ID, score.ScoreInfo); + request.Success += s => score.ScoreInfo.OnlineScoreID = s.ID; request.Failure += e => Logger.Error(e, "Failed to submit score"); api.Queue(request); - return score; + return score.ScoreInfo; } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 92c76ec2d2..3fb680b9c9 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading.Tasks; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Audio; @@ -527,8 +528,18 @@ namespace osu.Game.Screens.Play if (!showResults) return; - using (BeginDelayedSequence(RESULTS_DISPLAY_DELAY)) - completionProgressDelegate = Schedule(GotoRanking); + SubmitScore(CreateScore()).ContinueWith(t => Schedule(() => + { + using (BeginDelayedSequence(RESULTS_DISPLAY_DELAY)) + { + completionProgressDelegate = Schedule(() => + { + // screen may be in the exiting transition phase. + if (this.IsCurrentScreen()) + GotoRanking(t.Result); + }); + } + })); } protected override bool OnScroll(ScrollEvent e) => mouseWheelDisabled.Value && !GameplayClockContainer.IsPaused.Value; @@ -727,60 +738,56 @@ namespace osu.Game.Screens.Play return base.OnExiting(next); } - protected virtual ScoreInfo CreateScore() + protected virtual Score CreateScore() { - var score = new ScoreInfo + var score = new Score { - Beatmap = Beatmap.Value.BeatmapInfo, - Ruleset = rulesetInfo, - Mods = Mods.Value.ToArray(), + ScoreInfo = new ScoreInfo + { + Beatmap = Beatmap.Value.BeatmapInfo, + Ruleset = rulesetInfo, + Mods = Mods.Value.ToArray(), + } }; if (DrawableRuleset.ReplayScore != null) - score.User = DrawableRuleset.ReplayScore.ScoreInfo?.User ?? new GuestUser(); + { + score.ScoreInfo.User = DrawableRuleset.ReplayScore.ScoreInfo?.User ?? new GuestUser(); + score.Replay = DrawableRuleset.ReplayScore.Replay; + } else - score.User = api.LocalUser.Value; + { + score.ScoreInfo.User = api.LocalUser.Value; + if (recordingScore?.Replay.Frames.Count > 0) + score.Replay = recordingScore.Replay; + } - ScoreProcessor.PopulateScore(score); + ScoreProcessor.PopulateScore(score.ScoreInfo); return score; } - protected virtual void GotoRanking() + protected virtual async Task SubmitScore(Score score) { + // Replays are already populated and present in the game's database, so should not be re-imported. if (DrawableRuleset.ReplayScore != null) + return score.ScoreInfo; + + LegacyByteArrayReader replayReader; + + using (var stream = new MemoryStream()) { - // if a replay is present, we likely don't want to import into the local database. - this.Push(CreateResults(CreateScore())); - return; + new LegacyScoreEncoder(score, gameplayBeatmap.PlayableBeatmap).Encode(stream); + replayReader = new LegacyByteArrayReader(stream.ToArray(), "replay.osr"); } - LegacyByteArrayReader replayReader = null; - - var score = new Score { ScoreInfo = CreateScore() }; - - if (recordingScore?.Replay.Frames.Count > 0) - { - score.Replay = recordingScore.Replay; - - using (var stream = new MemoryStream()) - { - new LegacyScoreEncoder(score, gameplayBeatmap.PlayableBeatmap).Encode(stream); - replayReader = new LegacyByteArrayReader(stream.ToArray(), "replay.osr"); - } - } - - scoreManager.Import(score.ScoreInfo, replayReader) - .ContinueWith(imported => Schedule(() => - { - // screen may be in the exiting transition phase. - if (this.IsCurrentScreen()) - this.Push(CreateResults(imported.Result)); - })); + return await scoreManager.Import(score.ScoreInfo, replayReader); } protected virtual ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score, true); + protected virtual void GotoRanking(ScoreInfo score) => this.Push(CreateResults(score)); + private void fadeOut(bool instant = false) { float fadeOutDuration = instant ? 0 : 250; diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 294d116f51..390d1d1959 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Threading.Tasks; using osu.Framework.Input.Bindings; using osu.Game.Input.Bindings; using osu.Game.Scoring; @@ -26,18 +27,20 @@ namespace osu.Game.Screens.Play DrawableRuleset?.SetReplayScore(Score); } - protected override ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score, false); - - protected override ScoreInfo CreateScore() + protected override Score CreateScore() { var baseScore = base.CreateScore(); // Since the replay score doesn't contain statistics, we'll pass them through here. - Score.ScoreInfo.HitEvents = baseScore.HitEvents; + Score.ScoreInfo.HitEvents = baseScore.ScoreInfo.HitEvents; - return Score.ScoreInfo; + return Score; } + protected override Task SubmitScore(Score score) => Task.FromResult(score.ScoreInfo); + + protected override ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score, false); + public bool OnPressed(GlobalAction action) { switch (action) From 70cda680c0e868f41f27bd902cd2d0712d7ee4b6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 16:55:55 +0900 Subject: [PATCH 059/328] Update to match new implementation --- osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index b2dc47ce61..4d39d1a6b3 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Configuration; using osu.Game.Database; +using osu.Game.Online.API; using osu.Game.Online.Spectator; using osu.Game.Rulesets.Scoring; @@ -44,7 +45,7 @@ namespace osu.Game.Screens.Play.HUD private Bindable scoringMode; [BackgroundDependencyLoader] - private void load(OsuConfigManager config) + private void load(OsuConfigManager config, IAPIProvider api) { streamingClient.OnNewFrames += handleIncomingFrames; @@ -58,7 +59,7 @@ namespace osu.Game.Screens.Play.HUD var trackedUser = new TrackedUserData(); userScores[user] = trackedUser; - AddPlayer(trackedUser.Score, resolvedUser); + Add(new GameplayLeaderboardScore(resolvedUser, resolvedUser.Id == api.LocalUser.Value.Id)); //trackedUser.Score, resolvedUser); } scoringMode = config.GetBindable(OsuSetting.ScoreDisplayMode); From 97ff500b0daa28063188e699411b99017e2241bb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 Dec 2020 16:56:22 +0900 Subject: [PATCH 060/328] Make timeshift wait on score submission --- .../Screens/Multi/Play/TimeshiftPlayer.cs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs index 76e4a328e0..e106dc3a1c 100644 --- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs +++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs @@ -105,16 +105,29 @@ namespace osu.Game.Screens.Multi.Play protected override async Task SubmitScore(Score score) { - await base.SubmitScore(score); - Debug.Assert(token != null); + bool completed = false; var request = new SubmitRoomScoreRequest(token.Value, roomId.Value ?? 0, playlistItem.ID, score.ScoreInfo); - request.Success += s => score.ScoreInfo.OnlineScoreID = s.ID; - request.Failure += e => Logger.Error(e, "Failed to submit score"); + + request.Success += s => + { + score.ScoreInfo.OnlineScoreID = s.ID; + completed = true; + }; + + request.Failure += e => + { + Logger.Error(e, "Failed to submit score"); + completed = true; + }; + api.Queue(request); - return score.ScoreInfo; + while (!completed) + await Task.Delay(100); + + return await base.SubmitScore(score); } protected override void Dispose(bool isDisposing) From 157a72ec5deb0f5176fd171c57b9e61d30daa958 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 17:07:38 +0900 Subject: [PATCH 061/328] Revert previous player add flow via interface --- .../Gameplay/TestSceneGameplayLeaderboard.cs | 16 +++++++--------- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 16 +++++++++++++--- .../Screens/Play/HUD/GameplayLeaderboardScore.cs | 8 ++++---- osu.Game/Screens/Play/HUD/ILeaderboardScore.cs | 14 ++++++++++++++ 4 files changed, 38 insertions(+), 16 deletions(-) create mode 100644 osu.Game/Screens/Play/HUD/ILeaderboardScore.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index d596def98a..6e9375f69c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay playerScore.Value = 1222333; }); - AddStep("add local player", () => leaderboard.Add(createLeaderboardScore(playerScore, "You", true))); + AddStep("add local player", () => createLeaderboardScore(playerScore, "You", true)); AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); } @@ -49,8 +49,8 @@ namespace osu.Game.Tests.Visual.Gameplay var player2Score = new BindableDouble(1234567); var player3Score = new BindableDouble(1111111); - AddStep("add player 2", () => leaderboard.Add(createLeaderboardScore(player2Score, "Player 2"))); - AddStep("add player 3", () => leaderboard.Add(createLeaderboardScore(player3Score, "Player 3"))); + AddStep("add player 2", () => createLeaderboardScore(player2Score, "Player 2")); + AddStep("add player 3", () => createLeaderboardScore(player3Score, "Player 3")); AddAssert("is player 2 position #1", () => leaderboard.CheckPositionByUsername("Player 2", 1)); AddAssert("is player position #2", () => leaderboard.CheckPositionByUsername("You", 2)); @@ -71,15 +71,13 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestRandomScores() { int playerNumber = 1; - AddRepeatStep("add player with random score", () => leaderboard.Add(createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), $"Player {playerNumber++}")), 10); + AddRepeatStep("add player with random score", () => createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), $"Player {playerNumber++}"), 10); } - private static GameplayLeaderboardScore createLeaderboardScore(BindableDouble score, string username, bool localOrReplayPlayer = false) + private void createLeaderboardScore(BindableDouble score, string username, bool isTracked = false) { - return new GameplayLeaderboardScore(new User { Username = username }, localOrReplayPlayer) - { - TotalScore = { BindTarget = score }, - }; + var leaderboardScore = leaderboard.AddPlayer(new User { Username = username }, isTracked); + leaderboardScore.TotalScore.BindTo(score); } private class TestGameplayLeaderboard : GameplayLeaderboard diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 573bf54b14..e738477a80 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -1,9 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Users; using osuTK; namespace osu.Game.Screens.Play.HUD @@ -22,13 +24,21 @@ namespace osu.Game.Screens.Play.HUD LayoutEasing = Easing.OutQuint; } - public override void Add(GameplayLeaderboardScore drawable) + public ILeaderboardScore AddPlayer(User user, bool isTracked) { + var drawable = new GameplayLeaderboardScore(user, isTracked); base.Add(drawable); - drawable?.TotalScore.BindValueChanged(_ => updateScores(), true); + drawable.TotalScore.BindValueChanged(_ => Scheduler.AddOnce(sort), true); + + return drawable; } - private void updateScores() + public override void Add(GameplayLeaderboardScore drawable) + { + throw new InvalidOperationException($"Use {nameof(AddPlayer)} instead."); + } + + private void sort() { var orderedByScore = this.OrderByDescending(i => i.TotalScore.Value).ToList(); diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 439210c944..d4d7c69f6b 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD { - public class GameplayLeaderboardScore : CompositeDrawable + public class GameplayLeaderboardScore : CompositeDrawable, ILeaderboardScore { private const float regular_width = 215f; private const float extended_width = 235f; @@ -26,9 +26,9 @@ namespace osu.Game.Screens.Play.HUD private OsuSpriteText positionText, scoreText, accuracyText, comboText, usernameText; - public readonly BindableDouble TotalScore = new BindableDouble(1000000); - public readonly BindableDouble Accuracy = new BindableDouble(1); - public readonly BindableInt Combo = new BindableInt(); + public BindableDouble TotalScore { get; } = new BindableDouble(); + public BindableDouble Accuracy { get; } = new BindableDouble(1); + public BindableInt Combo { get; } = new BindableInt(); private int? scorePosition; diff --git a/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs b/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs new file mode 100644 index 0000000000..bc1a03c5aa --- /dev/null +++ b/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs @@ -0,0 +1,14 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; + +namespace osu.Game.Screens.Play.HUD +{ + public interface ILeaderboardScore + { + BindableDouble TotalScore { get; } + BindableDouble Accuracy { get; } + BindableInt Combo { get; } + } +} From cb3f89d0a5c73baa360413c9ef9cf08c8ea39617 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 17:13:51 +0900 Subject: [PATCH 062/328] Hook up with new leaderboard design --- osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 4d39d1a6b3..c96f496cd0 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -59,7 +59,11 @@ namespace osu.Game.Screens.Play.HUD var trackedUser = new TrackedUserData(); userScores[user] = trackedUser; - Add(new GameplayLeaderboardScore(resolvedUser, resolvedUser.Id == api.LocalUser.Value.Id)); //trackedUser.Score, resolvedUser); + var leaderboardScore = AddPlayer(resolvedUser, resolvedUser.Id == api.LocalUser.Value.Id); + + ((IBindable)leaderboardScore.Accuracy).BindTo(trackedUser.Accuracy); + ((IBindable)leaderboardScore.TotalScore).BindTo(trackedUser.Score); + ((IBindable)leaderboardScore.Combo).BindTo(trackedUser.CurrentCombo); } scoringMode = config.GetBindable(OsuSetting.ScoreDisplayMode); From bca4d83af794a587eb02eba41357ce6e841381c1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 17:07:38 +0900 Subject: [PATCH 063/328] Revert previous player add flow via interface --- .../Gameplay/TestSceneGameplayLeaderboard.cs | 16 +++++++--------- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 16 +++++++++++++--- .../Screens/Play/HUD/GameplayLeaderboardScore.cs | 8 ++++---- osu.Game/Screens/Play/HUD/ILeaderboardScore.cs | 14 ++++++++++++++ 4 files changed, 38 insertions(+), 16 deletions(-) create mode 100644 osu.Game/Screens/Play/HUD/ILeaderboardScore.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index d596def98a..6e9375f69c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay playerScore.Value = 1222333; }); - AddStep("add local player", () => leaderboard.Add(createLeaderboardScore(playerScore, "You", true))); + AddStep("add local player", () => createLeaderboardScore(playerScore, "You", true)); AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); } @@ -49,8 +49,8 @@ namespace osu.Game.Tests.Visual.Gameplay var player2Score = new BindableDouble(1234567); var player3Score = new BindableDouble(1111111); - AddStep("add player 2", () => leaderboard.Add(createLeaderboardScore(player2Score, "Player 2"))); - AddStep("add player 3", () => leaderboard.Add(createLeaderboardScore(player3Score, "Player 3"))); + AddStep("add player 2", () => createLeaderboardScore(player2Score, "Player 2")); + AddStep("add player 3", () => createLeaderboardScore(player3Score, "Player 3")); AddAssert("is player 2 position #1", () => leaderboard.CheckPositionByUsername("Player 2", 1)); AddAssert("is player position #2", () => leaderboard.CheckPositionByUsername("You", 2)); @@ -71,15 +71,13 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestRandomScores() { int playerNumber = 1; - AddRepeatStep("add player with random score", () => leaderboard.Add(createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), $"Player {playerNumber++}")), 10); + AddRepeatStep("add player with random score", () => createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), $"Player {playerNumber++}"), 10); } - private static GameplayLeaderboardScore createLeaderboardScore(BindableDouble score, string username, bool localOrReplayPlayer = false) + private void createLeaderboardScore(BindableDouble score, string username, bool isTracked = false) { - return new GameplayLeaderboardScore(new User { Username = username }, localOrReplayPlayer) - { - TotalScore = { BindTarget = score }, - }; + var leaderboardScore = leaderboard.AddPlayer(new User { Username = username }, isTracked); + leaderboardScore.TotalScore.BindTo(score); } private class TestGameplayLeaderboard : GameplayLeaderboard diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 573bf54b14..e738477a80 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -1,9 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Users; using osuTK; namespace osu.Game.Screens.Play.HUD @@ -22,13 +24,21 @@ namespace osu.Game.Screens.Play.HUD LayoutEasing = Easing.OutQuint; } - public override void Add(GameplayLeaderboardScore drawable) + public ILeaderboardScore AddPlayer(User user, bool isTracked) { + var drawable = new GameplayLeaderboardScore(user, isTracked); base.Add(drawable); - drawable?.TotalScore.BindValueChanged(_ => updateScores(), true); + drawable.TotalScore.BindValueChanged(_ => Scheduler.AddOnce(sort), true); + + return drawable; } - private void updateScores() + public override void Add(GameplayLeaderboardScore drawable) + { + throw new InvalidOperationException($"Use {nameof(AddPlayer)} instead."); + } + + private void sort() { var orderedByScore = this.OrderByDescending(i => i.TotalScore.Value).ToList(); diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 439210c944..d4d7c69f6b 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD { - public class GameplayLeaderboardScore : CompositeDrawable + public class GameplayLeaderboardScore : CompositeDrawable, ILeaderboardScore { private const float regular_width = 215f; private const float extended_width = 235f; @@ -26,9 +26,9 @@ namespace osu.Game.Screens.Play.HUD private OsuSpriteText positionText, scoreText, accuracyText, comboText, usernameText; - public readonly BindableDouble TotalScore = new BindableDouble(1000000); - public readonly BindableDouble Accuracy = new BindableDouble(1); - public readonly BindableInt Combo = new BindableInt(); + public BindableDouble TotalScore { get; } = new BindableDouble(); + public BindableDouble Accuracy { get; } = new BindableDouble(1); + public BindableInt Combo { get; } = new BindableInt(); private int? scorePosition; diff --git a/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs b/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs new file mode 100644 index 0000000000..bc1a03c5aa --- /dev/null +++ b/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs @@ -0,0 +1,14 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; + +namespace osu.Game.Screens.Play.HUD +{ + public interface ILeaderboardScore + { + BindableDouble TotalScore { get; } + BindableDouble Accuracy { get; } + BindableInt Combo { get; } + } +} From 4cf013c0058555776eea78a956203cfbbfe8d70a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 17:19:00 +0900 Subject: [PATCH 064/328] Fix animation replacing itself even when score position hasn't changed --- osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index d4d7c69f6b..086ac956e8 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -37,6 +37,9 @@ namespace osu.Game.Screens.Play.HUD get => scorePosition; set { + if (value == scorePosition) + return; + scorePosition = value; if (scorePosition.HasValue) From e82986b76328983a9c648ba274df7689115941af Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 17:19:36 +0900 Subject: [PATCH 065/328] Fix panel x positions getting weird duration relayouts Also adjust the transitions a bit to feel better. --- .../Play/HUD/GameplayLeaderboardScore.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 086ac956e8..77e6d320ae 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -67,11 +67,7 @@ namespace osu.Game.Screens.Play.HUD User = user; this.trackedPlayer = trackedPlayer; - AutoSizeAxes = Axes.X; - Height = panel_height; - - Anchor = Anchor.TopRight; - Origin = Anchor.TopRight; + Size = new Vector2(extended_width, panel_height); } protected override void LoadComplete() @@ -82,23 +78,25 @@ namespace osu.Game.Screens.Play.HUD FinishTransforms(true); } + private const double transition_duration = 500; + private void updateColour() { if (scorePosition == 1) { - mainFillContainer.ResizeWidthTo(extended_width, 200, Easing.OutQuint); + mainFillContainer.ResizeWidthTo(extended_width, transition_duration, Easing.OutElastic); panelColour = Color4Extensions.FromHex("7fcc33"); textColour = Color4.White; } else if (trackedPlayer) { - mainFillContainer.ResizeWidthTo(extended_width, 200, Easing.OutQuint); + mainFillContainer.ResizeWidthTo(extended_width, transition_duration, Easing.OutElastic); panelColour = Color4Extensions.FromHex("ffd966"); textColour = Color4Extensions.FromHex("2e576b"); } else { - mainFillContainer.ResizeWidthTo(regular_width, 200, Easing.OutQuint); + mainFillContainer.ResizeWidthTo(regular_width, transition_duration, Easing.OutElastic); panelColour = Color4Extensions.FromHex("3399cc"); textColour = Color4.White; } @@ -108,8 +106,8 @@ namespace osu.Game.Screens.Play.HUD { set { - mainFillContainer.FadeColour(value, 200, Easing.OutQuint); - centralFill.FadeColour(value, 200, Easing.OutQuint); + mainFillContainer.FadeColour(value, transition_duration, Easing.OutQuint); + centralFill.FadeColour(value, transition_duration, Easing.OutQuint); } } From 668536ce562eb30088b66602f294672b5be58d58 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 17:25:48 +0900 Subject: [PATCH 066/328] Fix vertical size potentially changing during relayout --- .../Gameplay/TestSceneGameplayLeaderboard.cs | 2 +- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 4 +++- .../Screens/Play/HUD/GameplayLeaderboardScore.cs | 15 ++++++++------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 6e9375f69c..ff15e1d2dc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.Gameplay Add(leaderboard = new TestGameplayLeaderboard { Anchor = Anchor.Centre, - Origin = Anchor.TopCentre, + Origin = Anchor.Centre, Scale = new Vector2(2), }); } diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index e738477a80..99319c0008 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -14,7 +14,7 @@ namespace osu.Game.Screens.Play.HUD { public GameplayLeaderboard() { - AutoSizeAxes = Axes.Both; + Width = GameplayLeaderboardScore.EXTENDED_WIDTH; Direction = FillDirection.Vertical; @@ -30,6 +30,8 @@ namespace osu.Game.Screens.Play.HUD base.Add(drawable); drawable.TotalScore.BindValueChanged(_ => Scheduler.AddOnce(sort), true); + Height = Count * (GameplayLeaderboardScore.PANEL_HEIGHT + Spacing.Y); + return drawable; } diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 77e6d320ae..242e7ff6b9 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -19,10 +19,11 @@ namespace osu.Game.Screens.Play.HUD { public class GameplayLeaderboardScore : CompositeDrawable, ILeaderboardScore { - private const float regular_width = 215f; - private const float extended_width = 235f; + public const float EXTENDED_WIDTH = 235f; - private const float panel_height = 35f; + private const float regular_width = 215f; + + public const float PANEL_HEIGHT = 35f; private OsuSpriteText positionText, scoreText, accuracyText, comboText, usernameText; @@ -67,7 +68,7 @@ namespace osu.Game.Screens.Play.HUD User = user; this.trackedPlayer = trackedPlayer; - Size = new Vector2(extended_width, panel_height); + Size = new Vector2(EXTENDED_WIDTH, PANEL_HEIGHT); } protected override void LoadComplete() @@ -84,13 +85,13 @@ namespace osu.Game.Screens.Play.HUD { if (scorePosition == 1) { - mainFillContainer.ResizeWidthTo(extended_width, transition_duration, Easing.OutElastic); + mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, transition_duration, Easing.OutElastic); panelColour = Color4Extensions.FromHex("7fcc33"); textColour = Color4.White; } else if (trackedPlayer) { - mainFillContainer.ResizeWidthTo(extended_width, transition_duration, Easing.OutElastic); + mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, transition_duration, Easing.OutElastic); panelColour = Color4Extensions.FromHex("ffd966"); textColour = Color4Extensions.FromHex("2e576b"); } @@ -127,7 +128,7 @@ namespace osu.Game.Screens.Play.HUD private void load() { const float panel_shear = 0.15f; - const float shear_width = panel_height * panel_shear; + const float shear_width = PANEL_HEIGHT * panel_shear; InternalChildren = new Drawable[] { From 615352c1e41a13c9dc189003aeb4ee2b8a3f95df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 17:30:11 +0900 Subject: [PATCH 067/328] Fix shear offset not being included in GameplayLeaderboard's own size --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 9 +++++++-- .../Screens/Play/HUD/GameplayLeaderboardScore.cs | 14 ++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 99319c0008..aa668cc4c8 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -14,7 +14,7 @@ namespace osu.Game.Screens.Play.HUD { public GameplayLeaderboard() { - Width = GameplayLeaderboardScore.EXTENDED_WIDTH; + Width = GameplayLeaderboardScore.EXTENDED_WIDTH + GameplayLeaderboardScore.SHEAR_WIDTH; Direction = FillDirection.Vertical; @@ -26,7 +26,12 @@ namespace osu.Game.Screens.Play.HUD public ILeaderboardScore AddPlayer(User user, bool isTracked) { - var drawable = new GameplayLeaderboardScore(user, isTracked); + var drawable = new GameplayLeaderboardScore(user, isTracked) + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }; + base.Add(drawable); drawable.TotalScore.BindValueChanged(_ => Scheduler.AddOnce(sort), true); diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 242e7ff6b9..5c4b4406cc 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -16,6 +16,7 @@ using osuTK; using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD + { public class GameplayLeaderboardScore : CompositeDrawable, ILeaderboardScore { @@ -25,6 +26,10 @@ namespace osu.Game.Screens.Play.HUD public const float PANEL_HEIGHT = 35f; + public const float SHEAR_WIDTH = PANEL_HEIGHT * panel_shear; + + private const float panel_shear = 0.15f; + private OsuSpriteText positionText, scoreText, accuracyText, comboText, usernameText; public BindableDouble TotalScore { get; } = new BindableDouble(); @@ -127,9 +132,6 @@ namespace osu.Game.Screens.Play.HUD [BackgroundDependencyLoader] private void load() { - const float panel_shear = 0.15f; - const float shear_width = PANEL_HEIGHT * panel_shear; - InternalChildren = new Drawable[] { mainFillContainer = new Container @@ -165,7 +167,7 @@ namespace osu.Game.Screens.Play.HUD { positionText = new OsuSpriteText { - Padding = new MarginPadding { Right = shear_width / 2 }, + Padding = new MarginPadding { Right = SHEAR_WIDTH / 2 }, Anchor = Anchor.Centre, Origin = Anchor.Centre, Colour = Color4.White, @@ -174,7 +176,7 @@ namespace osu.Game.Screens.Play.HUD }, new Container { - Padding = new MarginPadding { Horizontal = shear_width / 3 }, + Padding = new MarginPadding { Horizontal = SHEAR_WIDTH / 3 }, RelativeSizeAxes = Axes.Both, Children = new Drawable[] { @@ -196,7 +198,7 @@ namespace osu.Game.Screens.Play.HUD }, usernameText = new OsuSpriteText { - Padding = new MarginPadding { Left = shear_width }, + Padding = new MarginPadding { Left = SHEAR_WIDTH }, RelativeSizeAxes = Axes.X, Width = 0.8f, Anchor = Anchor.CentreLeft, From fdad5e86d3baa4adb991717e8408afae2da02bb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 17:33:18 +0900 Subject: [PATCH 068/328] Remove stray newline --- osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 5c4b4406cc..0b58cf76a2 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -16,7 +16,6 @@ using osuTK; using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD - { public class GameplayLeaderboardScore : CompositeDrawable, ILeaderboardScore { From 2958cab239027632f0b9b5c61109bbbd90bfa8b4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 Dec 2020 17:47:33 +0900 Subject: [PATCH 069/328] Remove GotoRanking --- .../TestSceneCompletionCancellation.cs | 13 ++++++++----- osu.Game/Screens/Play/Player.cs | 18 +++++++++++++++--- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneCompletionCancellation.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneCompletionCancellation.cs index 6e3b394057..4ee48fd853 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneCompletionCancellation.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneCompletionCancellation.cs @@ -11,6 +11,7 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Scoring; +using osu.Game.Screens.Ranking; using osu.Game.Storyboards; using osuTK; @@ -51,7 +52,7 @@ namespace osu.Game.Tests.Visual.Gameplay cancel(); complete(); - AddUntilStep("attempted to push ranking", () => ((FakeRankingPushPlayer)Player).GotoRankingInvoked); + AddUntilStep("attempted to push ranking", () => ((FakeRankingPushPlayer)Player).ResultsCreated); } /// @@ -85,7 +86,7 @@ namespace osu.Game.Tests.Visual.Gameplay { // wait to ensure there was no attempt of pushing the results screen. AddWaitStep("wait", resultsDisplayWaitCount); - AddAssert("no attempt to push ranking", () => !((FakeRankingPushPlayer)Player).GotoRankingInvoked); + AddAssert("no attempt to push ranking", () => !((FakeRankingPushPlayer)Player).ResultsCreated); } protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) @@ -111,16 +112,18 @@ namespace osu.Game.Tests.Visual.Gameplay public class FakeRankingPushPlayer : TestPlayer { - public bool GotoRankingInvoked; + public bool ResultsCreated { get; private set; } public FakeRankingPushPlayer() : base(true, true) { } - protected override void GotoRanking(ScoreInfo score) + protected override ResultsScreen CreateResults(ScoreInfo score) { - GotoRankingInvoked = true; + var results = base.CreateResults(score); + ResultsCreated = true; + return results; } } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 3fb680b9c9..cc5f32d300 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -536,7 +536,7 @@ namespace osu.Game.Screens.Play { // screen may be in the exiting transition phase. if (this.IsCurrentScreen()) - GotoRanking(t.Result); + this.Push(CreateResults(t.Result)); }); } })); @@ -738,6 +738,10 @@ namespace osu.Game.Screens.Play return base.OnExiting(next); } + /// + /// Creates the player's . + /// + /// The . protected virtual Score CreateScore() { var score = new Score @@ -767,6 +771,11 @@ namespace osu.Game.Screens.Play return score; } + /// + /// Submits the player's . + /// + /// The to submit. + /// The submitted score. protected virtual async Task SubmitScore(Score score) { // Replays are already populated and present in the game's database, so should not be re-imported. @@ -784,10 +793,13 @@ namespace osu.Game.Screens.Play return await scoreManager.Import(score.ScoreInfo, replayReader); } + /// + /// Creates the for a . + /// + /// The to be displayed in the results screen. + /// The . protected virtual ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score, true); - protected virtual void GotoRanking(ScoreInfo score) => this.Push(CreateResults(score)); - private void fadeOut(bool instant = false) { float fadeOutDuration = instant ? 0 : 250; From 1369b75a86b93cac21c22c0d4a9305b9864f9258 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 Dec 2020 17:48:42 +0900 Subject: [PATCH 070/328] Fix potential multiple submission --- osu.Game/Screens/Play/Player.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index cc5f32d300..94c595908e 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -502,6 +502,7 @@ namespace osu.Game.Screens.Play } private ScheduledDelegate completionProgressDelegate; + private Task scoreSubmissionTask; private void updateCompletionState(ValueChangedEvent completionState) { @@ -528,7 +529,8 @@ namespace osu.Game.Screens.Play if (!showResults) return; - SubmitScore(CreateScore()).ContinueWith(t => Schedule(() => + scoreSubmissionTask ??= SubmitScore(CreateScore()); + scoreSubmissionTask.ContinueWith(t => Schedule(() => { using (BeginDelayedSequence(RESULTS_DISPLAY_DELAY)) { From 8826d0155908750dfcc99df83bed41e548bb3391 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 Dec 2020 18:20:36 +0900 Subject: [PATCH 071/328] Create completion progress delegate immediately --- osu.Game/Screens/Play/Player.cs | 37 ++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 94c595908e..b79b8eeae8 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -529,21 +529,38 @@ namespace osu.Game.Screens.Play if (!showResults) return; - scoreSubmissionTask ??= SubmitScore(CreateScore()); - scoreSubmissionTask.ContinueWith(t => Schedule(() => + scoreSubmissionTask ??= Task.Run(async () => { - using (BeginDelayedSequence(RESULTS_DISPLAY_DELAY)) + var score = CreateScore(); + + try { - completionProgressDelegate = Schedule(() => - { - // screen may be in the exiting transition phase. - if (this.IsCurrentScreen()) - this.Push(CreateResults(t.Result)); - }); + return await SubmitScore(score); } - })); + catch (Exception ex) + { + Logger.Error(ex, "Score submission failed!"); + return score.ScoreInfo; + } + }); + + using (BeginDelayedSequence(RESULTS_DISPLAY_DELAY)) + scheduleCompletion(); } + private void scheduleCompletion() => completionProgressDelegate = Schedule(() => + { + if (!scoreSubmissionTask.IsCompleted) + { + scheduleCompletion(); + return; + } + + // screen may be in the exiting transition phase. + if (this.IsCurrentScreen()) + this.Push(CreateResults(scoreSubmissionTask.Result)); + }); + protected override bool OnScroll(ScrollEvent e) => mouseWheelDisabled.Value && !GameplayClockContainer.IsPaused.Value; #region Fail Logic From eccfc8ccd2b420c99cc2b30f868ad74e1214881a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 Dec 2020 18:31:49 +0900 Subject: [PATCH 072/328] Fix potential cross-reference access --- osu.Game/Screens/Play/Player.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index b79b8eeae8..c8f1980ab1 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -23,8 +23,10 @@ using osu.Game.Graphics.Containers; using osu.Game.IO.Archives; using osu.Game.Online.API; using osu.Game.Overlays; +using osu.Game.Replays; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; @@ -781,8 +783,7 @@ namespace osu.Game.Screens.Play else { score.ScoreInfo.User = api.LocalUser.Value; - if (recordingScore?.Replay.Frames.Count > 0) - score.Replay = recordingScore.Replay; + score.Replay = new Replay { Frames = recordingScore?.Replay.Frames.ToList() ?? new List() }; } ScoreProcessor.PopulateScore(score.ScoreInfo); From c9e75e790830816cd4b90525a71a625319e43bae Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Dec 2020 13:09:05 +0300 Subject: [PATCH 073/328] Add user avatar to leaderboard scores --- .../Play/HUD/GameplayLeaderboardScore.cs | 53 +++++++++++++++---- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 0b58cf76a2..9c444a6f1f 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Users; +using osu.Game.Users.Drawables; using osu.Game.Utils; using osuTK; using osuTK.Graphics; @@ -129,7 +130,7 @@ namespace osu.Game.Screens.Play.HUD } [BackgroundDependencyLoader] - private void load() + private void load(OsuColour colours) { InternalChildren = new Drawable[] { @@ -195,19 +196,51 @@ namespace osu.Game.Screens.Play.HUD }, } }, - usernameText = new OsuSpriteText + new FillFlowContainer { Padding = new MarginPadding { Left = SHEAR_WIDTH }, - RelativeSizeAxes = Axes.X, - Width = 0.8f, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Colour = Color4.White, - Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold), - Text = User.Username, - Truncate = true, - Shadow = false, - } + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(4f, 0f), + Children = new Drawable[] + { + new CircularContainer + { + Masking = true, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(25f), + Children = new Drawable[] + { + new Box + { + Name = "Placeholder while avatar loads", + Alpha = 0.3f, + RelativeSizeAxes = Axes.Both, + Colour = colours.Gray4, + }, + new UpdateableAvatar(User) + { + RelativeSizeAxes = Axes.Both, + }, + } + }, + usernameText = new OsuSpriteText + { + RelativeSizeAxes = Axes.X, + Width = 0.8f, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Colour = Color4.White, + Font = OsuFont.Torus.With(size: 14, weight: FontWeight.SemiBold), + Text = User.Username, + Truncate = true, + Shadow = false, + } + } + }, } }, new Container From 030dce55599422cc4017b5b754eab9a66cee623a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Dec 2020 13:09:50 +0300 Subject: [PATCH 074/328] Increase leaderboard score width a bit --- osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 9c444a6f1f..af3cb640bb 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -20,9 +20,9 @@ namespace osu.Game.Screens.Play.HUD { public class GameplayLeaderboardScore : CompositeDrawable, ILeaderboardScore { - public const float EXTENDED_WIDTH = 235f; + public const float EXTENDED_WIDTH = 255f; - private const float regular_width = 215f; + private const float regular_width = 235f; public const float PANEL_HEIGHT = 35f; From 228acf25a7d1b483841f4c6b1bbc4ab46c15aad6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Dec 2020 13:13:31 +0300 Subject: [PATCH 075/328] Add test case creating leaderboard scores with existing users --- .../Gameplay/TestSceneGameplayLeaderboard.cs | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index ff15e1d2dc..ca61672ef9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay playerScore.Value = 1222333; }); - AddStep("add local player", () => createLeaderboardScore(playerScore, "You", true)); + AddStep("add local player", () => createLeaderboardScore(playerScore, new User { Username = "You", Id = 3 }, true)); AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); } @@ -49,8 +49,8 @@ namespace osu.Game.Tests.Visual.Gameplay var player2Score = new BindableDouble(1234567); var player3Score = new BindableDouble(1111111); - AddStep("add player 2", () => createLeaderboardScore(player2Score, "Player 2")); - AddStep("add player 3", () => createLeaderboardScore(player3Score, "Player 3")); + AddStep("add player 2", () => createLeaderboardScore(player2Score, new User { Username = "Player 2" })); + AddStep("add player 3", () => createLeaderboardScore(player3Score, new User { Username = "Player 3" })); AddAssert("is player 2 position #1", () => leaderboard.CheckPositionByUsername("Player 2", 1)); AddAssert("is player position #2", () => leaderboard.CheckPositionByUsername("You", 2)); @@ -71,12 +71,23 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestRandomScores() { int playerNumber = 1; - AddRepeatStep("add player with random score", () => createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), $"Player {playerNumber++}"), 10); + AddRepeatStep("add player with random score", () => createRandomScore(new User { Username = $"Player {playerNumber++}" }), 10); } - private void createLeaderboardScore(BindableDouble score, string username, bool isTracked = false) + [Test] + public void TestExistingUsers() { - var leaderboardScore = leaderboard.AddPlayer(new User { Username = username }, isTracked); + AddStep("add peppy", () => createRandomScore(new User { Username = "peppy", Id = 2 })); + AddStep("add smoogipoo", () => createRandomScore(new User { Username = "smoogipoo", Id = 1040328 })); + AddStep("add flyte", () => createRandomScore(new User { Username = "flyte", Id = 3103765 })); + AddStep("add frenzibyte", () => createRandomScore(new User { Username = "frenzibyte", Id = 14210502 })); + } + + private void createRandomScore(User user) => createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), user); + + private void createLeaderboardScore(BindableDouble score, User user, bool isTracked = false) + { + var leaderboardScore = leaderboard.AddPlayer(user, isTracked); leaderboardScore.TotalScore.BindTo(score); } From 122250f454059d9adc231e982bd976e3795e1beb Mon Sep 17 00:00:00 2001 From: Graham Johnson Date: Fri, 18 Dec 2020 10:45:23 -0500 Subject: [PATCH 076/328] replace drag cirle function with dictionary --- .../Edit/Compose/Components/SelectionBox.cs | 61 ++++++------------- 1 file changed, 17 insertions(+), 44 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs index 8ccd4f71e9..85e86499be 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -235,13 +236,27 @@ namespace osu.Game.Screens.Edit.Compose.Components private void addDragHandle(Anchor anchor) => AddInternal(new SelectionBoxDragHandle { Anchor = anchor, - X = getAdjustmentToCenterCircleOnBorder(anchor).X, - Y = getAdjustmentToCenterCircleOnBorder(anchor).Y, + X = dragCircleAdjustments[anchor].X, + Y = dragCircleAdjustments[anchor].Y, HandleDrag = e => OnScale?.Invoke(e.Delta, anchor), OperationStarted = operationStarted, OperationEnded = operationEnded }); + /// + /// Adjust Drag circle to be centered on the center of the border instead of on the edge. + /// + private Dictionary dragCircleAdjustments = new Dictionary(){ + {Anchor.TopLeft, new Vector2(BORDER_RADIUS / 2)}, + {Anchor.CentreLeft, new Vector2(BORDER_RADIUS / 2, 0)}, + {Anchor.BottomLeft, new Vector2(BORDER_RADIUS / 2, -BORDER_RADIUS / 2)}, + {Anchor.TopCentre, new Vector2(0, BORDER_RADIUS / 2)}, + {Anchor.BottomCentre, new Vector2(0, -BORDER_RADIUS / 2)}, + {Anchor.TopRight, new Vector2(-BORDER_RADIUS / 2, BORDER_RADIUS / 2)}, + {Anchor.CentreRight, new Vector2(-BORDER_RADIUS / 2, 0)}, + {Anchor.BottomRight, new Vector2(-BORDER_RADIUS / 2)} + }; + private int activeOperations; private float convertDragEventToAngleOfRotation(DragEvent e) @@ -253,48 +268,6 @@ namespace osu.Game.Screens.Edit.Compose.Components return (endAngle - startAngle) * 180 / MathF.PI; } - /// - /// Adjust Drag circle to be centered on the center of the border instead of on the edge. - /// - /// The part of the rectangle to be adjusted. - /// A 2d vector on how much to adjust the drag circle - private Vector2 getAdjustmentToCenterCircleOnBorder(Anchor anchor) - { - Vector2 adjustment = Vector2.Zero; - - switch (anchor) - { - case Anchor.TopLeft: - case Anchor.CentreLeft: - case Anchor.BottomLeft: - adjustment.X = BORDER_RADIUS / 2; - break; - - case Anchor.TopRight: - case Anchor.CentreRight: - case Anchor.BottomRight: - adjustment.X = -BORDER_RADIUS / 2; - break; - } - - switch (anchor) - { - case Anchor.TopLeft: - case Anchor.TopCentre: - case Anchor.TopRight: - adjustment.Y = BORDER_RADIUS / 2; - break; - - case Anchor.BottomLeft: - case Anchor.BottomCentre: - case Anchor.BottomRight: - adjustment.Y = -BORDER_RADIUS / 2; - break; - } - - return adjustment; - } - private void operationEnded() { if (--activeOperations == 0) From 4494bb1eb5a587157f180f3ae14d078a0604194d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 00:15:41 +0900 Subject: [PATCH 077/328] Abstract RoomManager and Multiplayer --- .../Multiplayer/TestSceneMultiScreen.cs | 3 +- .../Navigation/TestSceneScreenNavigation.cs | 5 +- osu.Game/Screens/Menu/MainMenu.cs | 4 +- .../Components/ListingPollingComponent.cs | 68 ++++ .../Screens/Multi/Components/RoomManager.cs | 188 ++++++++++ .../Multi/Components/RoomPollingComponent.cs | 41 +++ .../Components/SelectionPollingComponent.cs | 69 ++++ osu.Game/Screens/Multi/IRoomManager.cs | 2 + osu.Game/Screens/Multi/Multiplayer.cs | 60 +--- osu.Game/Screens/Multi/RoomManager.cs | 337 ------------------ .../Multi/Timeshift/TimeshiftMultiplayer.cs | 48 +++ .../Multi/Timeshift/TimeshiftRoomManager.cs | 20 ++ 12 files changed, 460 insertions(+), 385 deletions(-) create mode 100644 osu.Game/Screens/Multi/Components/ListingPollingComponent.cs create mode 100644 osu.Game/Screens/Multi/Components/RoomManager.cs create mode 100644 osu.Game/Screens/Multi/Components/RoomPollingComponent.cs create mode 100644 osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs delete mode 100644 osu.Game/Screens/Multi/RoomManager.cs create mode 100644 osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs create mode 100644 osu.Game/Screens/Multi/Timeshift/TimeshiftRoomManager.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiScreen.cs index 3924b0333f..0390b995e1 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiScreen.cs @@ -4,6 +4,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Game.Overlays; +using osu.Game.Screens.Multi.Timeshift; namespace osu.Game.Tests.Visual.Multiplayer { @@ -17,7 +18,7 @@ namespace osu.Game.Tests.Visual.Multiplayer public TestSceneMultiScreen() { - Screens.Multi.Multiplayer multi = new Screens.Multi.Multiplayer(); + var multi = new TimeshiftMultiplayer(); AddStep("show", () => LoadScreen(multi)); AddUntilStep("wait for loaded", () => multi.IsLoaded); diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index d87854a7ea..43f97d8ace 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -11,6 +11,7 @@ using osu.Game.Beatmaps; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Overlays.Toolbar; +using osu.Game.Screens.Multi.Timeshift; using osu.Game.Screens.Play; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Options; @@ -107,14 +108,14 @@ namespace osu.Game.Tests.Visual.Navigation [Test] public void TestExitMultiWithEscape() { - PushAndConfirm(() => new Screens.Multi.Multiplayer()); + PushAndConfirm(() => new TimeshiftMultiplayer()); exitViaEscapeAndConfirm(); } [Test] public void TestExitMultiWithBackButton() { - PushAndConfirm(() => new Screens.Multi.Multiplayer()); + PushAndConfirm(() => new TimeshiftMultiplayer()); exitViaBackButtonAndConfirm(); } diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index c3ecd75963..b781c347f0 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -17,7 +17,7 @@ using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; -using osu.Game.Screens.Multi; +using osu.Game.Screens.Multi.Timeshift; using osu.Game.Screens.Select; namespace osu.Game.Screens.Menu @@ -104,7 +104,7 @@ namespace osu.Game.Screens.Menu this.Push(new Editor()); }, OnSolo = onSolo, - OnMulti = delegate { this.Push(new Multiplayer()); }, + OnMulti = delegate { this.Push(new TimeshiftMultiplayer()); }, OnExit = confirmAndExit, } } diff --git a/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs b/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs new file mode 100644 index 0000000000..e22f09779e --- /dev/null +++ b/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs @@ -0,0 +1,68 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Online.Multiplayer; +using osu.Game.Screens.Multi.Lounge.Components; + +namespace osu.Game.Screens.Multi.Components +{ + /// + /// A that polls for the lounge listing. + /// + public class ListingPollingComponent : RoomPollingComponent + { + [Resolved] + private Bindable currentFilter { get; set; } + + [Resolved] + private Bindable selectedRoom { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + currentFilter.BindValueChanged(_ => + { + if (IsLoaded) + PollImmediately(); + }); + } + + private GetRoomsRequest pollReq; + + protected override Task Poll() + { + if (!API.IsLoggedIn) + return base.Poll(); + + var tcs = new TaskCompletionSource(); + + pollReq?.Cancel(); + pollReq = new GetRoomsRequest(currentFilter.Value.Status, currentFilter.Value.Category); + + pollReq.Success += result => + { + for (int i = 0; i < result.Count; i++) + { + if (result[i].RoomID.Value == selectedRoom.Value?.RoomID.Value) + { + // The listing request always has less information than the opened room, so don't include it. + result[i] = selectedRoom.Value; + break; + } + } + + NotifyRoomsReceived(result); + tcs.SetResult(true); + }; + + pollReq.Failure += _ => tcs.SetResult(false); + + API.Queue(pollReq); + + return tcs.Task; + } + } +} diff --git a/osu.Game/Screens/Multi/Components/RoomManager.cs b/osu.Game/Screens/Multi/Components/RoomManager.cs new file mode 100644 index 0000000000..46941dc58e --- /dev/null +++ b/osu.Game/Screens/Multi/Components/RoomManager.cs @@ -0,0 +1,188 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Logging; +using osu.Game.Beatmaps; +using osu.Game.Online.API; +using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets; + +namespace osu.Game.Screens.Multi.Components +{ + public abstract class RoomManager : CompositeDrawable, IRoomManager + { + public event Action RoomsUpdated; + + private readonly BindableList rooms = new BindableList(); + + public Bindable InitialRoomsReceived { get; } = new Bindable(); + + public IBindableList Rooms => rooms; + + [Resolved] + private RulesetStore rulesets { get; set; } + + [Resolved] + private BeatmapManager beatmaps { get; set; } + + [Resolved] + private IAPIProvider api { get; set; } + + private Room joinedRoom; + + protected RoomManager() + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = CreatePollingComponents().Select(p => + { + p.InitialRoomsReceived.BindTo(InitialRoomsReceived); + p.RoomsReceived = onRoomsReceived; + return p; + }).ToList(); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + PartRoom(); + } + + public virtual void CreateRoom(Room room, Action onSuccess = null, Action onError = null) + { + room.Host.Value = api.LocalUser.Value; + + var req = new CreateRoomRequest(room); + + req.Success += result => + { + joinedRoom = room; + + update(room, result); + addRoom(room); + + RoomsUpdated?.Invoke(); + onSuccess?.Invoke(room); + }; + + req.Failure += exception => + { + if (req.Result != null) + onError?.Invoke(req.Result.Error); + else + Logger.Log($"Failed to create the room: {exception}", level: LogLevel.Important); + }; + + api.Queue(req); + } + + private JoinRoomRequest currentJoinRoomRequest; + + public virtual void JoinRoom(Room room, Action onSuccess = null, Action onError = null) + { + currentJoinRoomRequest?.Cancel(); + currentJoinRoomRequest = new JoinRoomRequest(room); + + currentJoinRoomRequest.Success += () => + { + joinedRoom = room; + onSuccess?.Invoke(room); + }; + + currentJoinRoomRequest.Failure += exception => + { + if (!(exception is OperationCanceledException)) + Logger.Log($"Failed to join room: {exception}", level: LogLevel.Important); + onError?.Invoke(exception.ToString()); + }; + + api.Queue(currentJoinRoomRequest); + } + + public void PartRoom() + { + currentJoinRoomRequest?.Cancel(); + + if (joinedRoom == null) + return; + + api.Queue(new PartRoomRequest(joinedRoom)); + joinedRoom = null; + } + + private readonly HashSet ignoredRooms = new HashSet(); + + private void onRoomsReceived(List received) + { + // Remove past matches + foreach (var r in rooms.ToList()) + { + if (received.All(e => e.RoomID.Value != r.RoomID.Value)) + rooms.Remove(r); + } + + for (int i = 0; i < received.Count; i++) + { + var room = received[i]; + + Debug.Assert(room.RoomID.Value != null); + + if (ignoredRooms.Contains(room.RoomID.Value.Value)) + continue; + + room.Position.Value = i; + + try + { + update(room, room); + addRoom(room); + } + catch (Exception ex) + { + Logger.Error(ex, $"Failed to update room: {room.Name.Value}."); + + ignoredRooms.Add(room.RoomID.Value.Value); + rooms.Remove(room); + } + } + + RoomsUpdated?.Invoke(); + } + + /// + /// Updates a local with a remote copy. + /// + /// The local to update. + /// The remote to update with. + private void update(Room local, Room remote) + { + foreach (var pi in remote.Playlist) + pi.MapObjects(beatmaps, rulesets); + + local.CopyFrom(remote); + } + + /// + /// Adds a to the list of available rooms. + /// + /// The to add. + private void addRoom(Room room) + { + var existing = rooms.FirstOrDefault(e => e.RoomID.Value == room.RoomID.Value); + if (existing == null) + rooms.Add(room); + else + existing.CopyFrom(room); + } + + protected abstract RoomPollingComponent[] CreatePollingComponents(); + } +} diff --git a/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs b/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs new file mode 100644 index 0000000000..5430d54644 --- /dev/null +++ b/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs @@ -0,0 +1,41 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Online; +using osu.Game.Online.API; +using osu.Game.Online.Multiplayer; + +namespace osu.Game.Screens.Multi.Components +{ + public abstract class RoomPollingComponent : PollingComponent + { + public Action> RoomsReceived; + + /// + /// The time in milliseconds to wait between polls. + /// Setting to zero stops all polling. + /// + public new readonly Bindable TimeBetweenPolls = new Bindable(); + + public IBindable InitialRoomsReceived => initialRoomsReceived; + private readonly Bindable initialRoomsReceived = new Bindable(); + + [Resolved] + protected IAPIProvider API { get; private set; } + + protected RoomPollingComponent() + { + TimeBetweenPolls.BindValueChanged(time => base.TimeBetweenPolls = time.NewValue); + } + + protected void NotifyRoomsReceived(List rooms) + { + initialRoomsReceived.Value = true; + RoomsReceived?.Invoke(rooms); + } + } +} diff --git a/osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs b/osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs new file mode 100644 index 0000000000..544d5b2388 --- /dev/null +++ b/osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs @@ -0,0 +1,69 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Online.Multiplayer; + +namespace osu.Game.Screens.Multi.Components +{ + /// + /// A that polls for the currently-selected room. + /// + public class SelectionPollingComponent : RoomPollingComponent + { + [Resolved] + private Bindable selectedRoom { get; set; } + + [Resolved] + private IRoomManager roomManager { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + selectedRoom.BindValueChanged(_ => + { + if (IsLoaded) + PollImmediately(); + }); + } + + private GetRoomRequest pollReq; + + protected override Task Poll() + { + if (!API.IsLoggedIn) + return base.Poll(); + + if (selectedRoom.Value?.RoomID.Value == null) + return base.Poll(); + + var tcs = new TaskCompletionSource(); + + pollReq?.Cancel(); + pollReq = new GetRoomRequest(selectedRoom.Value.RoomID.Value.Value); + + pollReq.Success += result => + { + var rooms = new List(roomManager.Rooms); + + int index = rooms.FindIndex(r => r.RoomID == result.RoomID); + if (index < 0) + return; + + rooms[index] = result; + + NotifyRoomsReceived(rooms); + tcs.SetResult(true); + }; + + pollReq.Failure += _ => tcs.SetResult(false); + + API.Queue(pollReq); + + return tcs.Task; + } + } +} diff --git a/osu.Game/Screens/Multi/IRoomManager.cs b/osu.Game/Screens/Multi/IRoomManager.cs index bf75843c3e..3d18edcd71 100644 --- a/osu.Game/Screens/Multi/IRoomManager.cs +++ b/osu.Game/Screens/Multi/IRoomManager.cs @@ -2,11 +2,13 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Online.Multiplayer; namespace osu.Game.Screens.Multi { + [Cached(typeof(IRoomManager))] public interface IRoomManager { /// diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index a323faeea1..5f61c5e635 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; @@ -30,7 +29,7 @@ using osuTK; namespace osu.Game.Screens.Multi { [Cached] - public class Multiplayer : OsuScreen + public abstract class Multiplayer : OsuScreen { public override bool CursorVisible => (screenStack.CurrentScreen as IMultiplayerSubScreen)?.CursorVisible ?? true; @@ -46,6 +45,9 @@ namespace osu.Game.Screens.Multi private readonly IBindable isIdle = new BindableBool(); + [Cached(Type = typeof(IRoomManager))] + protected IRoomManager RoomManager { get; private set; } + [Cached] private readonly Bindable selectedRoom = new Bindable(); @@ -55,9 +57,6 @@ namespace osu.Game.Screens.Multi [Resolved(CanBeNull = true)] private MusicController music { get; set; } - [Cached(Type = typeof(IRoomManager))] - private RoomManager roomManager; - [Resolved] private OsuGameBase game { get; set; } @@ -70,7 +69,7 @@ namespace osu.Game.Screens.Multi private readonly Drawable header; private readonly Drawable headerBackground; - public Multiplayer() + protected Multiplayer() { Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -82,7 +81,7 @@ namespace osu.Game.Screens.Multi InternalChild = waves = new MultiplayerWaveContainer { RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + Children = new[] { new Box { @@ -137,7 +136,7 @@ namespace osu.Game.Screens.Multi Origin = Anchor.TopRight, Action = () => CreateRoom() }, - roomManager = new RoomManager() + (Drawable)(RoomManager = CreateRoomManager()) } }; @@ -168,7 +167,7 @@ namespace osu.Game.Screens.Multi protected override void LoadComplete() { base.LoadComplete(); - isIdle.BindValueChanged(idle => updatePollingRate(idle.NewValue), true); + isIdle.BindValueChanged(idle => UpdatePollingRate(idle.NewValue), true); } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -178,36 +177,7 @@ namespace osu.Game.Screens.Multi return dependencies; } - private void updatePollingRate(bool idle) - { - if (!this.IsCurrentScreen()) - { - roomManager.TimeBetweenListingPolls = 0; - roomManager.TimeBetweenSelectionPolls = 0; - } - else - { - switch (screenStack.CurrentScreen) - { - case LoungeSubScreen _: - roomManager.TimeBetweenListingPolls = idle ? 120000 : 15000; - roomManager.TimeBetweenSelectionPolls = idle ? 120000 : 15000; - break; - - case MatchSubScreen _: - roomManager.TimeBetweenListingPolls = 0; - roomManager.TimeBetweenSelectionPolls = idle ? 30000 : 5000; - break; - - default: - roomManager.TimeBetweenListingPolls = 0; - roomManager.TimeBetweenSelectionPolls = 0; - break; - } - } - - Logger.Log($"Polling adjusted (listing: {roomManager.TimeBetweenListingPolls}, selection: {roomManager.TimeBetweenSelectionPolls})"); - } + protected abstract void UpdatePollingRate(bool isIdle); private void forcefullyExit() { @@ -241,7 +211,7 @@ namespace osu.Game.Screens.Multi beginHandlingTrack(); - updatePollingRate(isIdle.Value); + UpdatePollingRate(isIdle.Value); } public override void OnSuspending(IScreen next) @@ -251,12 +221,12 @@ namespace osu.Game.Screens.Multi endHandlingTrack(); - updatePollingRate(isIdle.Value); + UpdatePollingRate(isIdle.Value); } public override bool OnExiting(IScreen next) { - roomManager.PartRoom(); + RoomManager.PartRoom(); waves.Hide(); @@ -344,12 +314,14 @@ namespace osu.Game.Screens.Multi if (newScreen is IOsuScreen newOsuScreen) ((IBindable)Activity).BindTo(newOsuScreen.Activity); - updatePollingRate(isIdle.Value); + UpdatePollingRate(isIdle.Value); createButton.FadeTo(newScreen is LoungeSubScreen ? 1 : 0, 200); updateTrack(); } + protected IScreen CurrentSubScreen => screenStack.CurrentScreen; + private void updateTrack(ValueChangedEvent _ = null) { if (screenStack.CurrentScreen is MatchSubScreen) @@ -381,6 +353,8 @@ namespace osu.Game.Screens.Multi } } + protected abstract IRoomManager CreateRoomManager(); + private class MultiplayerWaveContainer : WaveContainer { protected override bool StartHidden => true; diff --git a/osu.Game/Screens/Multi/RoomManager.cs b/osu.Game/Screens/Multi/RoomManager.cs deleted file mode 100644 index fb0cf73bb9..0000000000 --- a/osu.Game/Screens/Multi/RoomManager.cs +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Logging; -using osu.Game.Beatmaps; -using osu.Game.Online; -using osu.Game.Online.API; -using osu.Game.Online.Multiplayer; -using osu.Game.Rulesets; -using osu.Game.Screens.Multi.Lounge.Components; - -namespace osu.Game.Screens.Multi -{ - public class RoomManager : CompositeDrawable, IRoomManager - { - public event Action RoomsUpdated; - - private readonly BindableList rooms = new BindableList(); - - public Bindable InitialRoomsReceived { get; } = new Bindable(); - - public IBindableList Rooms => rooms; - - public double TimeBetweenListingPolls - { - get => listingPollingComponent.TimeBetweenPolls; - set => listingPollingComponent.TimeBetweenPolls = value; - } - - public double TimeBetweenSelectionPolls - { - get => selectionPollingComponent.TimeBetweenPolls; - set => selectionPollingComponent.TimeBetweenPolls = value; - } - - [Resolved] - private RulesetStore rulesets { get; set; } - - [Resolved] - private BeatmapManager beatmaps { get; set; } - - [Resolved] - private IAPIProvider api { get; set; } - - [Resolved] - private Bindable selectedRoom { get; set; } - - private readonly ListingPollingComponent listingPollingComponent; - private readonly SelectionPollingComponent selectionPollingComponent; - - private Room joinedRoom; - - public RoomManager() - { - RelativeSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] - { - listingPollingComponent = new ListingPollingComponent - { - InitialRoomsReceived = { BindTarget = InitialRoomsReceived }, - RoomsReceived = onListingReceived - }, - selectionPollingComponent = new SelectionPollingComponent { RoomReceived = onSelectedRoomReceived } - }; - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - PartRoom(); - } - - public void CreateRoom(Room room, Action onSuccess = null, Action onError = null) - { - room.Host.Value = api.LocalUser.Value; - - var req = new CreateRoomRequest(room); - - req.Success += result => - { - joinedRoom = room; - - update(room, result); - addRoom(room); - - RoomsUpdated?.Invoke(); - onSuccess?.Invoke(room); - }; - - req.Failure += exception => - { - if (req.Result != null) - onError?.Invoke(req.Result.Error); - else - Logger.Log($"Failed to create the room: {exception}", level: LogLevel.Important); - }; - - api.Queue(req); - } - - private JoinRoomRequest currentJoinRoomRequest; - - public void JoinRoom(Room room, Action onSuccess = null, Action onError = null) - { - currentJoinRoomRequest?.Cancel(); - currentJoinRoomRequest = new JoinRoomRequest(room); - - currentJoinRoomRequest.Success += () => - { - joinedRoom = room; - onSuccess?.Invoke(room); - }; - - currentJoinRoomRequest.Failure += exception => - { - if (!(exception is OperationCanceledException)) - Logger.Log($"Failed to join room: {exception}", level: LogLevel.Important); - onError?.Invoke(exception.ToString()); - }; - - api.Queue(currentJoinRoomRequest); - } - - public void PartRoom() - { - currentJoinRoomRequest?.Cancel(); - - if (joinedRoom == null) - return; - - api.Queue(new PartRoomRequest(joinedRoom)); - joinedRoom = null; - } - - private readonly HashSet ignoredRooms = new HashSet(); - - /// - /// Invoked when the listing of all s is received from the server. - /// - /// The listing. - private void onListingReceived(List listing) - { - // Remove past matches - foreach (var r in rooms.ToList()) - { - if (listing.All(e => e.RoomID.Value != r.RoomID.Value)) - rooms.Remove(r); - } - - for (int i = 0; i < listing.Count; i++) - { - if (selectedRoom.Value?.RoomID?.Value == listing[i].RoomID.Value) - { - // The listing request contains less data than the selection request, so data from the selection request is always preferred while the room is selected. - continue; - } - - var room = listing[i]; - - Debug.Assert(room.RoomID.Value != null); - - if (ignoredRooms.Contains(room.RoomID.Value.Value)) - continue; - - room.Position.Value = i; - - try - { - update(room, room); - addRoom(room); - } - catch (Exception ex) - { - Logger.Error(ex, $"Failed to update room: {room.Name.Value}."); - - ignoredRooms.Add(room.RoomID.Value.Value); - rooms.Remove(room); - } - } - - RoomsUpdated?.Invoke(); - } - - /// - /// Invoked when a is received from the server. - /// - /// The received . - private void onSelectedRoomReceived(Room toUpdate) - { - foreach (var room in rooms) - { - if (room.RoomID.Value == toUpdate.RoomID.Value) - { - toUpdate.Position.Value = room.Position.Value; - update(room, toUpdate); - break; - } - } - } - - /// - /// Updates a local with a remote copy. - /// - /// The local to update. - /// The remote to update with. - private void update(Room local, Room remote) - { - foreach (var pi in remote.Playlist) - pi.MapObjects(beatmaps, rulesets); - - local.CopyFrom(remote); - } - - /// - /// Adds a to the list of available rooms. - /// - /// The to add. - private void addRoom(Room room) - { - var existing = rooms.FirstOrDefault(e => e.RoomID.Value == room.RoomID.Value); - if (existing == null) - rooms.Add(room); - else - existing.CopyFrom(room); - } - - private class SelectionPollingComponent : PollingComponent - { - public Action RoomReceived; - - [Resolved] - private IAPIProvider api { get; set; } - - [Resolved] - private Bindable selectedRoom { get; set; } - - [BackgroundDependencyLoader] - private void load() - { - selectedRoom.BindValueChanged(_ => - { - if (IsLoaded) - PollImmediately(); - }); - } - - private GetRoomRequest pollReq; - - protected override Task Poll() - { - if (!api.IsLoggedIn) - return base.Poll(); - - if (selectedRoom.Value?.RoomID.Value == null) - return base.Poll(); - - var tcs = new TaskCompletionSource(); - - pollReq?.Cancel(); - pollReq = new GetRoomRequest(selectedRoom.Value.RoomID.Value.Value); - - pollReq.Success += result => - { - RoomReceived?.Invoke(result); - tcs.SetResult(true); - }; - - pollReq.Failure += _ => tcs.SetResult(false); - - api.Queue(pollReq); - - return tcs.Task; - } - } - - private class ListingPollingComponent : PollingComponent - { - public Action> RoomsReceived; - - public readonly Bindable InitialRoomsReceived = new Bindable(); - - [Resolved] - private IAPIProvider api { get; set; } - - [Resolved] - private Bindable currentFilter { get; set; } - - [BackgroundDependencyLoader] - private void load() - { - currentFilter.BindValueChanged(_ => - { - InitialRoomsReceived.Value = false; - - if (IsLoaded) - PollImmediately(); - }); - } - - private GetRoomsRequest pollReq; - - protected override Task Poll() - { - if (!api.IsLoggedIn) - return base.Poll(); - - var tcs = new TaskCompletionSource(); - - pollReq?.Cancel(); - pollReq = new GetRoomsRequest(currentFilter.Value.Status, currentFilter.Value.Category); - - pollReq.Success += result => - { - InitialRoomsReceived.Value = true; - RoomsReceived?.Invoke(result); - tcs.SetResult(true); - }; - - pollReq.Failure += _ => tcs.SetResult(false); - - api.Queue(pollReq); - - return tcs.Task; - } - } - } -} diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs new file mode 100644 index 0000000000..1ff9c670a8 --- /dev/null +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs @@ -0,0 +1,48 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Logging; +using osu.Framework.Screens; +using osu.Game.Screens.Multi.Lounge; +using osu.Game.Screens.Multi.Match; + +namespace osu.Game.Screens.Multi.Timeshift +{ + public class TimeshiftMultiplayer : Multiplayer + { + protected override void UpdatePollingRate(bool isIdle) + { + var timeshiftManager = (TimeshiftRoomManager)RoomManager; + + if (!this.IsCurrentScreen()) + { + timeshiftManager.TimeBetweenListingPolls.Value = 0; + timeshiftManager.TimeBetweenSelectionPolls.Value = 0; + } + else + { + switch (CurrentSubScreen) + { + case LoungeSubScreen _: + timeshiftManager.TimeBetweenListingPolls.Value = isIdle ? 120000 : 15000; + timeshiftManager.TimeBetweenSelectionPolls.Value = isIdle ? 120000 : 15000; + break; + + case MatchSubScreen _: + timeshiftManager.TimeBetweenListingPolls.Value = 0; + timeshiftManager.TimeBetweenSelectionPolls.Value = isIdle ? 30000 : 5000; + break; + + default: + timeshiftManager.TimeBetweenListingPolls.Value = 0; + timeshiftManager.TimeBetweenSelectionPolls.Value = 0; + break; + } + } + + Logger.Log($"Polling adjusted (listing: {timeshiftManager.TimeBetweenListingPolls.Value}, selection: {timeshiftManager.TimeBetweenSelectionPolls.Value})"); + } + + protected override IRoomManager CreateRoomManager() => new TimeshiftRoomManager(); + } +} diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomManager.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomManager.cs new file mode 100644 index 0000000000..ba96721afc --- /dev/null +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomManager.cs @@ -0,0 +1,20 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Screens.Multi.Components; + +namespace osu.Game.Screens.Multi.Timeshift +{ + public class TimeshiftRoomManager : RoomManager + { + public readonly Bindable TimeBetweenListingPolls = new Bindable(); + public readonly Bindable TimeBetweenSelectionPolls = new Bindable(); + + protected override RoomPollingComponent[] CreatePollingComponents() => new RoomPollingComponent[] + { + new ListingPollingComponent { TimeBetweenPolls = { BindTarget = TimeBetweenListingPolls } }, + new SelectionPollingComponent { TimeBetweenPolls = { BindTarget = TimeBetweenSelectionPolls } } + }; + } +} From f4e9703deb20a7abdd303781a17c63e736951136 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 00:52:32 +0900 Subject: [PATCH 078/328] Fix incorrect comparison --- osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs b/osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs index 544d5b2388..37a190b5e0 100644 --- a/osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs +++ b/osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs @@ -49,7 +49,7 @@ namespace osu.Game.Screens.Multi.Components { var rooms = new List(roomManager.Rooms); - int index = rooms.FindIndex(r => r.RoomID == result.RoomID); + int index = rooms.FindIndex(r => r.RoomID.Value == result.RoomID.Value); if (index < 0) return; From ab9158c306c5b19c6f314967216ab4fe4915fd23 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 Dec 2020 20:50:54 +0900 Subject: [PATCH 079/328] Add a stateful multiplayer client --- .../StatefulMultiplayerClient.cs | 389 ++++++++++++++++++ 1 file changed, 389 insertions(+) create mode 100644 osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs new file mode 100644 index 0000000000..3e2f435524 --- /dev/null +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -0,0 +1,389 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Beatmaps; +using osu.Game.Database; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.RoomStatuses; +using osu.Game.Rulesets; +using osu.Game.Users; +using osu.Game.Utils; + +namespace osu.Game.Online.RealtimeMultiplayer +{ + public abstract class StatefulMultiplayerClient : Component, IMultiplayerClient, IMultiplayerRoomServer + { + /// + /// Invoked when any change occurs to the multiplayer room. + /// + public event Action? RoomChanged; + + /// + /// Invoked when the multiplayer server requests the current beatmap to be loaded into play. + /// + public event Action? LoadRequested; + + /// + /// Invoked when the multiplayer server requests gameplay to be started. + /// + public event Action? MatchStarted; + + /// + /// Invoked when the multiplayer server has finished collating results. + /// + public event Action? ResultsReady; + + /// + /// Whether the is currently connected. + /// + public abstract IBindable IsConnected { get; } + + /// + /// The joined . + /// + public MultiplayerRoom? Room { get; private set; } + + /// + /// The users currently in gameplay. + /// + public readonly BindableList PlayingUsers = new BindableList(); + + [Resolved] + private UserLookupCache userLookupCache { get; set; } = null!; + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + [Resolved] + private RulesetStore rulesets { get; set; } = null!; + + private Room? apiRoom; + private int playlistItemId; // Todo: THIS IS SUPER TEMPORARY!! + + /// + /// Joins the for a given API . + /// + /// The API . + public async Task JoinRoom(Room room) + { + Debug.Assert(Room == null); + Debug.Assert(room.RoomID.Value != null); + + apiRoom = room; + playlistItemId = room.Playlist.SingleOrDefault()?.ID ?? 0; + + Room = await JoinRoom(room.RoomID.Value.Value); + + Debug.Assert(Room != null); + + foreach (var user in Room.Users) + await PopulateUser(user); + + updateLocalRoomSettings(Room.Settings); + } + + /// + /// Joins the with a given ID. + /// + /// The room ID. + /// The joined . + protected abstract Task JoinRoom(long roomId); + + public virtual Task LeaveRoom() + { + if (Room == null) + return Task.CompletedTask; + + apiRoom = null; + Room = null; + + Schedule(() => RoomChanged?.Invoke()); + + return Task.CompletedTask; + } + + /// + /// Change the current settings. + /// + /// + /// A room must have been joined via for this to have any effect. + /// + /// The new room name, if any. + /// The new room playlist item, if any. + public void ChangeSettings(Optional name = default, Optional item = default) + { + if (Room == null) + return; + + // A dummy playlist item filled with the current room settings (except mods). + var existingPlaylistItem = new PlaylistItem + { + Beatmap = + { + Value = new BeatmapInfo + { + OnlineBeatmapID = Room.Settings.BeatmapID, + MD5Hash = Room.Settings.BeatmapChecksum + } + }, + RulesetID = Room.Settings.RulesetID + }; + + var newSettings = new MultiplayerRoomSettings + { + Name = name.GetOr(Room.Settings.Name), + BeatmapID = item.GetOr(existingPlaylistItem).BeatmapID, + BeatmapChecksum = item.GetOr(existingPlaylistItem).Beatmap.Value.MD5Hash, + RulesetID = item.GetOr(existingPlaylistItem).RulesetID, + Mods = item.HasValue ? item.Value!.RequiredMods.Select(m => new APIMod(m)).ToList() : Room.Settings.Mods + }; + + // Make sure there would be a meaningful change in settings. + if (newSettings.Equals(Room.Settings)) + return; + + ChangeSettings(newSettings); + } + + public abstract Task TransferHost(int userId); + + public abstract Task ChangeSettings(MultiplayerRoomSettings settings); + + public abstract Task ChangeState(MultiplayerUserState newState); + + public abstract Task StartMatch(); + + Task IMultiplayerClient.RoomStateChanged(MultiplayerRoomState state) + { + Schedule(() => + { + if (Room == null) + return; + + Debug.Assert(apiRoom != null); + + Room.State = state; + + switch (state) + { + case MultiplayerRoomState.Open: + apiRoom.Status.Value = new RoomStatusOpen(); + break; + + case MultiplayerRoomState.Playing: + apiRoom.Status.Value = new RoomStatusPlaying(); + break; + + case MultiplayerRoomState.Closed: + apiRoom.Status.Value = new RoomStatusEnded(); + break; + } + + RoomChanged?.Invoke(); + }); + + return Task.CompletedTask; + } + + async Task IMultiplayerClient.UserJoined(MultiplayerRoomUser user) + { + await PopulateUser(user); + + Schedule(() => + { + if (Room == null) + return; + + Room.Users.Add(user); + + RoomChanged?.Invoke(); + }); + } + + Task IMultiplayerClient.UserLeft(MultiplayerRoomUser user) + { + Schedule(() => + { + if (Room == null) + return; + + Room.Users.Remove(user); + PlayingUsers.Remove(user.UserID); + + RoomChanged?.Invoke(); + }); + + return Task.CompletedTask; + } + + Task IMultiplayerClient.HostChanged(int userId) + { + Schedule(() => + { + if (Room == null) + return; + + Debug.Assert(apiRoom != null); + + var user = Room.Users.FirstOrDefault(u => u.UserID == userId); + + Room.Host = user; + apiRoom.Host.Value = user?.User; + + RoomChanged?.Invoke(); + }); + + return Task.CompletedTask; + } + + Task IMultiplayerClient.SettingsChanged(MultiplayerRoomSettings newSettings) + { + updateLocalRoomSettings(newSettings); + return Task.CompletedTask; + } + + Task IMultiplayerClient.UserStateChanged(int userId, MultiplayerUserState state) + { + Schedule(() => + { + if (Room == null) + return; + + Room.Users.Single(u => u.UserID == userId).State = state; + + if (state != MultiplayerUserState.Playing) + PlayingUsers.Remove(userId); + + RoomChanged?.Invoke(); + }); + + return Task.CompletedTask; + } + + Task IMultiplayerClient.LoadRequested() + { + Schedule(() => + { + if (Room == null) + return; + + LoadRequested?.Invoke(); + }); + + return Task.CompletedTask; + } + + Task IMultiplayerClient.MatchStarted() + { + Debug.Assert(Room != null); + var players = Room.Users.Where(u => u.State == MultiplayerUserState.Playing).Select(u => u.UserID).ToList(); + + Schedule(() => + { + if (Room == null) + return; + + PlayingUsers.AddRange(players); + + MatchStarted?.Invoke(); + }); + + return Task.CompletedTask; + } + + Task IMultiplayerClient.ResultsReady() + { + Schedule(() => + { + if (Room == null) + return; + + ResultsReady?.Invoke(); + }); + + return Task.CompletedTask; + } + + /// + /// Populates the for a given . + /// + /// The to populate. + protected async Task PopulateUser(MultiplayerRoomUser multiplayerUser) => multiplayerUser.User ??= await userLookupCache.GetUserAsync(multiplayerUser.UserID); + + /// + /// Updates the local room settings with the given . + /// + /// + /// This updates both the joined and the respective API . + /// + /// The new to update from. + private void updateLocalRoomSettings(MultiplayerRoomSettings settings) + { + if (Room == null) + return; + + // Update a few instantaneously properties of the room. + Schedule(() => + { + if (Room == null) + return; + + Debug.Assert(apiRoom != null); + + Room.Settings = settings; + apiRoom.Name.Value = Room.Settings.Name; + + // The playlist update is delayed until an online beatmap lookup (below) succeeds. + // In-order for the client to not display an outdated beatmap, the playlist is forcefully cleared here. + apiRoom.Playlist.Clear(); + + RoomChanged?.Invoke(); + }); + + var req = new GetBeatmapSetRequest(settings.BeatmapID, BeatmapSetLookupType.BeatmapId); + req.Success += res => + { + var beatmapSet = res.ToBeatmapSet(rulesets); + + var beatmap = beatmapSet.Beatmaps.Single(b => b.OnlineBeatmapID == settings.BeatmapID); + beatmap.MD5Hash = settings.BeatmapChecksum; + + var ruleset = rulesets.GetRuleset(settings.RulesetID); + var mods = settings.Mods.Select(m => m.ToMod(ruleset.CreateInstance())); + + PlaylistItem playlistItem = new PlaylistItem + { + ID = playlistItemId, + Beatmap = { Value = beatmap }, + Ruleset = { Value = ruleset }, + }; + + playlistItem.RequiredMods.AddRange(mods); + + Schedule(() => + { + if (Room == null || !Room.Settings.Equals(settings)) + return; + + Debug.Assert(apiRoom != null); + + apiRoom.Playlist.Clear(); // Clearing should be unnecessary, but here for sanity. + apiRoom.Playlist.Add(playlistItem); + }); + }; + + api.Queue(req); + } + } +} From 9ceb090f04d682f583fdc2d06fe1462f12a9c8ec Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 00:17:50 +0900 Subject: [PATCH 080/328] Fix ambiguous reference --- .../Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index 3e2f435524..60960f4929 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -117,7 +117,7 @@ namespace osu.Game.Online.RealtimeMultiplayer /// Change the current settings. /// /// - /// A room must have been joined via for this to have any effect. + /// A room must be joined for this to have any effect. /// /// The new room name, if any. /// The new room playlist item, if any. From cf2340cafb8b7ce964935a410f3bd3af49041458 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 00:18:41 +0900 Subject: [PATCH 081/328] Add a realtime room manager --- .../RealtimeRoomManager.cs | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs new file mode 100644 index 0000000000..a86e924c85 --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -0,0 +1,45 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Logging; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Screens.Multi.Components; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer +{ + public class RealtimeRoomManager : RoomManager + { + [Resolved] + private StatefulMultiplayerClient multiplayerClient { get; set; } + + public override void CreateRoom(Room room, Action onSuccess = null, Action onError = null) + => base.CreateRoom(room, r => joinMultiplayerRoom(r, onSuccess), onError); + + public override void JoinRoom(Room room, Action onSuccess = null, Action onError = null) + => base.JoinRoom(room, r => joinMultiplayerRoom(r, onSuccess), onError); + + private void joinMultiplayerRoom(Room room, Action onSuccess = null) + { + Debug.Assert(room.RoomID.Value != null); + + var joinTask = multiplayerClient.JoinRoom(room); + joinTask.ContinueWith(_ => onSuccess?.Invoke(room)); + joinTask.ContinueWith(t => + { + PartRoom(); + if (t.Exception != null) + Logger.Error(t.Exception, "Failed to join multiplayer room."); + }, TaskContinuationOptions.NotOnRanToCompletion); + } + + protected override RoomPollingComponent[] CreatePollingComponents() => new RoomPollingComponent[] + { + new ListingPollingComponent() + }; + } +} From a6520d3d446230cb3c0ef49aa15cdf45ba8b2232 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 01:01:09 +0900 Subject: [PATCH 082/328] Clear rooms and poll only when connected to multiplayer server --- .../Screens/Multi/Components/RoomManager.cs | 6 ++ .../RealtimeRoomManager.cs | 64 ++++++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/Components/RoomManager.cs b/osu.Game/Screens/Multi/Components/RoomManager.cs index 46941dc58e..d92427680e 100644 --- a/osu.Game/Screens/Multi/Components/RoomManager.cs +++ b/osu.Game/Screens/Multi/Components/RoomManager.cs @@ -157,6 +157,12 @@ namespace osu.Game.Screens.Multi.Components RoomsUpdated?.Invoke(); } + protected void ClearRooms() + { + rooms.Clear(); + InitialRoomsReceived.Value = false; + } + /// /// Updates a local with a remote copy. /// diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index a86e924c85..62ea5d5512 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.Threading.Tasks; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; @@ -17,6 +18,22 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer [Resolved] private StatefulMultiplayerClient multiplayerClient { get; set; } + public readonly Bindable TimeBetweenListingPolls = new Bindable(); + public readonly Bindable TimeBetweenSelectionPolls = new Bindable(); + private readonly IBindable isConnected = new Bindable(); + + protected override void LoadComplete() + { + base.LoadComplete(); + + isConnected.BindTo(multiplayerClient.IsConnected); + isConnected.BindValueChanged(connected => Schedule(() => + { + if (!connected.NewValue) + ClearRooms(); + })); + } + public override void CreateRoom(Room room, Action onSuccess = null, Action onError = null) => base.CreateRoom(room, r => joinMultiplayerRoom(r, onSuccess), onError); @@ -39,7 +56,52 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer protected override RoomPollingComponent[] CreatePollingComponents() => new RoomPollingComponent[] { - new ListingPollingComponent() + new RealtimeListingPollingComponent + { + TimeBetweenPolls = { BindTarget = TimeBetweenListingPolls }, + AllowPolling = { BindTarget = isConnected } + }, + new RealtimeSelectionPollingComponent + { + TimeBetweenPolls = { BindTarget = TimeBetweenSelectionPolls }, + AllowPolling = { BindTarget = isConnected } + } }; + + private class RealtimeListingPollingComponent : ListingPollingComponent + { + public readonly IBindable AllowPolling = new Bindable(); + + protected override void LoadComplete() + { + base.LoadComplete(); + + AllowPolling.BindValueChanged(_ => + { + if (IsLoaded) + PollImmediately(); + }); + } + + protected override Task Poll() => !AllowPolling.Value ? Task.CompletedTask : base.Poll(); + } + + private class RealtimeSelectionPollingComponent : SelectionPollingComponent + { + public readonly IBindable AllowPolling = new Bindable(); + + protected override void LoadComplete() + { + base.LoadComplete(); + + AllowPolling.BindValueChanged(_ => + { + if (IsLoaded) + PollImmediately(); + }); + } + + protected override Task Poll() => !AllowPolling.Value ? Task.CompletedTask : base.Poll(); + } } } From 1e2163f55e0378604ebe2f083a84b1271a8e7f4d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 01:14:50 +0900 Subject: [PATCH 083/328] Add a testable realtime multiplayer client --- .../TestRealtimeMultiplayerClient.cs | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs new file mode 100644 index 0000000000..2a90f1e744 --- /dev/null +++ b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs @@ -0,0 +1,114 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Online.API; +using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual.RealtimeMultiplayer +{ + public class TestRealtimeMultiplayerClient : StatefulMultiplayerClient + { + public override IBindable IsConnected { get; } = new Bindable(true); + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + public void AddUser(User user) => ((IMultiplayerClient)this).UserJoined(new MultiplayerRoomUser(user.Id) { User = user }); + + public void RemoveUser(User user) + { + Debug.Assert(Room != null); + ((IMultiplayerClient)this).UserLeft(Room.Users.Single(u => u.User == user)); + + Schedule(() => + { + if (Room.Users.Any()) + TransferHost(Room.Users.First().UserID); + }); + } + + public void ChangeUserState(int userId, MultiplayerUserState newState) + { + Debug.Assert(Room != null); + + ((IMultiplayerClient)this).UserStateChanged(userId, newState); + + Schedule(() => + { + switch (newState) + { + case MultiplayerUserState.Loaded: + if (Room.Users.All(u => u.State != MultiplayerUserState.WaitingForLoad)) + { + foreach (var u in Room.Users.Where(u => u.State == MultiplayerUserState.Loaded)) + ChangeUserState(u.UserID, MultiplayerUserState.Playing); + + ((IMultiplayerClient)this).MatchStarted(); + } + + break; + + case MultiplayerUserState.FinishedPlay: + if (Room.Users.All(u => u.State != MultiplayerUserState.Playing)) + { + foreach (var u in Room.Users.Where(u => u.State == MultiplayerUserState.FinishedPlay)) + ChangeUserState(u.UserID, MultiplayerUserState.Results); + + ((IMultiplayerClient)this).ResultsReady(); + } + + break; + } + }); + } + + protected override Task JoinRoom(long roomId) + { + var user = new MultiplayerRoomUser(api.LocalUser.Value.Id) { User = api.LocalUser.Value }; + + var room = new MultiplayerRoom(roomId); + room.Users.Add(user); + + if (room.Users.Count == 1) + room.Host = user; + + return Task.FromResult(room); + } + + public override Task TransferHost(int userId) => ((IMultiplayerClient)this).HostChanged(userId); + + public override async Task ChangeSettings(MultiplayerRoomSettings settings) + { + Debug.Assert(Room != null); + + await ((IMultiplayerClient)this).SettingsChanged(settings); + + foreach (var user in Room.Users.Where(u => u.State == MultiplayerUserState.Ready)) + ChangeUserState(user.UserID, MultiplayerUserState.Idle); + } + + public override Task ChangeState(MultiplayerUserState newState) + { + ChangeUserState(api.LocalUser.Value.Id, newState); + return Task.CompletedTask; + } + + public override async Task StartMatch() + { + Debug.Assert(Room != null); + + foreach (var user in Room.Users.Where(u => u.State == MultiplayerUserState.Ready)) + ChangeUserState(user.UserID, MultiplayerUserState.WaitingForLoad); + + await ((IMultiplayerClient)this).LoadRequested(); + } + } +} From 50a35c0f63222f767678d4b661b93f19e04a2b67 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 01:16:00 +0900 Subject: [PATCH 084/328] Add connection/disconnection capability --- .../RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs index 2a90f1e744..bfa8362c7e 100644 --- a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs @@ -16,11 +16,16 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer { public class TestRealtimeMultiplayerClient : StatefulMultiplayerClient { - public override IBindable IsConnected { get; } = new Bindable(true); + public override IBindable IsConnected => isConnected; + private readonly Bindable isConnected = new Bindable(true); [Resolved] private IAPIProvider api { get; set; } = null!; + public void Connect() => isConnected.Value = true; + + public void Disconnect() => isConnected.Value = false; + public void AddUser(User user) => ((IMultiplayerClient)this).UserJoined(new MultiplayerRoomUser(user.Id) { User = user }); public void RemoveUser(User user) From c6555c53cc315b6df93cab9d7c56dc2c018ad2ed Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 01:17:24 +0900 Subject: [PATCH 085/328] Add a testable realtime room manager --- .../API/Requests/GetBeatmapSetRequest.cs | 10 +- .../Online/Multiplayer/CreateRoomRequest.cs | 6 +- .../TestRealtimeRoomManager.cs | 91 +++++++++++++++++++ 3 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs diff --git a/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs index 8e6deeb3c6..158ae03b8d 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs @@ -7,16 +7,16 @@ namespace osu.Game.Online.API.Requests { public class GetBeatmapSetRequest : APIRequest { - private readonly int id; - private readonly BeatmapSetLookupType type; + public readonly int ID; + public readonly BeatmapSetLookupType Type; public GetBeatmapSetRequest(int id, BeatmapSetLookupType type = BeatmapSetLookupType.SetId) { - this.id = id; - this.type = type; + ID = id; + Type = type; } - protected override string Target => type == BeatmapSetLookupType.SetId ? $@"beatmapsets/{id}" : $@"beatmapsets/lookup?beatmap_id={id}"; + protected override string Target => Type == BeatmapSetLookupType.SetId ? $@"beatmapsets/{ID}" : $@"beatmapsets/lookup?beatmap_id={ID}"; } public enum BeatmapSetLookupType diff --git a/osu.Game/Online/Multiplayer/CreateRoomRequest.cs b/osu.Game/Online/Multiplayer/CreateRoomRequest.cs index dcb4ed51ea..5be99e9442 100644 --- a/osu.Game/Online/Multiplayer/CreateRoomRequest.cs +++ b/osu.Game/Online/Multiplayer/CreateRoomRequest.cs @@ -10,11 +10,11 @@ namespace osu.Game.Online.Multiplayer { public class CreateRoomRequest : APIRequest { - private readonly Room room; + public readonly Room Room; public CreateRoomRequest(Room room) { - this.room = room; + Room = room; } protected override WebRequest CreateWebRequest() @@ -24,7 +24,7 @@ namespace osu.Game.Online.Multiplayer req.ContentType = "application/json"; req.Method = HttpMethod.Post; - req.AddRaw(JsonConvert.SerializeObject(room)); + req.AddRaw(JsonConvert.SerializeObject(Room)); return req; } diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs new file mode 100644 index 0000000000..773b72da88 --- /dev/null +++ b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs @@ -0,0 +1,91 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; +using osu.Game.Screens.Multi.RealtimeMultiplayer; + +namespace osu.Game.Tests.Visual.RealtimeMultiplayer +{ + public class TestRealtimeRoomManager : RealtimeRoomManager + { + [Resolved] + private IAPIProvider api { get; set; } + + [Resolved] + private OsuGameBase game { get; set; } + + private readonly List rooms = new List(); + + protected override void LoadComplete() + { + base.LoadComplete(); + + int currentScoreId = 0; + + ((DummyAPIAccess)api).HandleRequest = req => + { + switch (req) + { + case CreateRoomRequest createRoomRequest: + var createdRoom = new APICreatedRoom(); + + createdRoom.CopyFrom(createRoomRequest.Room); + createdRoom.RoomID.Value = 1; + + rooms.Add(createdRoom); + createRoomRequest.TriggerSuccess(createdRoom); + break; + + case JoinRoomRequest joinRoomRequest: + joinRoomRequest.TriggerSuccess(); + break; + + case PartRoomRequest partRoomRequest: + partRoomRequest.TriggerSuccess(); + break; + + case GetRoomsRequest getRoomsRequest: + getRoomsRequest.TriggerSuccess(rooms); + break; + + case GetBeatmapSetRequest getBeatmapSetRequest: + var onlineReq = new GetBeatmapSetRequest(getBeatmapSetRequest.ID, getBeatmapSetRequest.Type); + onlineReq.Success += res => getBeatmapSetRequest.TriggerSuccess(res); + onlineReq.Failure += e => getBeatmapSetRequest.TriggerFailure(e); + + // Get the online API from the game's dependencies. + game.Dependencies.Get().Queue(onlineReq); + break; + + case CreateRoomScoreRequest createRoomScoreRequest: + createRoomScoreRequest.TriggerSuccess(new APIScoreToken { ID = 1 }); + break; + + case SubmitRoomScoreRequest submitRoomScoreRequest: + submitRoomScoreRequest.TriggerSuccess(new MultiplayerScore + { + ID = currentScoreId++, + Accuracy = 1, + EndedAt = DateTimeOffset.Now, + Passed = true, + Rank = ScoreRank.S, + MaxCombo = 1000, + TotalScore = 1000000, + User = api.LocalUser.Value, + Statistics = new Dictionary() + }); + break; + } + }; + } + + public new void Schedule(Action action) => base.Schedule(action); + } +} From c6da680c803a0d9cf055fbedbd57e7992eed823e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 01:19:08 +0900 Subject: [PATCH 086/328] Add a container for testing purposes --- .../TestRealtimeRoomContainer.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomContainer.cs diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomContainer.cs b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomContainer.cs new file mode 100644 index 0000000000..aa75968cca --- /dev/null +++ b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomContainer.cs @@ -0,0 +1,40 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Screens.Multi.Lounge.Components; +using osu.Game.Screens.Multi.RealtimeMultiplayer; + +namespace osu.Game.Tests.Visual.RealtimeMultiplayer +{ + public class TestRealtimeRoomContainer : Container + { + protected override Container Content => content; + private readonly Container content; + + [Cached(typeof(StatefulMultiplayerClient))] + public readonly TestRealtimeMultiplayerClient Client; + + [Cached(typeof(RealtimeRoomManager))] + public readonly TestRealtimeRoomManager RoomManager; + + [Cached] + public readonly Bindable Filter = new Bindable(new FilterCriteria()); + + public TestRealtimeRoomContainer() + { + RelativeSizeAxes = Axes.Both; + + AddRangeInternal(new Drawable[] + { + Client = new TestRealtimeMultiplayerClient(), + RoomManager = new TestRealtimeRoomManager(), + content = new Container { RelativeSizeAxes = Axes.Both } + }); + } + } +} From 2fc5561b7ec7a4a5c53235203cd65b1c8d6869b8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 01:22:52 +0900 Subject: [PATCH 087/328] Add handling for GetRoomRequest() --- osu.Game/Online/Multiplayer/GetRoomRequest.cs | 6 +++--- .../TestRealtimeRoomManager.cs | 19 ++++++++++++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Multiplayer/GetRoomRequest.cs b/osu.Game/Online/Multiplayer/GetRoomRequest.cs index 2907b49f1d..449c2c8e31 100644 --- a/osu.Game/Online/Multiplayer/GetRoomRequest.cs +++ b/osu.Game/Online/Multiplayer/GetRoomRequest.cs @@ -7,13 +7,13 @@ namespace osu.Game.Online.Multiplayer { public class GetRoomRequest : APIRequest { - private readonly int roomId; + public readonly int RoomId; public GetRoomRequest(int roomId) { - this.roomId = roomId; + RoomId = roomId; } - protected override string Target => $"rooms/{roomId}"; + protected override string Target => $"rooms/{RoomId}"; } } diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs index 773b72da88..cee1c706ae 100644 --- a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs +++ b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -52,7 +53,23 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer break; case GetRoomsRequest getRoomsRequest: - getRoomsRequest.TriggerSuccess(rooms); + var roomsWithoutParticipants = new List(); + + foreach (var r in rooms) + { + var newRoom = new Room(); + + newRoom.CopyFrom(r); + newRoom.RecentParticipants.Clear(); + + roomsWithoutParticipants.Add(newRoom); + } + + getRoomsRequest.TriggerSuccess(roomsWithoutParticipants); + break; + + case GetRoomRequest getRoomRequest: + getRoomRequest.TriggerSuccess(rooms.Single(r => r.RoomID.Value == getRoomRequest.RoomId)); break; case GetBeatmapSetRequest getBeatmapSetRequest: From 9b0ca8fc3b2b380578202e5e75145d1b88ed9743 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 01:57:30 +0900 Subject: [PATCH 088/328] Make real time room manager not poll while inside a room --- .../Screens/Multi/Components/RoomManager.cs | 14 ++++++------ .../RealtimeRoomManager.cs | 22 +++++++++++++------ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Multi/Components/RoomManager.cs b/osu.Game/Screens/Multi/Components/RoomManager.cs index d92427680e..6e27515849 100644 --- a/osu.Game/Screens/Multi/Components/RoomManager.cs +++ b/osu.Game/Screens/Multi/Components/RoomManager.cs @@ -27,6 +27,8 @@ namespace osu.Game.Screens.Multi.Components public IBindableList Rooms => rooms; + protected Room JoinedRoom { get; private set; } + [Resolved] private RulesetStore rulesets { get; set; } @@ -36,8 +38,6 @@ namespace osu.Game.Screens.Multi.Components [Resolved] private IAPIProvider api { get; set; } - private Room joinedRoom; - protected RoomManager() { RelativeSizeAxes = Axes.Both; @@ -64,7 +64,7 @@ namespace osu.Game.Screens.Multi.Components req.Success += result => { - joinedRoom = room; + JoinedRoom = room; update(room, result); addRoom(room); @@ -93,7 +93,7 @@ namespace osu.Game.Screens.Multi.Components currentJoinRoomRequest.Success += () => { - joinedRoom = room; + JoinedRoom = room; onSuccess?.Invoke(room); }; @@ -111,11 +111,11 @@ namespace osu.Game.Screens.Multi.Components { currentJoinRoomRequest?.Cancel(); - if (joinedRoom == null) + if (JoinedRoom == null) return; - api.Queue(new PartRoomRequest(joinedRoom)); - joinedRoom = null; + api.Queue(new PartRoomRequest(JoinedRoom)); + JoinedRoom = null; } private readonly HashSet ignoredRooms = new HashSet(); diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index 62ea5d5512..69addde2a6 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -21,17 +21,16 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer public readonly Bindable TimeBetweenListingPolls = new Bindable(); public readonly Bindable TimeBetweenSelectionPolls = new Bindable(); private readonly IBindable isConnected = new Bindable(); + private readonly Bindable allowPolling = new Bindable(); protected override void LoadComplete() { base.LoadComplete(); isConnected.BindTo(multiplayerClient.IsConnected); - isConnected.BindValueChanged(connected => Schedule(() => - { - if (!connected.NewValue) - ClearRooms(); - })); + isConnected.BindValueChanged(_ => Schedule(updatePolling), true); + + updatePolling(); } public override void CreateRoom(Room room, Action onSuccess = null, Action onError = null) @@ -54,17 +53,26 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer }, TaskContinuationOptions.NotOnRanToCompletion); } + private void updatePolling() + { + if (!isConnected.Value) + ClearRooms(); + + // Don't poll when not connected or when a room has been joined. + allowPolling.Value = isConnected.Value && JoinedRoom == null; + } + protected override RoomPollingComponent[] CreatePollingComponents() => new RoomPollingComponent[] { new RealtimeListingPollingComponent { TimeBetweenPolls = { BindTarget = TimeBetweenListingPolls }, - AllowPolling = { BindTarget = isConnected } + AllowPolling = { BindTarget = allowPolling } }, new RealtimeSelectionPollingComponent { TimeBetweenPolls = { BindTarget = TimeBetweenSelectionPolls }, - AllowPolling = { BindTarget = isConnected } + AllowPolling = { BindTarget = allowPolling } } }; From 7d1fe7955e633e332e2d43fafc1dd24f313e4ee5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 01:57:40 +0900 Subject: [PATCH 089/328] Small improvements to testable room manager --- .../RealtimeMultiplayer/TestRealtimeRoomManager.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs index cee1c706ae..0d1314fb51 100644 --- a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs +++ b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs @@ -5,11 +5,13 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; +using osu.Game.Screens.Multi.Lounge.Components; using osu.Game.Screens.Multi.RealtimeMultiplayer; namespace osu.Game.Tests.Visual.RealtimeMultiplayer @@ -22,6 +24,9 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer [Resolved] private OsuGameBase game { get; set; } + [Cached] + public readonly Bindable Filter = new Bindable(new FilterCriteria()); + private readonly List rooms = new List(); protected override void LoadComplete() @@ -29,6 +34,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer base.LoadComplete(); int currentScoreId = 0; + int currentRoomId = 0; ((DummyAPIAccess)api).HandleRequest = req => { @@ -38,7 +44,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer var createdRoom = new APICreatedRoom(); createdRoom.CopyFrom(createRoomRequest.Room); - createdRoom.RoomID.Value = 1; + createdRoom.RoomID.Value ??= currentRoomId++; rooms.Add(createdRoom); createRoomRequest.TriggerSuccess(createdRoom); @@ -103,6 +109,8 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer }; } + public new void ClearRooms() => base.ClearRooms(); + public new void Schedule(Action action) => base.Schedule(action); } } From 0fb8615f95b29dbff7ba1c839c3591a1b72aa5b1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 02:02:04 +0900 Subject: [PATCH 090/328] Implement room parting --- .../Screens/Multi/Components/RoomManager.cs | 4 +++- .../RealtimeRoomManager.cs | 20 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/Components/RoomManager.cs b/osu.Game/Screens/Multi/Components/RoomManager.cs index 6e27515849..21bff70b8b 100644 --- a/osu.Game/Screens/Multi/Components/RoomManager.cs +++ b/osu.Game/Screens/Multi/Components/RoomManager.cs @@ -107,7 +107,7 @@ namespace osu.Game.Screens.Multi.Components api.Queue(currentJoinRoomRequest); } - public void PartRoom() + public virtual void PartRoom() { currentJoinRoomRequest?.Cancel(); @@ -157,6 +157,8 @@ namespace osu.Game.Screens.Multi.Components RoomsUpdated?.Invoke(); } + protected void RemoveRoom(Room room) => rooms.Remove(room); + protected void ClearRooms() { rooms.Clear(); diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index 69addde2a6..4f73ee3865 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -23,6 +23,8 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer private readonly IBindable isConnected = new Bindable(); private readonly Bindable allowPolling = new Bindable(); + private ListingPollingComponent listingPollingComponent; + protected override void LoadComplete() { base.LoadComplete(); @@ -39,6 +41,22 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer public override void JoinRoom(Room room, Action onSuccess = null, Action onError = null) => base.JoinRoom(room, r => joinMultiplayerRoom(r, onSuccess), onError); + public override void PartRoom() + { + if (JoinedRoom == null) + return; + + var joinedRoom = JoinedRoom; + + base.PartRoom(); + multiplayerClient.LeaveRoom().Wait(); + + // Todo: This is not the way to do this. Basically when we're the only participant and the room closes, there's no way to know if this is actually the case. + RemoveRoom(joinedRoom); + // This is delayed one frame because upon exiting the match subscreen, multiplayer updates the polling rate and messes with polling. + Schedule(() => listingPollingComponent.PollImmediately()); + } + private void joinMultiplayerRoom(Room room, Action onSuccess = null) { Debug.Assert(room.RoomID.Value != null); @@ -64,7 +82,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer protected override RoomPollingComponent[] CreatePollingComponents() => new RoomPollingComponent[] { - new RealtimeListingPollingComponent + listingPollingComponent = new RealtimeListingPollingComponent { TimeBetweenPolls = { BindTarget = TimeBetweenListingPolls }, AllowPolling = { BindTarget = allowPolling } From a593f588db95a8ac6b8bb2594c1a94909ade9c5f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 02:02:47 +0900 Subject: [PATCH 091/328] Add a test for the realtime room manager --- .../TestSceneRealtimeRoomManager.cs | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs new file mode 100644 index 0000000000..6bd8c410a4 --- /dev/null +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs @@ -0,0 +1,105 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Game.Online.Multiplayer; + +namespace osu.Game.Tests.Visual.RealtimeMultiplayer +{ + public class TestSceneRealtimeRoomManager : MultiplayerTestScene + { + private TestRealtimeRoomContainer roomContainer; + private TestRealtimeRoomManager roomManager => roomContainer.RoomManager; + + [Test] + public void TestPollsInitially() + { + AddStep("create room manager with a few rooms", () => + { + createRoomManager().With(d => d.OnLoadComplete += _ => + { + roomManager.CreateRoom(new Room { Name = { Value = "1" } }); + roomManager.PartRoom(); + roomManager.CreateRoom(new Room { Name = { Value = "2" } }); + roomManager.PartRoom(); + roomManager.ClearRooms(); + }); + }); + + AddAssert("manager polled for rooms", () => roomManager.Rooms.Count == 2); + AddAssert("initial rooms received", () => roomManager.InitialRoomsReceived.Value); + } + + [Test] + public void TestRoomsClearedOnDisconnection() + { + AddStep("create room manager with a few rooms", () => + { + createRoomManager().With(d => d.OnLoadComplete += _ => + { + roomManager.CreateRoom(new Room()); + roomManager.PartRoom(); + roomManager.CreateRoom(new Room()); + roomManager.PartRoom(); + }); + }); + + AddStep("disconnect", () => roomContainer.Client.Disconnect()); + + AddAssert("rooms cleared", () => roomManager.Rooms.Count == 0); + AddAssert("initial rooms not received", () => !roomManager.InitialRoomsReceived.Value); + } + + [Test] + public void TestRoomsPolledOnReconnect() + { + AddStep("create room manager with a few rooms", () => + { + createRoomManager().With(d => d.OnLoadComplete += _ => + { + roomManager.CreateRoom(new Room()); + roomManager.PartRoom(); + roomManager.CreateRoom(new Room()); + roomManager.PartRoom(); + }); + }); + + AddStep("disconnect", () => roomContainer.Client.Disconnect()); + AddStep("connect", () => roomContainer.Client.Connect()); + + AddAssert("manager polled for rooms", () => roomManager.Rooms.Count == 2); + AddAssert("initial rooms received", () => roomManager.InitialRoomsReceived.Value); + } + + [Test] + public void TestRoomsNotPolledWhenJoined() + { + AddStep("create room manager with a room", () => + { + createRoomManager().With(d => d.OnLoadComplete += _ => + { + roomManager.CreateRoom(new Room()); + roomManager.ClearRooms(); + }); + }); + + AddAssert("manager not polled for rooms", () => roomManager.Rooms.Count == 0); + AddAssert("initial rooms not received", () => !roomManager.InitialRoomsReceived.Value); + } + + private TestRealtimeRoomManager createRoomManager() + { + Child = roomContainer = new TestRealtimeRoomContainer + { + RoomManager = + { + TimeBetweenListingPolls = { Value = 1 }, + TimeBetweenSelectionPolls = { Value = 1 } + } + }; + + return roomManager; + } + } +} From e84ce80d6cb0187b67527d5289ee3480e0746484 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 02:17:07 +0900 Subject: [PATCH 092/328] Make test headless --- .../Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs index 6bd8c410a4..9a4b748de1 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs @@ -3,10 +3,12 @@ using NUnit.Framework; using osu.Framework.Graphics; +using osu.Framework.Testing; using osu.Game.Online.Multiplayer; namespace osu.Game.Tests.Visual.RealtimeMultiplayer { + [HeadlessTest] public class TestSceneRealtimeRoomManager : MultiplayerTestScene { private TestRealtimeRoomContainer roomContainer; From 109e6b4283e0a49ac13be9a59572ab1f6f599e0a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 02:20:02 +0900 Subject: [PATCH 093/328] Add tests for creating/joining/parting multiplayer rooms --- .../TestSceneRealtimeRoomManager.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs index 9a4b748de1..598641682b 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs @@ -90,6 +90,52 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer AddAssert("initial rooms not received", () => !roomManager.InitialRoomsReceived.Value); } + [Test] + public void TestMultiplayerRoomJoinedWhenCreated() + { + AddStep("create room manager with a room", () => + { + createRoomManager().With(d => d.OnLoadComplete += _ => + { + roomManager.CreateRoom(new Room()); + }); + }); + + AddAssert("multiplayer room joined", () => roomContainer.Client.Room != null); + } + + [Test] + public void TestMultiplayerRoomPartedWhenAPIRoomParted() + { + AddStep("create room manager with a room", () => + { + createRoomManager().With(d => d.OnLoadComplete += _ => + { + roomManager.CreateRoom(new Room()); + roomManager.PartRoom(); + }); + }); + + AddAssert("multiplayer room parted", () => roomContainer.Client.Room == null); + } + + [Test] + public void TestMultiplayerRoomPartedWhenAPIRoomJoined() + { + AddStep("create room manager with a room", () => + { + createRoomManager().With(d => d.OnLoadComplete += _ => + { + var r = new Room(); + roomManager.CreateRoom(r); + roomManager.PartRoom(); + roomManager.JoinRoom(r); + }); + }); + + AddAssert("multiplayer room parted", () => roomContainer.Client.Room != null); + } + private TestRealtimeRoomManager createRoomManager() { Child = roomContainer = new TestRealtimeRoomContainer From 3f4a66c4ae6036b98cb3512ba2440d75596c056e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 02:23:42 +0900 Subject: [PATCH 094/328] Add realtime multiplayer test scene abstract class --- .../RealtimeMultiplayerTestScene.cs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs b/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs new file mode 100644 index 0000000000..e41076a4fd --- /dev/null +++ b/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs @@ -0,0 +1,53 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Screens.Multi.Lounge.Components; +using osu.Game.Screens.Multi.RealtimeMultiplayer; + +namespace osu.Game.Tests.Visual.RealtimeMultiplayer +{ + public class RealtimeMultiplayerTestScene : MultiplayerTestScene + { + [Cached(typeof(StatefulMultiplayerClient))] + public TestRealtimeMultiplayerClient Client { get; } + + [Cached(typeof(RealtimeRoomManager))] + public TestRealtimeRoomManager RoomManager { get; } + + [Cached] + public Bindable Filter { get; } + + protected override Container Content => content; + private readonly TestRealtimeRoomContainer content; + + private readonly bool joinRoom; + + public RealtimeMultiplayerTestScene(bool joinRoom = true) + { + this.joinRoom = joinRoom; + base.Content.Add(content = new TestRealtimeRoomContainer { RelativeSizeAxes = Axes.Both }); + + Client = content.Client; + RoomManager = content.RoomManager; + Filter = content.Filter; + } + + [SetUp] + public new void Setup() => Schedule(() => + { + RoomManager.Schedule(() => RoomManager.PartRoom()); + + if (joinRoom) + { + Room.RoomID.Value = 1; + RoomManager.Schedule(() => RoomManager.JoinRoom(Room, null, null)); + } + }); + } +} From 9b08f573baeb360e0f5135f98f5205b7145757e5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 02:41:04 +0900 Subject: [PATCH 095/328] Fix room not created before being joined --- .../RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs b/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs index e41076a4fd..b52106551e 100644 --- a/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs +++ b/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs @@ -44,10 +44,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer RoomManager.Schedule(() => RoomManager.PartRoom()); if (joinRoom) - { - Room.RoomID.Value = 1; - RoomManager.Schedule(() => RoomManager.JoinRoom(Room, null, null)); - } + RoomManager.Schedule(() => RoomManager.CreateRoom(Room)); }); } } From 4d051818a152573834a0e859994f25c83bda1b7a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 02:30:53 +0900 Subject: [PATCH 096/328] Add base class for all realtime multiplayer classes --- .../RealtimeRoomComposite.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomComposite.cs diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomComposite.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomComposite.cs new file mode 100644 index 0000000000..e6d1274316 --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomComposite.cs @@ -0,0 +1,38 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Game.Online.RealtimeMultiplayer; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer +{ + public abstract class RealtimeRoomComposite : MultiplayerComposite + { + [CanBeNull] + protected MultiplayerRoom Room => Client.Room; + + [Resolved] + protected StatefulMultiplayerClient Client { get; private set; } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Client.RoomChanged += OnRoomChanged; + OnRoomChanged(); + } + + protected virtual void OnRoomChanged() + { + } + + protected override void Dispose(bool isDisposing) + { + if (Client != null) + Client.RoomChanged -= OnRoomChanged; + + base.Dispose(isDisposing); + } + } +} From 1e5c32410ad572883295e0f8e47e90704ef4593e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 02:37:47 +0900 Subject: [PATCH 097/328] Add the realtime multiplayer participants list --- .../TestSceneParticipantsList.cs | 96 +++++++++ .../Participants/ParticipantPanel.cs | 187 ++++++++++++++++++ .../Participants/ParticipantsList.cs | 55 ++++++ .../Participants/ReadyMark.cs | 51 +++++ 4 files changed, 389 insertions(+) create mode 100644 osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsList.cs create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ReadyMark.cs diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs new file mode 100644 index 0000000000..ee6bbc4ecd --- /dev/null +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs @@ -0,0 +1,96 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Testing; +using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Screens.Multi.RealtimeMultiplayer.Participants; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Tests.Visual.RealtimeMultiplayer +{ + public class TestSceneParticipantsList : RealtimeMultiplayerTestScene + { + [SetUp] + public new void Setup() => Schedule(() => + { + Child = new ParticipantsList + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Y, + Size = new Vector2(380, 0.7f) + }; + }); + + [Test] + public void TestAddUser() + { + AddAssert("one unique panel", () => this.ChildrenOfType().Select(p => p.User).Distinct().Count() == 1); + + AddStep("add user", () => Client.AddUser(new User + { + Id = 3, + Username = "Second", + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", + })); + + AddAssert("two unique panels", () => this.ChildrenOfType().Select(p => p.User).Distinct().Count() == 2); + } + + [Test] + public void TestRemoveUser() + { + User secondUser = null; + + AddStep("add a user", () => + { + Client.AddUser(secondUser = new User + { + Id = 3, + Username = "Second", + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", + }); + }); + + AddStep("remove host", () => Client.RemoveUser(API.LocalUser.Value)); + + AddAssert("single panel is for second user", () => this.ChildrenOfType().Single().User.User == secondUser); + } + + [Test] + public void TestToggleReadyState() + { + AddAssert("ready mark invisible", () => !this.ChildrenOfType().Single().IsPresent); + + AddStep("make user ready", () => Client.ChangeState(MultiplayerUserState.Ready)); + AddUntilStep("ready mark visible", () => this.ChildrenOfType().Single().IsPresent); + + AddStep("make user idle", () => Client.ChangeState(MultiplayerUserState.Idle)); + AddUntilStep("ready mark invisible", () => !this.ChildrenOfType().Single().IsPresent); + } + + [Test] + public void TestCrownChangesStateWhenHostTransferred() + { + AddStep("add user", () => Client.AddUser(new User + { + Id = 3, + Username = "Second", + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", + })); + + AddUntilStep("first user crown visible", () => this.ChildrenOfType().ElementAt(0).ChildrenOfType().First().Alpha == 1); + AddUntilStep("second user crown hidden", () => this.ChildrenOfType().ElementAt(1).ChildrenOfType().First().Alpha == 0); + + AddStep("make second user host", () => Client.TransferHost(3)); + + AddUntilStep("first user crown hidden", () => this.ChildrenOfType().ElementAt(0).ChildrenOfType().First().Alpha == 0); + AddUntilStep("second user crown visible", () => this.ChildrenOfType().ElementAt(1).ChildrenOfType().First().Alpha == 1); + } + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs new file mode 100644 index 0000000000..306a54bfdc --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs @@ -0,0 +1,187 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics; +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.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; +using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Users; +using osu.Game.Users.Drawables; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants +{ + public class ParticipantPanel : RealtimeRoomComposite, IHasContextMenu + { + public readonly MultiplayerRoomUser User; + + [Resolved] + private IAPIProvider api { get; set; } + + private ReadyMark readyMark; + private SpriteIcon crown; + + public ParticipantPanel(MultiplayerRoomUser user) + { + User = user; + + RelativeSizeAxes = Axes.X; + Height = 40; + } + + [BackgroundDependencyLoader] + private void load() + { + Debug.Assert(User.User != null); + + var backgroundColour = Color4Extensions.FromHex("#33413C"); + + InternalChildren = new Drawable[] + { + crown = new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Icon = FontAwesome.Solid.Crown, + Size = new Vector2(14), + Colour = Color4Extensions.FromHex("#F7E65D"), + Alpha = 0 + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = 24 }, + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 5, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = backgroundColour + }, + new UserCoverBackground + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Both, + Width = 0.75f, + User = User.User, + Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(0), Color4.White.Opacity(0.25f)) + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Spacing = new Vector2(10), + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + new UpdateableAvatar + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + User = User.User + }, + new UpdateableFlag + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(30, 20), + Country = User.User.Country + }, + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 18), + Text = User.User.Username + }, + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 14), + Text = User.User.CurrentModeRank != null ? $"#{User.User.CurrentModeRank}" : string.Empty + } + } + }, + readyMark = new ReadyMark + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Margin = new MarginPadding { Right = 10 }, + Alpha = 0 + } + } + } + } + }; + } + + protected override void OnRoomChanged() + { + base.OnRoomChanged(); + + if (Room == null) + return; + + if (User.State == MultiplayerUserState.Ready) + readyMark.FadeIn(50); + else + readyMark.FadeOut(50); + + if (Room.Host?.Equals(User) == true) + crown.FadeIn(50); + else + crown.FadeOut(50); + } + + public MenuItem[] ContextMenuItems + { + get + { + if (Room == null) + return null; + + // If the local user is targetted. + if (User.UserID == api.LocalUser.Value.Id) + return null; + + // If the local user is not the host of the room. + if (Room.Host?.UserID != api.LocalUser.Value.Id) + return null; + + int targetUser = User.UserID; + + return new MenuItem[] + { + new OsuMenuItem("Give host", MenuItemType.Standard, () => + { + // Ensure the local user is still host. + if (Room.Host?.UserID != api.LocalUser.Value.Id) + return; + + Client.TransferHost(targetUser); + }) + }; + } + } + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsList.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsList.cs new file mode 100644 index 0000000000..d4c32d9189 --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsList.cs @@ -0,0 +1,55 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Cursor; +using osuTK; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants +{ + public class ParticipantsList : RealtimeRoomComposite + { + private FillFlowContainer panels; + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new OsuContextMenuContainer + { + RelativeSizeAxes = Axes.Both, + Child = new OsuScrollContainer + { + RelativeSizeAxes = Axes.Both, + Child = panels = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 2) + } + } + }; + } + + protected override void OnRoomChanged() + { + base.OnRoomChanged(); + + if (Room == null) + panels.Clear(); + else + { + // Remove panels for users no longer in the room. + panels.RemoveAll(p => !Room.Users.Contains(p.User)); + + // Add panels for all users new to the room. + foreach (var user in Room.Users.Except(panels.Select(p => p.User))) + panels.Add(new ParticipantPanel(user)); + } + } + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ReadyMark.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ReadyMark.cs new file mode 100644 index 0000000000..df49d9342e --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ReadyMark.cs @@ -0,0 +1,51 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osuTK; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants +{ + public class ReadyMark : CompositeDrawable + { + public ReadyMark() + { + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 12), + Text = "ready", + Colour = Color4Extensions.FromHex("#DDFFFF") + }, + new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Icon = FontAwesome.Solid.CheckCircle, + Size = new Vector2(12), + Colour = Color4Extensions.FromHex("#AADD00") + } + } + }; + } + } +} From 11a903a206a820191af25de9e4f953223869c44a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 02:46:16 +0900 Subject: [PATCH 098/328] Add test for many users and disable scrollbar --- .../TestSceneParticipantsList.cs | 20 +++++++++++++++++++ .../Participants/ParticipantsList.cs | 1 + 2 files changed, 21 insertions(+) diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs index ee6bbc4ecd..8c997e9e32 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs @@ -92,5 +92,25 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer AddUntilStep("first user crown hidden", () => this.ChildrenOfType().ElementAt(0).ChildrenOfType().First().Alpha == 0); AddUntilStep("second user crown visible", () => this.ChildrenOfType().ElementAt(1).ChildrenOfType().First().Alpha == 1); } + + [Test] + public void TestManyUsers() + { + AddStep("add many users", () => + { + for (int i = 0; i < 20; i++) + { + Client.AddUser(new User + { + Id = i, + Username = $"User {i}", + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", + }); + + if (i % 2 == 0) + Client.ChangeUserState(i, MultiplayerUserState.Ready); + } + }); + } } } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsList.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsList.cs index d4c32d9189..218c2cabb7 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsList.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsList.cs @@ -24,6 +24,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants Child = new OsuScrollContainer { RelativeSizeAxes = Axes.Both, + ScrollbarVisible = false, Child = panels = new FillFlowContainer { RelativeSizeAxes = Axes.X, From e4a54dc6cdccdf17b1e950fe1abf0424e9c28485 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 02:52:51 +0900 Subject: [PATCH 099/328] Renamespace ready button --- osu.Game/Screens/Multi/{Match => }/Components/ReadyButton.cs | 2 +- osu.Game/Screens/Multi/Match/Components/Footer.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) rename osu.Game/Screens/Multi/{Match => }/Components/ReadyButton.cs (98%) diff --git a/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs b/osu.Game/Screens/Multi/Components/ReadyButton.cs similarity index 98% rename from osu.Game/Screens/Multi/Match/Components/ReadyButton.cs rename to osu.Game/Screens/Multi/Components/ReadyButton.cs index a64f24dd7e..6d12111d8f 100644 --- a/osu.Game/Screens/Multi/Match/Components/ReadyButton.cs +++ b/osu.Game/Screens/Multi/Components/ReadyButton.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; -namespace osu.Game.Screens.Multi.Match.Components +namespace osu.Game.Screens.Multi.Components { public class ReadyButton : TriangleButton { diff --git a/osu.Game/Screens/Multi/Match/Components/Footer.cs b/osu.Game/Screens/Multi/Match/Components/Footer.cs index be4ee873fa..4ec8628d2b 100644 --- a/osu.Game/Screens/Multi/Match/Components/Footer.cs +++ b/osu.Game/Screens/Multi/Match/Components/Footer.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Online.Multiplayer; +using osu.Game.Screens.Multi.Components; using osuTK; namespace osu.Game.Screens.Multi.Match.Components From 4e0113afbf51e5d9be43e73b1fee714a21c04ee1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 02:55:48 +0900 Subject: [PATCH 100/328] Abstractify ready button and add a timeshift implementation --- .../Screens/Multi/Components/ReadyButton.cs | 24 +++--------- .../Screens/Multi/Match/Components/Footer.cs | 4 +- .../Multi/Timeshift/TimeshiftReadyButton.cs | 38 +++++++++++++++++++ 3 files changed, 46 insertions(+), 20 deletions(-) create mode 100644 osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs diff --git a/osu.Game/Screens/Multi/Components/ReadyButton.cs b/osu.Game/Screens/Multi/Components/ReadyButton.cs index 6d12111d8f..0bb4ed8617 100644 --- a/osu.Game/Screens/Multi/Components/ReadyButton.cs +++ b/osu.Game/Screens/Multi/Components/ReadyButton.cs @@ -13,26 +13,20 @@ using osu.Game.Online.Multiplayer; namespace osu.Game.Screens.Multi.Components { - public class ReadyButton : TriangleButton + public abstract class ReadyButton : TriangleButton { public readonly Bindable SelectedItem = new Bindable(); - [Resolved(typeof(Room), nameof(Room.EndDate))] - private Bindable endDate { get; set; } + public new readonly BindableBool Enabled = new BindableBool(); [Resolved] - private IBindable gameBeatmap { get; set; } + protected IBindable GameBeatmap { get; private set; } [Resolved] private BeatmapManager beatmaps { get; set; } private bool hasBeatmap; - public ReadyButton() - { - Text = "Start"; - } - private IBindable> managerUpdated; private IBindable> managerRemoved; @@ -45,10 +39,6 @@ namespace osu.Game.Screens.Multi.Components managerRemoved.BindValueChanged(beatmapRemoved); SelectedItem.BindValueChanged(item => updateSelectedItem(item.NewValue), true); - - BackgroundColour = colours.Green; - Triangles.ColourDark = colours.Green; - Triangles.ColourLight = colours.GreenLight; } private void updateSelectedItem(PlaylistItem item) @@ -94,15 +84,13 @@ namespace osu.Game.Screens.Multi.Components private void updateEnabledState() { - if (gameBeatmap.Value == null || SelectedItem.Value == null) + if (GameBeatmap.Value == null || SelectedItem.Value == null) { - Enabled.Value = false; + base.Enabled.Value = false; return; } - bool hasEnoughTime = DateTimeOffset.UtcNow.AddSeconds(30).AddMilliseconds(gameBeatmap.Value.Track.Length) < endDate.Value; - - Enabled.Value = hasBeatmap && hasEnoughTime; + base.Enabled.Value = hasBeatmap && Enabled.Value; } } } diff --git a/osu.Game/Screens/Multi/Match/Components/Footer.cs b/osu.Game/Screens/Multi/Match/Components/Footer.cs index 4ec8628d2b..d6a7e380bf 100644 --- a/osu.Game/Screens/Multi/Match/Components/Footer.cs +++ b/osu.Game/Screens/Multi/Match/Components/Footer.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Online.Multiplayer; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.Multi.Timeshift; using osuTK; namespace osu.Game.Screens.Multi.Match.Components @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Multi.Match.Components InternalChildren = new[] { background = new Box { RelativeSizeAxes = Axes.Both }, - new ReadyButton + new TimeshiftReadyButton { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs new file mode 100644 index 0000000000..b6698b195c --- /dev/null +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs @@ -0,0 +1,38 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Graphics; +using osu.Game.Online.Multiplayer; +using osu.Game.Screens.Multi.Components; + +namespace osu.Game.Screens.Multi.Timeshift +{ + public class TimeshiftReadyButton : ReadyButton + { + [Resolved(typeof(Room), nameof(Room.EndDate))] + private Bindable endDate { get; set; } + + public TimeshiftReadyButton() + { + Text = "Start"; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = colours.Green; + Triangles.ColourDark = colours.Green; + Triangles.ColourLight = colours.GreenLight; + } + + protected override void Update() + { + base.Update(); + + Enabled.Value = endDate.Value == null || DateTimeOffset.UtcNow.AddSeconds(30).AddMilliseconds(GameBeatmap.Value.Track.Length) < endDate.Value; + } + } +} From 6efe24695b2cf930f554fd72cd9c5c51214abf6f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 02:59:11 +0900 Subject: [PATCH 101/328] Add the realtime multiplayer ready button --- .../TestSceneRealtimeReadyButton.cs | 129 ++++++++++++++++++ .../RealtimeReadyButton.cs | 122 +++++++++++++++++ 2 files changed, 251 insertions(+) create mode 100644 osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeReadyButton.cs diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs new file mode 100644 index 0000000000..889c0c0be3 --- /dev/null +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs @@ -0,0 +1,129 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Graphics; +using osu.Framework.Platform; +using osu.Game.Beatmaps; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Rulesets; +using osu.Game.Screens.Multi.RealtimeMultiplayer; +using osu.Game.Tests.Resources; +using osu.Game.Users; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.RealtimeMultiplayer +{ + public class TestSceneRealtimeReadyButton : RealtimeMultiplayerTestScene + { + private RealtimeReadyButton button; + + private BeatmapManager beatmaps; + private RulesetStore rulesets; + + [BackgroundDependencyLoader] + private void load(GameHost host, AudioManager audio) + { + Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); + Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default)); + beatmaps.Import(TestResources.GetTestBeatmapForImport(true)).Wait(); + } + + [SetUp] + public new void Setup() => Schedule(() => + { + var beatmap = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First().Beatmaps.First(); + + Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap); + + Child = button = new RealtimeReadyButton + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(200, 50), + SelectedItem = + { + Value = new PlaylistItem + { + Beatmap = { Value = beatmap }, + Ruleset = { Value = beatmap.Ruleset } + } + } + }; + + Client.AddUser(API.LocalUser.Value); + }); + + [Test] + public void TestToggleStateWhenNotHost() + { + AddStep("add second user as host", () => + { + Client.AddUser(new User { Id = 2, Username = "Another user" }); + Client.TransferHost(2); + }); + + addClickButtonStep(); + AddAssert("user is ready", () => Client.Room?.Users[0].State == MultiplayerUserState.Ready); + + addClickButtonStep(); + AddAssert("user is idle", () => Client.Room?.Users[0].State == MultiplayerUserState.Idle); + } + + [TestCase(true)] + [TestCase(false)] + public void TestToggleStateWhenHost(bool allReady) + { + AddStep("setup", () => + { + Client.TransferHost(Client.Room?.Users[0].UserID ?? 0); + + if (!allReady) + Client.AddUser(new User { Id = 2, Username = "Another user" }); + }); + + addClickButtonStep(); + AddAssert("user is ready", () => Client.Room?.Users[0].State == MultiplayerUserState.Ready); + + addClickButtonStep(); + AddAssert("match started", () => Client.Room?.Users[0].State == MultiplayerUserState.WaitingForLoad); + } + + [Test] + public void TestBecomeHostWhileReady() + { + addClickButtonStep(); + AddStep("make user host", () => Client.TransferHost(Client.Room?.Users[0].UserID ?? 0)); + + addClickButtonStep(); + AddAssert("match started", () => Client.Room?.Users[0].State == MultiplayerUserState.WaitingForLoad); + } + + [Test] + public void TestLoseHostWhileReady() + { + AddStep("setup", () => + { + Client.TransferHost(Client.Room?.Users[0].UserID ?? 0); + Client.AddUser(new User { Id = 2, Username = "Another user" }); + }); + + addClickButtonStep(); + AddStep("transfer host", () => Client.TransferHost(Client.Room?.Users[1].UserID ?? 0)); + + addClickButtonStep(); + AddAssert("match not started", () => Client.Room?.Users[0].State == MultiplayerUserState.Idle); + } + + private void addClickButtonStep() => AddStep("click button", () => + { + InputManager.MoveMouseTo(button); + InputManager.Click(MouseButton.Left); + }); + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeReadyButton.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeReadyButton.cs new file mode 100644 index 0000000000..d52df258ad --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeReadyButton.cs @@ -0,0 +1,122 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics; +using System.Linq; +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Graphics.Backgrounds; +using osu.Game.Online.API; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Screens.Multi.Components; +using osuTK; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer +{ + public class RealtimeReadyButton : RealtimeRoomComposite + { + public Bindable SelectedItem => button.SelectedItem; + + [Resolved] + private IAPIProvider api { get; set; } + + [CanBeNull] + private MultiplayerRoomUser localUser; + + [Resolved] + private OsuColour colours { get; set; } + + private readonly ButtonWithTrianglesExposed button; + + public RealtimeReadyButton() + { + InternalChild = button = new ButtonWithTrianglesExposed + { + RelativeSizeAxes = Axes.Both, + Size = Vector2.One, + Enabled = { Value = true }, + Action = onClick + }; + } + + protected override void OnRoomChanged() + { + base.OnRoomChanged(); + + localUser = Room?.Users.Single(u => u.User?.Id == api.LocalUser.Value.Id); + button.Enabled.Value = Client.Room?.State == MultiplayerRoomState.Open; + updateState(); + } + + private void updateState() + { + if (localUser == null) + return; + + Debug.Assert(Room != null); + + switch (localUser.State) + { + case MultiplayerUserState.Idle: + button.Text = "Ready"; + updateButtonColour(true); + break; + + case MultiplayerUserState.Ready: + if (Room?.Host?.Equals(localUser) == true) + { + button.Text = "Let's go!"; + updateButtonColour(Room.Users.All(u => u.State == MultiplayerUserState.Ready)); + } + else + { + button.Text = "Waiting for host..."; + updateButtonColour(false); + } + + break; + } + } + + private void updateButtonColour(bool green) + { + if (green) + { + button.BackgroundColour = colours.Green; + button.Triangles.ColourDark = colours.Green; + button.Triangles.ColourLight = colours.GreenLight; + } + else + { + button.BackgroundColour = colours.YellowDark; + button.Triangles.ColourDark = colours.YellowDark; + button.Triangles.ColourLight = colours.Yellow; + } + } + + private void onClick() + { + if (localUser == null) + return; + + if (localUser.State == MultiplayerUserState.Idle) + Client.ChangeState(MultiplayerUserState.Ready); + else + { + if (Room?.Host?.Equals(localUser) == true) + Client.StartMatch(); + else + Client.ChangeState(MultiplayerUserState.Idle); + } + } + + private class ButtonWithTrianglesExposed : ReadyButton + { + public new Triangles Triangles => base.Triangles; + } + } +} From cc22efaa6babc4592a06a34f6affb226caea56cb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 03:17:04 +0900 Subject: [PATCH 102/328] Use tcs instead of delay-wait --- osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs index e106dc3a1c..2b7ca189ee 100644 --- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs +++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs @@ -107,25 +107,23 @@ namespace osu.Game.Screens.Multi.Play { Debug.Assert(token != null); - bool completed = false; + var tcs = new TaskCompletionSource(); var request = new SubmitRoomScoreRequest(token.Value, roomId.Value ?? 0, playlistItem.ID, score.ScoreInfo); request.Success += s => { score.ScoreInfo.OnlineScoreID = s.ID; - completed = true; + tcs.SetResult(true); }; request.Failure += e => { Logger.Error(e, "Failed to submit score"); - completed = true; + tcs.SetResult(false); }; api.Queue(request); - - while (!completed) - await Task.Delay(100); + await tcs.Task; return await base.SubmitScore(score); } From 772dd0287e4932e232d4f6c033b7246f740d3541 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 19 Dec 2020 03:32:05 +0900 Subject: [PATCH 103/328] Split submission and import into two methods --- .../Screens/Multi/Play/TimeshiftPlayer.cs | 6 ++-- osu.Game/Screens/Play/Player.cs | 33 ++++++++++++++----- osu.Game/Screens/Play/ReplayPlayer.cs | 3 +- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs index 2b7ca189ee..41dcf61740 100644 --- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs +++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs @@ -103,8 +103,10 @@ namespace osu.Game.Screens.Multi.Play return score; } - protected override async Task SubmitScore(Score score) + protected override async Task SubmitScore(Score score) { + await base.SubmitScore(score); + Debug.Assert(token != null); var tcs = new TaskCompletionSource(); @@ -124,8 +126,6 @@ namespace osu.Game.Screens.Multi.Play api.Queue(request); await tcs.Task; - - return await base.SubmitScore(score); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index c8f1980ab1..a83f0e1b33 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -537,13 +537,23 @@ namespace osu.Game.Screens.Play try { - return await SubmitScore(score); + await SubmitScore(score); } catch (Exception ex) { Logger.Error(ex, "Score submission failed!"); - return score.ScoreInfo; } + + try + { + await ImportScore(score); + } + catch (Exception ex) + { + Logger.Error(ex, "Score import failed!"); + } + + return score.ScoreInfo; }); using (BeginDelayedSequence(RESULTS_DISPLAY_DELAY)) @@ -792,15 +802,15 @@ namespace osu.Game.Screens.Play } /// - /// Submits the player's . + /// Imports the player's to the local database. /// - /// The to submit. - /// The submitted score. - protected virtual async Task SubmitScore(Score score) + /// The to import. + /// The imported score. + protected virtual async Task ImportScore(Score score) { // Replays are already populated and present in the game's database, so should not be re-imported. if (DrawableRuleset.ReplayScore != null) - return score.ScoreInfo; + return; LegacyByteArrayReader replayReader; @@ -810,9 +820,16 @@ namespace osu.Game.Screens.Play replayReader = new LegacyByteArrayReader(stream.ToArray(), "replay.osr"); } - return await scoreManager.Import(score.ScoreInfo, replayReader); + await scoreManager.Import(score.ScoreInfo, replayReader); } + /// + /// Submits the player's . + /// + /// The to submit. + /// The submitted score. + protected virtual Task SubmitScore(Score score) => Task.CompletedTask; + /// /// Creates the for a . /// diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 390d1d1959..a07213cb33 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -37,7 +37,8 @@ namespace osu.Game.Screens.Play return Score; } - protected override Task SubmitScore(Score score) => Task.FromResult(score.ScoreInfo); + // Don't re-import replay scores as they're already present in the database. + protected override Task ImportScore(Score score) => Task.CompletedTask; protected override ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score, false); From f1878eff639bce6d336008cc85e4a4b2c8260bf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 18 Dec 2020 23:45:42 +0100 Subject: [PATCH 104/328] Use yet another solution leveraging padding --- .../Edit/Compose/Components/SelectionBox.cs | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs index 85e86499be..2f4721f63e 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -93,6 +92,7 @@ namespace osu.Game.Screens.Edit.Compose.Components } } + private Container dragHandles; private FillFlowContainer buttons; public const float BORDER_RADIUS = 3; @@ -152,6 +152,12 @@ namespace osu.Game.Screens.Edit.Compose.Components }, } }, + dragHandles = new Container + { + RelativeSizeAxes = Axes.Both, + // ensures that the centres of all drag handles line up with the middle of the selection box border. + Padding = new MarginPadding(BORDER_RADIUS / 2) + }, buttons = new FillFlowContainer { Y = 20, @@ -233,30 +239,14 @@ namespace osu.Game.Screens.Edit.Compose.Components }); } - private void addDragHandle(Anchor anchor) => AddInternal(new SelectionBoxDragHandle + private void addDragHandle(Anchor anchor) => dragHandles.Add(new SelectionBoxDragHandle { Anchor = anchor, - X = dragCircleAdjustments[anchor].X, - Y = dragCircleAdjustments[anchor].Y, HandleDrag = e => OnScale?.Invoke(e.Delta, anchor), OperationStarted = operationStarted, OperationEnded = operationEnded }); - /// - /// Adjust Drag circle to be centered on the center of the border instead of on the edge. - /// - private Dictionary dragCircleAdjustments = new Dictionary(){ - {Anchor.TopLeft, new Vector2(BORDER_RADIUS / 2)}, - {Anchor.CentreLeft, new Vector2(BORDER_RADIUS / 2, 0)}, - {Anchor.BottomLeft, new Vector2(BORDER_RADIUS / 2, -BORDER_RADIUS / 2)}, - {Anchor.TopCentre, new Vector2(0, BORDER_RADIUS / 2)}, - {Anchor.BottomCentre, new Vector2(0, -BORDER_RADIUS / 2)}, - {Anchor.TopRight, new Vector2(-BORDER_RADIUS / 2, BORDER_RADIUS / 2)}, - {Anchor.CentreRight, new Vector2(-BORDER_RADIUS / 2, 0)}, - {Anchor.BottomRight, new Vector2(-BORDER_RADIUS / 2)} - }; - private int activeOperations; private float convertDragEventToAngleOfRotation(DragEvent e) From beaced321153867f0ae9c1d39af5a82848e2ced0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 19 Dec 2020 13:58:56 +0900 Subject: [PATCH 105/328] Remove unnecessary async state machine --- osu.Game/Screens/Play/Player.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index a83f0e1b33..c539dff5d9 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -806,11 +806,11 @@ namespace osu.Game.Screens.Play /// /// The to import. /// The imported score. - protected virtual async Task ImportScore(Score score) + protected virtual Task ImportScore(Score score) { // Replays are already populated and present in the game's database, so should not be re-imported. if (DrawableRuleset.ReplayScore != null) - return; + return Task.CompletedTask; LegacyByteArrayReader replayReader; @@ -820,7 +820,7 @@ namespace osu.Game.Screens.Play replayReader = new LegacyByteArrayReader(stream.ToArray(), "replay.osr"); } - await scoreManager.Import(score.ScoreInfo, replayReader); + return scoreManager.Import(score.ScoreInfo, replayReader); } /// From 28ca21b432627ffb9d8058475bf969143dd71163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 19 Dec 2020 14:50:09 +0100 Subject: [PATCH 106/328] Seal banned method & throw better exception --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index aa668cc4c8..d2d5594edd 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -40,9 +40,9 @@ namespace osu.Game.Screens.Play.HUD return drawable; } - public override void Add(GameplayLeaderboardScore drawable) + public sealed override void Add(GameplayLeaderboardScore drawable) { - throw new InvalidOperationException($"Use {nameof(AddPlayer)} instead."); + throw new NotSupportedException($"Use {nameof(AddPlayer)} instead."); } private void sort() From 22a2c3efdf2f15944e7714da36ea11962345055d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 19 Dec 2020 14:55:58 +0100 Subject: [PATCH 107/328] Add back xmldoc of AddPlayer --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index d2d5594edd..cab1cbd3f1 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -24,6 +24,14 @@ namespace osu.Game.Screens.Play.HUD LayoutEasing = Easing.OutQuint; } + /// + /// Adds a player to the leaderboard. + /// + /// The player. + /// + /// Whether the player should be tracked on the leaderboard. + /// Set to true for the local player or a player whose replay is currently being played. + /// public ILeaderboardScore AddPlayer(User user, bool isTracked) { var drawable = new GameplayLeaderboardScore(user, isTracked) From d392e0f27e2444dfa8a21758a835ddbaef1842e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 19 Dec 2020 15:02:56 +0100 Subject: [PATCH 108/328] Extract shared rank-formatting helper --- osu.Game/Online/Leaderboards/LeaderboardScore.cs | 4 ++-- osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs | 3 +-- osu.Game/Utils/FormatUtils.cs | 8 ++++++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index dcd0cb435a..d8207aa8f4 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -24,8 +24,8 @@ using osu.Game.Scoring; using osu.Game.Users.Drawables; using osuTK; using osuTK.Graphics; -using Humanizer; using osu.Game.Online.API; +using osu.Game.Utils; namespace osu.Game.Online.Leaderboards { @@ -358,7 +358,7 @@ namespace osu.Game.Online.Leaderboards Anchor = Anchor.Centre, Origin = Anchor.Centre, Font = OsuFont.GetFont(size: 20, italics: true), - Text = rank == null ? "-" : rank.Value.ToMetric(decimals: rank < 100000 ? 1 : 0), + Text = rank == null ? "-" : rank.Value.FormatRank() }; } diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index af3cb640bb..9684ae016c 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -49,7 +48,7 @@ namespace osu.Game.Screens.Play.HUD scorePosition = value; if (scorePosition.HasValue) - positionText.Text = $"#{scorePosition.Value.ToMetric(decimals: scorePosition < 100000 ? 1 : 0)}"; + positionText.Text = $"#{scorePosition.Value.FormatRank()}"; positionText.FadeTo(scorePosition.HasValue ? 1 : 0); updateColour(); diff --git a/osu.Game/Utils/FormatUtils.cs b/osu.Game/Utils/FormatUtils.cs index f2ab99f4b7..2578d8d835 100644 --- a/osu.Game/Utils/FormatUtils.cs +++ b/osu.Game/Utils/FormatUtils.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using Humanizer; + namespace osu.Game.Utils { public static class FormatUtils @@ -18,5 +20,11 @@ namespace osu.Game.Utils /// The accuracy to be formatted /// formatted accuracy in percentage public static string FormatAccuracy(this decimal accuracy) => $"{accuracy:0.00}%"; + + /// + /// Formats the supplied rank/leaderboard position in a consistent, simplified way. + /// + /// The rank/position to be formatted. + public static string FormatRank(this int rank) => rank.ToMetric(decimals: rank < 100_000 ? 1 : 0); } } From e2cc401c124b631c8ade6bde8120e71c44c3e2ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 19 Dec 2020 15:05:59 +0100 Subject: [PATCH 109/328] Move BDL above LoadComplete() --- .../Play/HUD/GameplayLeaderboardScore.cs | 106 +++++++++--------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 9684ae016c..d510ea5f8b 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -75,59 +75,6 @@ namespace osu.Game.Screens.Play.HUD Size = new Vector2(EXTENDED_WIDTH, PANEL_HEIGHT); } - protected override void LoadComplete() - { - base.LoadComplete(); - - updateColour(); - FinishTransforms(true); - } - - private const double transition_duration = 500; - - private void updateColour() - { - if (scorePosition == 1) - { - mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, transition_duration, Easing.OutElastic); - panelColour = Color4Extensions.FromHex("7fcc33"); - textColour = Color4.White; - } - else if (trackedPlayer) - { - mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, transition_duration, Easing.OutElastic); - panelColour = Color4Extensions.FromHex("ffd966"); - textColour = Color4Extensions.FromHex("2e576b"); - } - else - { - mainFillContainer.ResizeWidthTo(regular_width, transition_duration, Easing.OutElastic); - panelColour = Color4Extensions.FromHex("3399cc"); - textColour = Color4.White; - } - } - - private Color4 panelColour - { - set - { - mainFillContainer.FadeColour(value, transition_duration, Easing.OutQuint); - centralFill.FadeColour(value, transition_duration, Easing.OutQuint); - } - } - - private Color4 textColour - { - set - { - scoreText.FadeColour(value, 200, Easing.OutQuint); - accuracyText.FadeColour(value, 200, Easing.OutQuint); - comboText.FadeColour(value, 200, Easing.OutQuint); - usernameText.FadeColour(value, 200, Easing.OutQuint); - positionText.FadeColour(value, 200, Easing.OutQuint); - } - } - [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -284,5 +231,58 @@ namespace osu.Game.Screens.Play.HUD Accuracy.BindValueChanged(v => accuracyText.Text = v.NewValue.FormatAccuracy(), true); Combo.BindValueChanged(v => comboText.Text = $"{v.NewValue}x", true); } + + protected override void LoadComplete() + { + base.LoadComplete(); + + updateColour(); + FinishTransforms(true); + } + + private const double transition_duration = 500; + + private void updateColour() + { + if (scorePosition == 1) + { + mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, transition_duration, Easing.OutElastic); + panelColour = Color4Extensions.FromHex("7fcc33"); + textColour = Color4.White; + } + else if (trackedPlayer) + { + mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, transition_duration, Easing.OutElastic); + panelColour = Color4Extensions.FromHex("ffd966"); + textColour = Color4Extensions.FromHex("2e576b"); + } + else + { + mainFillContainer.ResizeWidthTo(regular_width, transition_duration, Easing.OutElastic); + panelColour = Color4Extensions.FromHex("3399cc"); + textColour = Color4.White; + } + } + + private Color4 panelColour + { + set + { + mainFillContainer.FadeColour(value, transition_duration, Easing.OutQuint); + centralFill.FadeColour(value, transition_duration, Easing.OutQuint); + } + } + + private Color4 textColour + { + set + { + scoreText.FadeColour(value, 200, Easing.OutQuint); + accuracyText.FadeColour(value, 200, Easing.OutQuint); + comboText.FadeColour(value, 200, Easing.OutQuint); + usernameText.FadeColour(value, 200, Easing.OutQuint); + positionText.FadeColour(value, 200, Easing.OutQuint); + } + } } } From 315a957a0ca3ad242671e49ec73a27e05e1432b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 19 Dec 2020 15:17:31 +0100 Subject: [PATCH 110/328] Extract constant for text transition duration --- .../Screens/Play/HUD/GameplayLeaderboardScore.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index d510ea5f8b..cff3a1fc66 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -273,15 +273,17 @@ namespace osu.Game.Screens.Play.HUD } } + private const double text_transition_duration = 200; + private Color4 textColour { set { - scoreText.FadeColour(value, 200, Easing.OutQuint); - accuracyText.FadeColour(value, 200, Easing.OutQuint); - comboText.FadeColour(value, 200, Easing.OutQuint); - usernameText.FadeColour(value, 200, Easing.OutQuint); - positionText.FadeColour(value, 200, Easing.OutQuint); + scoreText.FadeColour(value, text_transition_duration, Easing.OutQuint); + accuracyText.FadeColour(value, text_transition_duration, Easing.OutQuint); + comboText.FadeColour(value, text_transition_duration, Easing.OutQuint); + usernameText.FadeColour(value, text_transition_duration, Easing.OutQuint); + positionText.FadeColour(value, text_transition_duration, Easing.OutQuint); } } } From 06a17a9d8cb9c94dd886e2b1e80992436521f42d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 19 Dec 2020 15:18:05 +0100 Subject: [PATCH 111/328] Rename other constant to be distinguishable --- .../Screens/Play/HUD/GameplayLeaderboardScore.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index cff3a1fc66..b93db09f71 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -240,25 +240,25 @@ namespace osu.Game.Screens.Play.HUD FinishTransforms(true); } - private const double transition_duration = 500; + private const double panel_transition_duration = 500; private void updateColour() { if (scorePosition == 1) { - mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, transition_duration, Easing.OutElastic); + mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, panel_transition_duration, Easing.OutElastic); panelColour = Color4Extensions.FromHex("7fcc33"); textColour = Color4.White; } else if (trackedPlayer) { - mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, transition_duration, Easing.OutElastic); + mainFillContainer.ResizeWidthTo(EXTENDED_WIDTH, panel_transition_duration, Easing.OutElastic); panelColour = Color4Extensions.FromHex("ffd966"); textColour = Color4Extensions.FromHex("2e576b"); } else { - mainFillContainer.ResizeWidthTo(regular_width, transition_duration, Easing.OutElastic); + mainFillContainer.ResizeWidthTo(regular_width, panel_transition_duration, Easing.OutElastic); panelColour = Color4Extensions.FromHex("3399cc"); textColour = Color4.White; } @@ -268,8 +268,8 @@ namespace osu.Game.Screens.Play.HUD { set { - mainFillContainer.FadeColour(value, transition_duration, Easing.OutQuint); - centralFill.FadeColour(value, transition_duration, Easing.OutQuint); + mainFillContainer.FadeColour(value, panel_transition_duration, Easing.OutQuint); + centralFill.FadeColour(value, panel_transition_duration, Easing.OutQuint); } } From c738a57b399b5f701fa314fb2dc01de43659c092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 19 Dec 2020 18:48:17 +0100 Subject: [PATCH 112/328] Fix username overflow in new leaderboard design --- osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index b93db09f71..58281debf1 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -176,7 +176,7 @@ namespace osu.Game.Screens.Play.HUD usernameText = new OsuSpriteText { RelativeSizeAxes = Axes.X, - Width = 0.8f, + Width = 0.6f, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Colour = Color4.White, From afa6a869545692f4abed538f7d5e20e70a37a3c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 19 Dec 2020 19:00:05 +0100 Subject: [PATCH 113/328] Remove unnecessary lookup incrementing --- .../Visual/Online/TestSceneCurrentlyPlayingDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs index eaa881b02c..1666c9cde4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs @@ -92,7 +92,7 @@ namespace osu.Game.Tests.Visual.Online protected override Task ComputeValueAsync(int lookup, CancellationToken token = default) => Task.FromResult(new User { - Id = lookup++, + Id = lookup, Username = usernames[lookup % usernames.Length], }); } From ee33c0be93c16b61762edc6d85165fb5ec05fd93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 19 Dec 2020 19:08:29 +0100 Subject: [PATCH 114/328] Extract combo & accuracy ratio calculation helpers --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index f5fb918ba3..10d0cc2865 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -201,8 +201,8 @@ namespace osu.Game.Rulesets.Scoring private double getScore(ScoringMode mode) { return GetScore(mode, maxAchievableCombo, - maxBaseScore > 0 ? baseScore / maxBaseScore : 0, - maxAchievableCombo > 0 ? (double)HighestCombo.Value / maxAchievableCombo : 1, + calculateAccuracyRatio(baseScore), + calculateComboRatio(HighestCombo.Value), scoreResultCounts); } @@ -252,14 +252,17 @@ namespace osu.Game.Rulesets.Scoring computedBaseScore += Judgement.ToNumericResult(pair.Key) * pair.Value; } - double accuracy = maxBaseScore > 0 ? computedBaseScore / maxBaseScore : 0; - double comboRatio = maxAchievableCombo > 0 ? (double)maxCombo / maxAchievableCombo : 1; + double accuracy = calculateAccuracyRatio(computedBaseScore); + double comboRatio = calculateComboRatio(maxCombo); double score = GetScore(mode, maxAchievableCombo, accuracy, comboRatio, scoreResultCounts); return (score, accuracy); } + private double calculateAccuracyRatio(double baseScore) => maxBaseScore > 0 ? baseScore / maxBaseScore : 0; + private double calculateComboRatio(int maxCombo) => maxAchievableCombo > 0 ? (double)maxCombo / maxAchievableCombo : 1; + private double getBonusScore(Dictionary statistics) => statistics.GetOrDefault(HitResult.SmallBonus) * Judgement.SMALL_BONUS_SCORE + statistics.GetOrDefault(HitResult.LargeBonus) * Judgement.LARGE_BONUS_SCORE; From 631a0cea41e7e21b1ab592bc80fa748c733a22d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 19 Dec 2020 21:25:04 +0100 Subject: [PATCH 115/328] Fix intended random factor not being random in test --- .../Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs index 0c8d8ca165..0ca1d9008b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs @@ -109,7 +109,7 @@ namespace osu.Game.Tests.Visual.Gameplay { foreach (var userId in PlayingUsers) { - if (RNG.Next(0, 1) == 1) + if (RNG.NextBool()) continue; if (!lastHeaders.TryGetValue(userId, out var header)) From f827b6c030b3cbde588effdd908b3138eff827fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 19 Dec 2020 21:26:40 +0100 Subject: [PATCH 116/328] Use terser dictionary initialiser syntax --- .../TestSceneMultiplayerGameplayLeaderboard.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs index 0ca1d9008b..e42ddeb35e 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs @@ -116,12 +116,12 @@ namespace osu.Game.Tests.Visual.Gameplay { lastHeaders[userId] = header = new FrameHeader(new ScoreInfo { - Statistics = new Dictionary(new[] + Statistics = new Dictionary { - new KeyValuePair(HitResult.Miss, 0), - new KeyValuePair(HitResult.Meh, 0), - new KeyValuePair(HitResult.Great, 0) - }) + [HitResult.Miss] = 0, + [HitResult.Meh] = 0, + [HitResult.Great] = 0 + } }); } From 4e5064c4f611de5704982e8dbbe670a247814f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 19 Dec 2020 21:31:17 +0100 Subject: [PATCH 117/328] Start accuracy at 1 --- osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index c96f496cd0..12321de442 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -108,7 +108,7 @@ namespace osu.Game.Screens.Play.HUD public IBindableNumber Accuracy => accuracy; - private readonly BindableDouble accuracy = new BindableDouble(); + private readonly BindableDouble accuracy = new BindableDouble(1); public IBindableNumber CurrentCombo => currentCombo; From b87f89986a5b2bb5fd73a43ba04459df84f92417 Mon Sep 17 00:00:00 2001 From: Joehu Date: Sat, 19 Dec 2020 16:57:25 -0800 Subject: [PATCH 118/328] Fix selected item not being highlighted on some setting dropdowns --- .../Settings/Sections/Graphics/LayoutSettings.cs | 3 +-- .../Sections/UserInterface/MainMenuSettings.cs | 11 +++-------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 62dc1dc806..3df2a78552 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -59,11 +59,10 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics Children = new Drawable[] { - windowModeDropdown = new SettingsDropdown + windowModeDropdown = new SettingsEnumDropdown { LabelText = "Screen mode", Current = config.GetBindable(FrameworkSetting.WindowMode), - ItemSource = windowModes, }, resolutionSettingsContainer = new Container { diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs index 598b666642..95e2e9da30 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Configuration; @@ -28,23 +26,20 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface LabelText = "osu! music theme", Current = config.GetBindable(OsuSetting.MenuMusic) }, - new SettingsDropdown + new SettingsEnumDropdown { LabelText = "Intro sequence", Current = config.GetBindable(OsuSetting.IntroSequence), - Items = Enum.GetValues(typeof(IntroSequence)).Cast() }, - new SettingsDropdown + new SettingsEnumDropdown { LabelText = "Background source", Current = config.GetBindable(OsuSetting.MenuBackgroundSource), - Items = Enum.GetValues(typeof(BackgroundSource)).Cast() }, - new SettingsDropdown + new SettingsEnumDropdown { LabelText = "Seasonal backgrounds", Current = config.GetBindable(OsuSetting.SeasonalBackgroundMode), - Items = Enum.GetValues(typeof(SeasonalBackgroundMode)).Cast() } }; } From 5b8e35c98cec02b359eb2cf598713638538d349a Mon Sep 17 00:00:00 2001 From: Joehu Date: Sat, 19 Dec 2020 16:57:42 -0800 Subject: [PATCH 119/328] Make settings dropdown abstract --- osu.Game/Overlays/Settings/SettingsDropdown.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/SettingsDropdown.cs b/osu.Game/Overlays/Settings/SettingsDropdown.cs index 1175ddaab8..e1c6333aa0 100644 --- a/osu.Game/Overlays/Settings/SettingsDropdown.cs +++ b/osu.Game/Overlays/Settings/SettingsDropdown.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings { - public class SettingsDropdown : SettingsItem + public abstract class SettingsDropdown : SettingsItem { protected new OsuDropdown Control => (OsuDropdown)base.Control; From d20eb368f5f86a22bf91a9f8f9838ef862effbc5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 17:36:23 +0900 Subject: [PATCH 120/328] Make return into IEnumerable --- osu.Game/Screens/Multi/Components/RoomManager.cs | 2 +- osu.Game/Screens/Multi/Timeshift/TimeshiftRoomManager.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/Components/RoomManager.cs b/osu.Game/Screens/Multi/Components/RoomManager.cs index 46941dc58e..ffc5e94106 100644 --- a/osu.Game/Screens/Multi/Components/RoomManager.cs +++ b/osu.Game/Screens/Multi/Components/RoomManager.cs @@ -183,6 +183,6 @@ namespace osu.Game.Screens.Multi.Components existing.CopyFrom(room); } - protected abstract RoomPollingComponent[] CreatePollingComponents(); + protected abstract IEnumerable CreatePollingComponents(); } } diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomManager.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomManager.cs index ba96721afc..d21f844e04 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomManager.cs +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomManager.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using osu.Framework.Bindables; using osu.Game.Screens.Multi.Components; @@ -11,7 +12,7 @@ namespace osu.Game.Screens.Multi.Timeshift public readonly Bindable TimeBetweenListingPolls = new Bindable(); public readonly Bindable TimeBetweenSelectionPolls = new Bindable(); - protected override RoomPollingComponent[] CreatePollingComponents() => new RoomPollingComponent[] + protected override IEnumerable CreatePollingComponents() => new RoomPollingComponent[] { new ListingPollingComponent { TimeBetweenPolls = { BindTarget = TimeBetweenListingPolls } }, new SelectionPollingComponent { TimeBetweenPolls = { BindTarget = TimeBetweenSelectionPolls } } From 7c7f15089a6ee06b3e244fc03db8e7114e165cca Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 17:42:23 +0900 Subject: [PATCH 121/328] Make CreateRoomManager return the drawable version --- osu.Game/Screens/Multi/Multiplayer.cs | 8 ++++---- osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index 5f61c5e635..837ccdf2e9 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -46,7 +46,7 @@ namespace osu.Game.Screens.Multi private readonly IBindable isIdle = new BindableBool(); [Cached(Type = typeof(IRoomManager))] - protected IRoomManager RoomManager { get; private set; } + protected RoomManager RoomManager { get; private set; } [Cached] private readonly Bindable selectedRoom = new Bindable(); @@ -81,7 +81,7 @@ namespace osu.Game.Screens.Multi InternalChild = waves = new MultiplayerWaveContainer { RelativeSizeAxes = Axes.Both, - Children = new[] + Children = new Drawable[] { new Box { @@ -136,7 +136,7 @@ namespace osu.Game.Screens.Multi Origin = Anchor.TopRight, Action = () => CreateRoom() }, - (Drawable)(RoomManager = CreateRoomManager()) + RoomManager = CreateRoomManager() } }; @@ -353,7 +353,7 @@ namespace osu.Game.Screens.Multi } } - protected abstract IRoomManager CreateRoomManager(); + protected abstract RoomManager CreateRoomManager(); private class MultiplayerWaveContainer : WaveContainer { diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs index 1ff9c670a8..d2d6a35a2e 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs @@ -3,6 +3,7 @@ using osu.Framework.Logging; using osu.Framework.Screens; +using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Match; @@ -43,6 +44,6 @@ namespace osu.Game.Screens.Multi.Timeshift Logger.Log($"Polling adjusted (listing: {timeshiftManager.TimeBetweenListingPolls.Value}, selection: {timeshiftManager.TimeBetweenSelectionPolls.Value})"); } - protected override IRoomManager CreateRoomManager() => new TimeshiftRoomManager(); + protected override RoomManager CreateRoomManager() => new TimeshiftRoomManager(); } } From d74485704ae9c4a424bfb5fc5780b03e14f3f8be Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 17:46:45 +0900 Subject: [PATCH 122/328] Reset intial rooms received on filter change --- osu.Game/Screens/Multi/Components/ListingPollingComponent.cs | 2 ++ osu.Game/Screens/Multi/Components/RoomPollingComponent.cs | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs b/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs index e22f09779e..ebb3403950 100644 --- a/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs +++ b/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs @@ -25,6 +25,8 @@ namespace osu.Game.Screens.Multi.Components { currentFilter.BindValueChanged(_ => { + InitialRoomsReceived.Value = false; + if (IsLoaded) PollImmediately(); }); diff --git a/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs b/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs index 5430d54644..a81a9540c3 100644 --- a/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs +++ b/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs @@ -21,8 +21,7 @@ namespace osu.Game.Screens.Multi.Components /// public new readonly Bindable TimeBetweenPolls = new Bindable(); - public IBindable InitialRoomsReceived => initialRoomsReceived; - private readonly Bindable initialRoomsReceived = new Bindable(); + public readonly Bindable InitialRoomsReceived = new Bindable(); [Resolved] protected IAPIProvider API { get; private set; } @@ -34,7 +33,7 @@ namespace osu.Game.Screens.Multi.Components protected void NotifyRoomsReceived(List rooms) { - initialRoomsReceived.Value = true; + InitialRoomsReceived.Value = true; RoomsReceived?.Invoke(rooms); } } From 812a1d2b4f43cfb1eade5f22d9290bbe26d0fb27 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 18:03:30 +0900 Subject: [PATCH 123/328] Fix onSuccess callback potentially being called on failure --- .../Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index 4f73ee3865..1a6e976d15 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -62,7 +62,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer Debug.Assert(room.RoomID.Value != null); var joinTask = multiplayerClient.JoinRoom(room); - joinTask.ContinueWith(_ => onSuccess?.Invoke(room)); + joinTask.ContinueWith(_ => onSuccess?.Invoke(room), TaskContinuationOptions.OnlyOnRanToCompletion); joinTask.ContinueWith(t => { PartRoom(); From fb61cdfd417701b4cacfe1aefd4bb374e344c2e5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 18:05:43 +0900 Subject: [PATCH 124/328] Remove unnecessary first-frame polling + address concerns --- .../Screens/Multi/Components/RoomManager.cs | 11 ++++++----- .../RealtimeMultiplayer/RealtimeRoomManager.cs | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Multi/Components/RoomManager.cs b/osu.Game/Screens/Multi/Components/RoomManager.cs index 21bff70b8b..7b419c9efe 100644 --- a/osu.Game/Screens/Multi/Components/RoomManager.cs +++ b/osu.Game/Screens/Multi/Components/RoomManager.cs @@ -27,7 +27,8 @@ namespace osu.Game.Screens.Multi.Components public IBindableList Rooms => rooms; - protected Room JoinedRoom { get; private set; } + protected IBindable JoinedRoom => joinedRoom; + private readonly Bindable joinedRoom = new Bindable(); [Resolved] private RulesetStore rulesets { get; set; } @@ -64,7 +65,7 @@ namespace osu.Game.Screens.Multi.Components req.Success += result => { - JoinedRoom = room; + joinedRoom.Value = room; update(room, result); addRoom(room); @@ -93,7 +94,7 @@ namespace osu.Game.Screens.Multi.Components currentJoinRoomRequest.Success += () => { - JoinedRoom = room; + joinedRoom.Value = room; onSuccess?.Invoke(room); }; @@ -114,8 +115,8 @@ namespace osu.Game.Screens.Multi.Components if (JoinedRoom == null) return; - api.Queue(new PartRoomRequest(JoinedRoom)); - JoinedRoom = null; + api.Queue(new PartRoomRequest(joinedRoom.Value)); + joinedRoom.Value = null; } private readonly HashSet ignoredRooms = new HashSet(); diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index 1a6e976d15..9e3c921d9e 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -30,7 +30,8 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer base.LoadComplete(); isConnected.BindTo(multiplayerClient.IsConnected); - isConnected.BindValueChanged(_ => Schedule(updatePolling), true); + isConnected.BindValueChanged(_ => Schedule(updatePolling)); + JoinedRoom.BindValueChanged(_ => updatePolling()); updatePolling(); } @@ -46,7 +47,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer if (JoinedRoom == null) return; - var joinedRoom = JoinedRoom; + var joinedRoom = JoinedRoom.Value; base.PartRoom(); multiplayerClient.LeaveRoom().Wait(); @@ -77,7 +78,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer ClearRooms(); // Don't poll when not connected or when a room has been joined. - allowPolling.Value = isConnected.Value && JoinedRoom == null; + allowPolling.Value = isConnected.Value && JoinedRoom.Value == null; } protected override RoomPollingComponent[] CreatePollingComponents() => new RoomPollingComponent[] @@ -102,8 +103,11 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer { base.LoadComplete(); - AllowPolling.BindValueChanged(_ => + AllowPolling.BindValueChanged(allowPolling => { + if (!allowPolling.NewValue) + return; + if (IsLoaded) PollImmediately(); }); @@ -120,8 +124,11 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer { base.LoadComplete(); - AllowPolling.BindValueChanged(_ => + AllowPolling.BindValueChanged(allowPolling => { + if (!allowPolling.NewValue) + return; + if (IsLoaded) PollImmediately(); }); From 724e4b83fe266896bef4c10f9a51840cc36a24ae Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 18:19:41 +0900 Subject: [PATCH 125/328] Fix nullability and remove early check --- .../StatefulMultiplayerClient.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index 60960f4929..fe2f4c88f0 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Database; @@ -140,20 +141,14 @@ namespace osu.Game.Online.RealtimeMultiplayer RulesetID = Room.Settings.RulesetID }; - var newSettings = new MultiplayerRoomSettings + ChangeSettings(new MultiplayerRoomSettings { Name = name.GetOr(Room.Settings.Name), BeatmapID = item.GetOr(existingPlaylistItem).BeatmapID, BeatmapChecksum = item.GetOr(existingPlaylistItem).Beatmap.Value.MD5Hash, RulesetID = item.GetOr(existingPlaylistItem).RulesetID, - Mods = item.HasValue ? item.Value!.RequiredMods.Select(m => new APIMod(m)).ToList() : Room.Settings.Mods - }; - - // Make sure there would be a meaningful change in settings. - if (newSettings.Equals(Room.Settings)) - return; - - ChangeSettings(newSettings); + Mods = item.HasValue ? item.Value.AsNonNull().RequiredMods.Select(m => new APIMod(m)).ToList() : Room.Settings.Mods + }); } public abstract Task TransferHost(int userId); From ba4307a74c9bf82503b2e5dad391e3b28442959a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 18:24:13 +0900 Subject: [PATCH 126/328] Directly return task --- .../RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs index bfa8362c7e..de52633c88 100644 --- a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs @@ -106,14 +106,14 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer return Task.CompletedTask; } - public override async Task StartMatch() + public override Task StartMatch() { Debug.Assert(Room != null); foreach (var user in Room.Users.Where(u => u.State == MultiplayerUserState.Ready)) ChangeUserState(user.UserID, MultiplayerUserState.WaitingForLoad); - await ((IMultiplayerClient)this).LoadRequested(); + return ((IMultiplayerClient)this).LoadRequested(); } } } From 1e2b425f3f0b787a747896e485a80a066b1a7429 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 18:24:15 +0900 Subject: [PATCH 127/328] Fix incorrect test name + assertion --- .../RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs index 598641682b..925a83a863 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs @@ -120,7 +120,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer } [Test] - public void TestMultiplayerRoomPartedWhenAPIRoomJoined() + public void TestMultiplayerRoomJoinedWhenAPIRoomJoined() { AddStep("create room manager with a room", () => { @@ -133,7 +133,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer }); }); - AddAssert("multiplayer room parted", () => roomContainer.Client.Room != null); + AddAssert("multiplayer room joined", () => roomContainer.Client.Room != null); } private TestRealtimeRoomManager createRoomManager() From 8b1f5ff4927fa83700a4b22e213fe8ff0914d8d8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 18:25:23 +0900 Subject: [PATCH 128/328] Only instantiate ruleset once --- .../Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index fe2f4c88f0..77dbc16786 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -354,14 +354,14 @@ namespace osu.Game.Online.RealtimeMultiplayer var beatmap = beatmapSet.Beatmaps.Single(b => b.OnlineBeatmapID == settings.BeatmapID); beatmap.MD5Hash = settings.BeatmapChecksum; - var ruleset = rulesets.GetRuleset(settings.RulesetID); - var mods = settings.Mods.Select(m => m.ToMod(ruleset.CreateInstance())); + var ruleset = rulesets.GetRuleset(settings.RulesetID).CreateInstance(); + var mods = settings.Mods.Select(m => m.ToMod(ruleset)); PlaylistItem playlistItem = new PlaylistItem { ID = playlistItemId, Beatmap = { Value = beatmap }, - Ruleset = { Value = ruleset }, + Ruleset = { Value = ruleset.RulesetInfo }, }; playlistItem.RequiredMods.AddRange(mods); From 508f73d94961b8baae97956a3c328b41277ed434 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 18:25:54 +0900 Subject: [PATCH 129/328] Fix up comment --- .../Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index 77dbc16786..35c8a3397e 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -328,7 +328,7 @@ namespace osu.Game.Online.RealtimeMultiplayer if (Room == null) return; - // Update a few instantaneously properties of the room. + // Update a few properties of the room instantaneously. Schedule(() => { if (Room == null) From 0cf078562dada06982d9af80136c02e145d42efa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 18:30:00 +0900 Subject: [PATCH 130/328] Split method up and remove nested scheduling --- .../StatefulMultiplayerClient.cs | 59 +++++++++---------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index 35c8a3397e..8d3b161804 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -15,6 +15,7 @@ using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Online.API; using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.RoomStatuses; using osu.Game.Rulesets; @@ -347,38 +348,36 @@ namespace osu.Game.Online.RealtimeMultiplayer }); var req = new GetBeatmapSetRequest(settings.BeatmapID, BeatmapSetLookupType.BeatmapId); - req.Success += res => - { - var beatmapSet = res.ToBeatmapSet(rulesets); - - var beatmap = beatmapSet.Beatmaps.Single(b => b.OnlineBeatmapID == settings.BeatmapID); - beatmap.MD5Hash = settings.BeatmapChecksum; - - var ruleset = rulesets.GetRuleset(settings.RulesetID).CreateInstance(); - var mods = settings.Mods.Select(m => m.ToMod(ruleset)); - - PlaylistItem playlistItem = new PlaylistItem - { - ID = playlistItemId, - Beatmap = { Value = beatmap }, - Ruleset = { Value = ruleset.RulesetInfo }, - }; - - playlistItem.RequiredMods.AddRange(mods); - - Schedule(() => - { - if (Room == null || !Room.Settings.Equals(settings)) - return; - - Debug.Assert(apiRoom != null); - - apiRoom.Playlist.Clear(); // Clearing should be unnecessary, but here for sanity. - apiRoom.Playlist.Add(playlistItem); - }); - }; + req.Success += res => updatePlaylist(settings, res); api.Queue(req); } + + private void updatePlaylist(MultiplayerRoomSettings settings, APIBeatmapSet onlineSet) + { + if (Room == null || !Room.Settings.Equals(settings)) + return; + + Debug.Assert(apiRoom != null); + + var beatmapSet = onlineSet.ToBeatmapSet(rulesets); + var beatmap = beatmapSet.Beatmaps.Single(b => b.OnlineBeatmapID == settings.BeatmapID); + beatmap.MD5Hash = settings.BeatmapChecksum; + + var ruleset = rulesets.GetRuleset(settings.RulesetID).CreateInstance(); + var mods = settings.Mods.Select(m => m.ToMod(ruleset)); + + PlaylistItem playlistItem = new PlaylistItem + { + ID = playlistItemId, + Beatmap = { Value = beatmap }, + Ruleset = { Value = ruleset.RulesetInfo }, + }; + + playlistItem.RequiredMods.AddRange(mods); + + apiRoom.Playlist.Clear(); // Clearing should be unnecessary, but here for sanity. + apiRoom.Playlist.Add(playlistItem); + } } } From 45107280a00e310402a368a6f9b15050f1bcfd0a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 18:34:54 +0900 Subject: [PATCH 131/328] Make TimeBetweenPolls into a bindable --- .../Components/TestScenePollingComponent.cs | 10 +++---- osu.Game/Online/Chat/ChannelManager.cs | 2 +- osu.Game/Online/PollingComponent.cs | 30 ++++++++----------- .../Multi/Components/RoomPollingComponent.cs | 11 ------- 4 files changed, 19 insertions(+), 34 deletions(-) diff --git a/osu.Game.Tests/Visual/Components/TestScenePollingComponent.cs b/osu.Game.Tests/Visual/Components/TestScenePollingComponent.cs index fb10015ef4..2236f85b92 100644 --- a/osu.Game.Tests/Visual/Components/TestScenePollingComponent.cs +++ b/osu.Game.Tests/Visual/Components/TestScenePollingComponent.cs @@ -61,12 +61,12 @@ namespace osu.Game.Tests.Visual.Components { createPoller(true); - AddStep("set poll interval to 1", () => poller.TimeBetweenPolls = TimePerAction * safety_adjust); + AddStep("set poll interval to 1", () => poller.TimeBetweenPolls.Value = TimePerAction * safety_adjust); checkCount(1); checkCount(2); checkCount(3); - AddStep("set poll interval to 5", () => poller.TimeBetweenPolls = TimePerAction * safety_adjust * 5); + AddStep("set poll interval to 5", () => poller.TimeBetweenPolls.Value = TimePerAction * safety_adjust * 5); checkCount(4); checkCount(4); checkCount(4); @@ -76,7 +76,7 @@ namespace osu.Game.Tests.Visual.Components checkCount(5); checkCount(5); - AddStep("set poll interval to 1", () => poller.TimeBetweenPolls = TimePerAction * safety_adjust); + AddStep("set poll interval to 1", () => poller.TimeBetweenPolls.Value = TimePerAction * safety_adjust); checkCount(6); checkCount(7); } @@ -87,7 +87,7 @@ namespace osu.Game.Tests.Visual.Components { createPoller(false); - AddStep("set poll interval to 1", () => poller.TimeBetweenPolls = TimePerAction * safety_adjust * 5); + AddStep("set poll interval to 1", () => poller.TimeBetweenPolls.Value = TimePerAction * safety_adjust * 5); checkCount(0); skip(); checkCount(0); @@ -141,7 +141,7 @@ namespace osu.Game.Tests.Visual.Components public class TestSlowPoller : TestPoller { - protected override Task Poll() => Task.Delay((int)(TimeBetweenPolls / 2f / Clock.Rate)).ContinueWith(_ => base.Poll()); + protected override Task Poll() => Task.Delay((int)(TimeBetweenPolls.Value / 2f / Clock.Rate)).ContinueWith(_ => base.Poll()); } } } diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 16f46581c5..62ae507419 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -57,7 +57,7 @@ namespace osu.Game.Online.Chat { CurrentChannel.ValueChanged += currentChannelChanged; - HighPollRate.BindValueChanged(enabled => TimeBetweenPolls = enabled.NewValue ? 1000 : 6000, true); + HighPollRate.BindValueChanged(enabled => TimeBetweenPolls.Value = enabled.NewValue ? 1000 : 6000, true); } /// diff --git a/osu.Game/Online/PollingComponent.cs b/osu.Game/Online/PollingComponent.cs index 228f147835..3d19f2ab09 100644 --- a/osu.Game/Online/PollingComponent.cs +++ b/osu.Game/Online/PollingComponent.cs @@ -3,6 +3,7 @@ using System; using System.Threading.Tasks; +using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; using osu.Framework.Threading; @@ -19,22 +20,11 @@ namespace osu.Game.Online private bool pollingActive; - private double timeBetweenPolls; - /// /// The time in milliseconds to wait between polls. /// Setting to zero stops all polling. /// - public double TimeBetweenPolls - { - get => timeBetweenPolls; - set - { - timeBetweenPolls = value; - scheduledPoll?.Cancel(); - pollIfNecessary(); - } - } + public readonly Bindable TimeBetweenPolls = new Bindable(); /// /// @@ -42,7 +32,13 @@ namespace osu.Game.Online /// The initial time in milliseconds to wait between polls. Setting to zero stops all polling. protected PollingComponent(double timeBetweenPolls = 0) { - TimeBetweenPolls = timeBetweenPolls; + TimeBetweenPolls.BindValueChanged(_ => + { + scheduledPoll?.Cancel(); + pollIfNecessary(); + }); + + TimeBetweenPolls.Value = timeBetweenPolls; } protected override void LoadComplete() @@ -60,7 +56,7 @@ namespace osu.Game.Online if (pollingActive) return false; // don't try polling if the time between polls hasn't been set. - if (timeBetweenPolls == 0) return false; + if (TimeBetweenPolls.Value == 0) return false; if (!lastTimePolled.HasValue) { @@ -68,7 +64,7 @@ namespace osu.Game.Online return true; } - if (Time.Current - lastTimePolled.Value > timeBetweenPolls) + if (Time.Current - lastTimePolled.Value > TimeBetweenPolls.Value) { doPoll(); return true; @@ -99,7 +95,7 @@ namespace osu.Game.Online /// public void PollImmediately() { - lastTimePolled = Time.Current - timeBetweenPolls; + lastTimePolled = Time.Current - TimeBetweenPolls.Value; scheduleNextPoll(); } @@ -121,7 +117,7 @@ namespace osu.Game.Online double lastPollDuration = lastTimePolled.HasValue ? Time.Current - lastTimePolled.Value : 0; - scheduledPoll = Scheduler.AddDelayed(doPoll, Math.Max(0, timeBetweenPolls - lastPollDuration)); + scheduledPoll = Scheduler.AddDelayed(doPoll, Math.Max(0, TimeBetweenPolls.Value - lastPollDuration)); } } } diff --git a/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs b/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs index a81a9540c3..ad0720db7b 100644 --- a/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs +++ b/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs @@ -15,22 +15,11 @@ namespace osu.Game.Screens.Multi.Components { public Action> RoomsReceived; - /// - /// The time in milliseconds to wait between polls. - /// Setting to zero stops all polling. - /// - public new readonly Bindable TimeBetweenPolls = new Bindable(); - public readonly Bindable InitialRoomsReceived = new Bindable(); [Resolved] protected IAPIProvider API { get; private set; } - protected RoomPollingComponent() - { - TimeBetweenPolls.BindValueChanged(time => base.TimeBetweenPolls = time.NewValue); - } - protected void NotifyRoomsReceived(List rooms) { InitialRoomsReceived.Value = true; From ce2560b545deea1076c5f6cfd781e9089a360061 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 18:36:31 +0900 Subject: [PATCH 132/328] Extract value into const --- .../Participants/ParticipantPanel.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs index 306a54bfdc..002849a275 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs @@ -142,15 +142,17 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants if (Room == null) return; + const double fade_time = 50; + if (User.State == MultiplayerUserState.Ready) - readyMark.FadeIn(50); + readyMark.FadeIn(fade_time); else - readyMark.FadeOut(50); + readyMark.FadeOut(fade_time); if (Room.Host?.Equals(User) == true) - crown.FadeIn(50); + crown.FadeIn(fade_time); else - crown.FadeOut(50); + crown.FadeOut(fade_time); } public MenuItem[] ContextMenuItems From 19db35501e156ceaaf45f65bb4360dc4d859a68f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 18:44:36 +0900 Subject: [PATCH 133/328] Fix incorrect end date usage in timeshift ready button --- osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs index b6698b195c..ba639c29f4 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs @@ -13,7 +13,7 @@ namespace osu.Game.Screens.Multi.Timeshift public class TimeshiftReadyButton : ReadyButton { [Resolved(typeof(Room), nameof(Room.EndDate))] - private Bindable endDate { get; set; } + private Bindable endDate { get; set; } public TimeshiftReadyButton() { @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Multi.Timeshift { base.Update(); - Enabled.Value = endDate.Value == null || DateTimeOffset.UtcNow.AddSeconds(30).AddMilliseconds(GameBeatmap.Value.Track.Length) < endDate.Value; + Enabled.Value = DateTimeOffset.UtcNow.AddSeconds(30).AddMilliseconds(GameBeatmap.Value.Track.Length) < endDate.Value; } } } From a07a36793a5d90781178b0f94743580359c17973 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 18:44:41 +0900 Subject: [PATCH 134/328] Fix test not working --- .../RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs index 889c0c0be3..1f863028af 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs @@ -97,6 +97,12 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer [Test] public void TestBecomeHostWhileReady() { + AddStep("add host", () => + { + Client.AddUser(new User { Id = 2, Username = "Another user" }); + Client.TransferHost(2); + }); + addClickButtonStep(); AddStep("make user host", () => Client.TransferHost(Client.Room?.Users[0].UserID ?? 0)); From b002c466660535e32e036d322e97e68335c6c497 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 18:49:39 +0900 Subject: [PATCH 135/328] Add number of ready users to button --- .../Screens/Multi/RealtimeMultiplayer/RealtimeReadyButton.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeReadyButton.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeReadyButton.cs index d52df258ad..ea8fb04994 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeReadyButton.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeReadyButton.cs @@ -69,8 +69,9 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer case MultiplayerUserState.Ready: if (Room?.Host?.Equals(localUser) == true) { - button.Text = "Let's go!"; - updateButtonColour(Room.Users.All(u => u.State == MultiplayerUserState.Ready)); + int countReady = Room.Users.Count(u => u.State == MultiplayerUserState.Ready); + button.Text = $"Start match ({countReady} / {Room.Users.Count} ready)"; + updateButtonColour(true); } else { From f876a329b1b4e8b2cbef4effd6ef242e1be1c233 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 22:51:33 +0900 Subject: [PATCH 136/328] Fire-and-forget leave-room request --- .../StatefulMultiplayerClient.cs | 29 +++++++++++++++++-- .../RealtimeRoomManager.cs | 2 +- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index 60960f4929..b846d6732f 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -77,7 +77,9 @@ namespace osu.Game.Online.RealtimeMultiplayer /// The API . public async Task JoinRoom(Room room) { - Debug.Assert(Room == null); + if (Room != null) + throw new InvalidOperationException("Cannot join a multiplayer room while already in one."); + Debug.Assert(room.RoomID.Value != null); apiRoom = room; @@ -166,6 +168,9 @@ namespace osu.Game.Online.RealtimeMultiplayer Task IMultiplayerClient.RoomStateChanged(MultiplayerRoomState state) { + if (Room == null) + return Task.CompletedTask; + Schedule(() => { if (Room == null) @@ -198,6 +203,9 @@ namespace osu.Game.Online.RealtimeMultiplayer async Task IMultiplayerClient.UserJoined(MultiplayerRoomUser user) { + if (Room == null) + return; + await PopulateUser(user); Schedule(() => @@ -213,6 +221,9 @@ namespace osu.Game.Online.RealtimeMultiplayer Task IMultiplayerClient.UserLeft(MultiplayerRoomUser user) { + if (Room == null) + return Task.CompletedTask; + Schedule(() => { if (Room == null) @@ -229,6 +240,9 @@ namespace osu.Game.Online.RealtimeMultiplayer Task IMultiplayerClient.HostChanged(int userId) { + if (Room == null) + return Task.CompletedTask; + Schedule(() => { if (Room == null) @@ -255,6 +269,9 @@ namespace osu.Game.Online.RealtimeMultiplayer Task IMultiplayerClient.UserStateChanged(int userId, MultiplayerUserState state) { + if (Room == null) + return Task.CompletedTask; + Schedule(() => { if (Room == null) @@ -273,6 +290,9 @@ namespace osu.Game.Online.RealtimeMultiplayer Task IMultiplayerClient.LoadRequested() { + if (Room == null) + return Task.CompletedTask; + Schedule(() => { if (Room == null) @@ -286,7 +306,9 @@ namespace osu.Game.Online.RealtimeMultiplayer Task IMultiplayerClient.MatchStarted() { - Debug.Assert(Room != null); + if (Room == null) + return Task.CompletedTask; + var players = Room.Users.Where(u => u.State == MultiplayerUserState.Playing).Select(u => u.UserID).ToList(); Schedule(() => @@ -304,6 +326,9 @@ namespace osu.Game.Online.RealtimeMultiplayer Task IMultiplayerClient.ResultsReady() { + if (Room == null) + return Task.CompletedTask; + Schedule(() => { if (Room == null) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index 4f73ee3865..d2a03da714 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -49,7 +49,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer var joinedRoom = JoinedRoom; base.PartRoom(); - multiplayerClient.LeaveRoom().Wait(); + multiplayerClient.LeaveRoom(); // Todo: This is not the way to do this. Basically when we're the only participant and the room closes, there's no way to know if this is actually the case. RemoveRoom(joinedRoom); From 9d13a5b06a9f90e9cd9a8e489594f03b3d3ec4f0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 22:53:07 +0900 Subject: [PATCH 137/328] Fix potential cross-thread list access --- .../Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index b846d6732f..bf58849e35 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -309,14 +309,12 @@ namespace osu.Game.Online.RealtimeMultiplayer if (Room == null) return Task.CompletedTask; - var players = Room.Users.Where(u => u.State == MultiplayerUserState.Playing).Select(u => u.UserID).ToList(); - Schedule(() => { if (Room == null) return; - PlayingUsers.AddRange(players); + PlayingUsers.AddRange(Room.Users.Where(u => u.State == MultiplayerUserState.Playing).Select(u => u.UserID)); MatchStarted?.Invoke(); }); From c33e693b8e3331af505931950940dc7684b04f41 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 23:05:17 +0900 Subject: [PATCH 138/328] Refactor InitialRoomsReceived to avoid extra bindables --- .../Visual/Multiplayer/TestRoomManager.cs | 2 +- .../Multiplayer/TestSceneMatchSettingsOverlay.cs | 2 +- .../Multiplayer/TestSceneMatchSubScreen.cs | 2 +- .../Multi/Components/ListingPollingComponent.cs | 3 +-- osu.Game/Screens/Multi/Components/RoomManager.cs | 12 ++++++++++-- .../Multi/Components/RoomPollingComponent.cs | 16 ++++++++-------- osu.Game/Screens/Multi/IRoomManager.cs | 2 +- osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs | 2 +- 8 files changed, 24 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs b/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs index 67a53307fc..9dd4aea4bd 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Multiplayer public readonly BindableList Rooms = new BindableList(); - public Bindable InitialRoomsReceived { get; } = new Bindable(true); + public IBindable InitialRoomsReceived { get; } = new Bindable(true); IBindableList IRoomManager.Rooms => Rooms; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs index cbe8cc6137..234374ee2b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs @@ -131,7 +131,7 @@ namespace osu.Game.Tests.Visual.Multiplayer remove { } } - public Bindable InitialRoomsReceived { get; } = new Bindable(true); + public IBindable InitialRoomsReceived { get; } = new Bindable(true); public IBindableList Rooms => null; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs index 65e9893851..bceb6efac1 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs @@ -151,7 +151,7 @@ namespace osu.Game.Tests.Visual.Multiplayer remove => throw new NotImplementedException(); } - public Bindable InitialRoomsReceived { get; } = new Bindable(true); + public IBindable InitialRoomsReceived { get; } = new Bindable(true); public IBindableList Rooms { get; } = new BindableList(); diff --git a/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs b/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs index ebb3403950..dff6c50bf2 100644 --- a/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs +++ b/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs @@ -25,8 +25,7 @@ namespace osu.Game.Screens.Multi.Components { currentFilter.BindValueChanged(_ => { - InitialRoomsReceived.Value = false; - + NotifyRoomsReceived(null); if (IsLoaded) PollImmediately(); }); diff --git a/osu.Game/Screens/Multi/Components/RoomManager.cs b/osu.Game/Screens/Multi/Components/RoomManager.cs index ffc5e94106..382ce52723 100644 --- a/osu.Game/Screens/Multi/Components/RoomManager.cs +++ b/osu.Game/Screens/Multi/Components/RoomManager.cs @@ -23,7 +23,8 @@ namespace osu.Game.Screens.Multi.Components private readonly BindableList rooms = new BindableList(); - public Bindable InitialRoomsReceived { get; } = new Bindable(); + public IBindable InitialRoomsReceived => initialRoomsReceived; + private readonly Bindable initialRoomsReceived = new Bindable(); public IBindableList Rooms => rooms; @@ -44,7 +45,6 @@ namespace osu.Game.Screens.Multi.Components InternalChildren = CreatePollingComponents().Select(p => { - p.InitialRoomsReceived.BindTo(InitialRoomsReceived); p.RoomsReceived = onRoomsReceived; return p; }).ToList(); @@ -122,6 +122,13 @@ namespace osu.Game.Screens.Multi.Components private void onRoomsReceived(List received) { + if (received == null) + { + rooms.Clear(); + initialRoomsReceived.Value = false; + return; + } + // Remove past matches foreach (var r in rooms.ToList()) { @@ -155,6 +162,7 @@ namespace osu.Game.Screens.Multi.Components } RoomsUpdated?.Invoke(); + initialRoomsReceived.Value = true; } /// diff --git a/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs b/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs index ad0720db7b..fbaf9dd930 100644 --- a/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs +++ b/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Game.Online; using osu.Game.Online.API; using osu.Game.Online.Multiplayer; @@ -13,17 +12,18 @@ namespace osu.Game.Screens.Multi.Components { public abstract class RoomPollingComponent : PollingComponent { + /// + /// Invoked when any s have been received from the API. + /// + /// Any s present locally but not returned by this event are to be removed from display. + /// If null, the display of local rooms is reset to an initial state. + /// + /// public Action> RoomsReceived; - public readonly Bindable InitialRoomsReceived = new Bindable(); - [Resolved] protected IAPIProvider API { get; private set; } - protected void NotifyRoomsReceived(List rooms) - { - InitialRoomsReceived.Value = true; - RoomsReceived?.Invoke(rooms); - } + protected void NotifyRoomsReceived(List rooms) => RoomsReceived?.Invoke(rooms); } } diff --git a/osu.Game/Screens/Multi/IRoomManager.cs b/osu.Game/Screens/Multi/IRoomManager.cs index 3d18edcd71..630e3af91c 100644 --- a/osu.Game/Screens/Multi/IRoomManager.cs +++ b/osu.Game/Screens/Multi/IRoomManager.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Multi /// /// Whether an initial listing of rooms has been received. /// - Bindable InitialRoomsReceived { get; } + IBindable InitialRoomsReceived { get; } /// /// All the active s. diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs index a26a64d86d..165a2b201c 100644 --- a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs @@ -27,7 +27,7 @@ namespace osu.Game.Screens.Multi.Lounge protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby(); - private readonly Bindable initialRoomsReceived = new Bindable(); + private readonly IBindable initialRoomsReceived = new Bindable(); private Container content; private LoadingLayer loadingLayer; From 594db76cf3191ae55861633c1efa187794a018c5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 23:10:45 +0900 Subject: [PATCH 139/328] Fix compilation errors --- osu.Game/Screens/Multi/Components/RoomManager.cs | 5 ++--- .../Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Multi/Components/RoomManager.cs b/osu.Game/Screens/Multi/Components/RoomManager.cs index 0bcf3a90c3..276a5a6148 100644 --- a/osu.Game/Screens/Multi/Components/RoomManager.cs +++ b/osu.Game/Screens/Multi/Components/RoomManager.cs @@ -125,8 +125,7 @@ namespace osu.Game.Screens.Multi.Components { if (received == null) { - rooms.Clear(); - initialRoomsReceived.Value = false; + ClearRooms(); return; } @@ -171,7 +170,7 @@ namespace osu.Game.Screens.Multi.Components protected void ClearRooms() { rooms.Clear(); - InitialRoomsReceived.Value = false; + initialRoomsReceived.Value = false; } /// diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index 9e3c921d9e..a50628a5fa 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; using osu.Framework.Allocation; @@ -81,7 +82,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer allowPolling.Value = isConnected.Value && JoinedRoom.Value == null; } - protected override RoomPollingComponent[] CreatePollingComponents() => new RoomPollingComponent[] + protected override IEnumerable CreatePollingComponents() => new RoomPollingComponent[] { listingPollingComponent = new RealtimeListingPollingComponent { From 1d7d8bd6fccba84c32f004caddaf3fb0a3bdfe33 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 23:26:31 +0900 Subject: [PATCH 140/328] Hook up a realtime multiplayer client --- .../RealtimeMultiplayerClient.cs | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs diff --git a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs new file mode 100644 index 0000000000..6f18e1c922 --- /dev/null +++ b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs @@ -0,0 +1,171 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR.Client; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Logging; +using osu.Game.Online.API; + +namespace osu.Game.Online.RealtimeMultiplayer +{ + public class RealtimeMultiplayerClient : StatefulMultiplayerClient + { + private const string endpoint = "https://spectator.ppy.sh/multiplayer"; + + public override IBindable IsConnected => isConnected; + + private readonly Bindable isConnected = new Bindable(); + private readonly IBindable apiState = new Bindable(); + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + private HubConnection? connection; + + [BackgroundDependencyLoader] + private void load() + { + apiState.BindTo(api.State); + apiState.BindValueChanged(apiStateChanged, true); + } + + private void apiStateChanged(ValueChangedEvent state) + { + switch (state.NewValue) + { + case APIState.Failing: + case APIState.Offline: + connection?.StopAsync(); + connection = null; + break; + + case APIState.Online: + Task.Run(Connect); + break; + } + } + + protected virtual async Task Connect() + { + if (connection != null) + return; + + connection = new HubConnectionBuilder() + .WithUrl(endpoint, options => + { + options.Headers.Add("Authorization", $"Bearer {api.AccessToken}"); + }) + .AddNewtonsoftJsonProtocol(options => { options.PayloadSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; }) + .Build(); + + // this is kind of SILLY + // https://github.com/dotnet/aspnetcore/issues/15198 + connection.On(nameof(IMultiplayerClient.RoomStateChanged), ((IMultiplayerClient)this).RoomStateChanged); + connection.On(nameof(IMultiplayerClient.UserJoined), ((IMultiplayerClient)this).UserJoined); + connection.On(nameof(IMultiplayerClient.UserLeft), ((IMultiplayerClient)this).UserLeft); + connection.On(nameof(IMultiplayerClient.HostChanged), ((IMultiplayerClient)this).HostChanged); + connection.On(nameof(IMultiplayerClient.SettingsChanged), ((IMultiplayerClient)this).SettingsChanged); + connection.On(nameof(IMultiplayerClient.UserStateChanged), ((IMultiplayerClient)this).UserStateChanged); + connection.On(nameof(IMultiplayerClient.LoadRequested), ((IMultiplayerClient)this).LoadRequested); + connection.On(nameof(IMultiplayerClient.MatchStarted), ((IMultiplayerClient)this).MatchStarted); + connection.On(nameof(IMultiplayerClient.ResultsReady), ((IMultiplayerClient)this).ResultsReady); + + connection.Closed += async ex => + { + isConnected.Value = false; + + if (ex != null) + { + Logger.Log($"Multiplayer client lost connection: {ex}", LoggingTarget.Network); + await tryUntilConnected(); + } + }; + + await tryUntilConnected(); + + async Task tryUntilConnected() + { + Logger.Log("Multiplayer client connecting...", LoggingTarget.Network); + + while (api.State.Value == APIState.Online) + { + try + { + // reconnect on any failure + await connection.StartAsync(); + Logger.Log("Multiplayer client connected!", LoggingTarget.Network); + + // Success. + isConnected.Value = true; + break; + } + catch (Exception e) + { + Logger.Log($"Multiplayer client connection error: {e}", LoggingTarget.Network); + await Task.Delay(5000); + } + } + } + } + + protected override Task JoinRoom(long roomId) + { + if (!isConnected.Value) + return Task.FromCanceled(CancellationToken.None); + + return connection.InvokeAsync(nameof(IMultiplayerServer.JoinRoom), roomId); + } + + public override async Task LeaveRoom() + { + if (!isConnected.Value) + return; + + if (Room == null) + return; + + await base.LeaveRoom(); + await connection.InvokeAsync(nameof(IMultiplayerServer.LeaveRoom)); + } + + public override Task TransferHost(int userId) + { + if (!isConnected.Value) + return Task.CompletedTask; + + return connection.InvokeAsync(nameof(IMultiplayerServer.TransferHost), userId); + } + + public override Task ChangeSettings(MultiplayerRoomSettings settings) + { + if (!isConnected.Value) + return Task.CompletedTask; + + return connection.InvokeAsync(nameof(IMultiplayerServer.ChangeSettings), settings); + } + + public override Task ChangeState(MultiplayerUserState newState) + { + if (!isConnected.Value) + return Task.CompletedTask; + + return connection.InvokeAsync(nameof(IMultiplayerServer.ChangeState), newState); + } + + public override Task StartMatch() + { + if (!isConnected.Value) + return Task.CompletedTask; + + return connection.InvokeAsync(nameof(IMultiplayerServer.StartMatch)); + } + } +} From 455a84c73fb616e89ec76c8af8cb553ed61d3688 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 23:32:57 +0900 Subject: [PATCH 141/328] Add realtime multiplayer screen --- .../Multi/Lounge/Components/DrawableRoom.cs | 2 +- osu.Game/Screens/Multi/Multiplayer.cs | 12 +++- .../RealtimeMultiplayer.cs | 65 +++++++++++++++++++ 3 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs diff --git a/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs index 01a85382e4..56116b219a 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs @@ -242,7 +242,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components { new OsuMenuItem("Create copy", MenuItemType.Standard, () => { - multiplayer?.CreateRoom(Room.CreateCopy()); + multiplayer?.OpenNewRoom(Room.CreateCopy()); }) }; } diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index 837ccdf2e9..027fedaad6 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -134,7 +134,7 @@ namespace osu.Game.Screens.Multi { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Action = () => CreateRoom() + Action = () => OpenNewRoom() }, RoomManager = CreateRoomManager() } @@ -264,10 +264,16 @@ namespace osu.Game.Screens.Multi } /// - /// Create a new room. + /// Creates and opens the newly-created room. /// /// An optional template to use when creating the room. - public void CreateRoom(Room room = null) => loungeSubScreen.Open(room ?? new Room { Name = { Value = $"{api.LocalUser}'s awesome room" } }); + public void OpenNewRoom(Room room = null) => loungeSubScreen.Open(room ?? CreateNewRoom()); + + /// + /// Creates a new room. + /// + /// The created . + protected virtual Room CreateNewRoom() => new Room { Name = { Value = $"{api.LocalUser}'s awesome room" } }; private void beginHandlingTrack() { diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs new file mode 100644 index 0000000000..075c552437 --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs @@ -0,0 +1,65 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Logging; +using osu.Framework.Screens; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.Multi.Lounge; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer +{ + public class RealtimeMultiplayer : Multiplayer + { + [Resolved] + private StatefulMultiplayerClient client { get; set; } + + public override void OnResuming(IScreen last) + { + base.OnResuming(last); + + if (client.Room != null) + client.ChangeState(MultiplayerUserState.Idle); + } + + protected override void UpdatePollingRate(bool isIdle) + { + var timeshiftManager = (RealtimeRoomManager)RoomManager; + + if (!this.IsCurrentScreen()) + { + timeshiftManager.TimeBetweenListingPolls.Value = 0; + timeshiftManager.TimeBetweenSelectionPolls.Value = 0; + } + else + { + switch (CurrentSubScreen) + { + case LoungeSubScreen _: + timeshiftManager.TimeBetweenListingPolls.Value = isIdle ? 120000 : 15000; + timeshiftManager.TimeBetweenSelectionPolls.Value = isIdle ? 120000 : 15000; + break; + + // Don't poll inside the match or anywhere else. + default: + timeshiftManager.TimeBetweenListingPolls.Value = 0; + timeshiftManager.TimeBetweenSelectionPolls.Value = 0; + break; + } + } + + Logger.Log($"Polling adjusted (listing: {timeshiftManager.TimeBetweenListingPolls.Value}, selection: {timeshiftManager.TimeBetweenSelectionPolls.Value})"); + } + + protected override Room CreateNewRoom() + { + var room = base.CreateNewRoom(); + room.Category.Value = RoomCategory.Realtime; + return room; + } + + protected override RoomManager CreateRoomManager() => new RealtimeRoomManager(); + } +} From b9e4a7196e454743a96736c597b6749975e197eb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 23:36:56 +0900 Subject: [PATCH 142/328] Add realtime lounge subscreen --- ...s => TestSceneTimeshiftLoungeSubScreen.cs} | 5 ++-- .../Screens/Multi/Lounge/LoungeSubScreen.cs | 25 ++++++++++--------- osu.Game/Screens/Multi/Multiplayer.cs | 4 ++- .../RealtimeFilterControl.cs | 17 +++++++++++++ .../RealtimeLoungeSubScreen.cs | 13 ++++++++++ .../RealtimeMultiplayer.cs | 2 ++ .../Timeshift/TimeshiftLoungeSubScreen.cs | 13 ++++++++++ .../Multi/Timeshift/TimeshiftMultiplayer.cs | 2 ++ 8 files changed, 66 insertions(+), 15 deletions(-) rename osu.Game.Tests/Visual/Multiplayer/{TestSceneLoungeSubScreen.cs => TestSceneTimeshiftLoungeSubScreen.cs} (92%) create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeFilterControl.cs create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs create mode 100644 osu.Game/Screens/Multi/Timeshift/TimeshiftLoungeSubScreen.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftLoungeSubScreen.cs similarity index 92% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeSubScreen.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftLoungeSubScreen.cs index 68987127d2..73afd65d6d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftLoungeSubScreen.cs @@ -10,10 +10,11 @@ using osu.Framework.Testing; using osu.Game.Graphics.Containers; using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Lounge.Components; +using osu.Game.Screens.Multi.Timeshift; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneLoungeSubScreen : RoomManagerTestScene + public class TestSceneTimeshiftLoungeSubScreen : RoomManagerTestScene { private LoungeSubScreen loungeScreen; @@ -26,7 +27,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { base.SetUpSteps(); - AddStep("push screen", () => LoadScreen(loungeScreen = new LoungeSubScreen + AddStep("push screen", () => LoadScreen(loungeScreen = new TimeshiftLoungeSubScreen { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs index 165a2b201c..26e351fc2b 100644 --- a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs @@ -19,16 +19,15 @@ using osu.Game.Users; namespace osu.Game.Screens.Multi.Lounge { [Cached] - public class LoungeSubScreen : MultiplayerSubScreen + public abstract class LoungeSubScreen : MultiplayerSubScreen { public override string Title => "Lounge"; - protected FilterControl Filter; - protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby(); private readonly IBindable initialRoomsReceived = new Bindable(); + private FilterControl filter; private Container content; private LoadingLayer loadingLayer; @@ -78,11 +77,11 @@ namespace osu.Game.Screens.Multi.Lounge }, }, }, - Filter = new TimeshiftFilterControl + filter = CreateFilterControl().With(d => { - RelativeSizeAxes = Axes.X, - Height = 80, - }, + d.RelativeSizeAxes = Axes.X; + d.Height = 80; + }) }; // scroll selected room into view on selection. @@ -108,7 +107,7 @@ namespace osu.Game.Screens.Multi.Lounge content.Padding = new MarginPadding { - Top = Filter.DrawHeight, + Top = filter.DrawHeight, Left = WaveOverlayContainer.WIDTH_PADDING - DrawableRoom.SELECTION_BORDER_WIDTH + HORIZONTAL_OVERFLOW_PADDING, Right = WaveOverlayContainer.WIDTH_PADDING + HORIZONTAL_OVERFLOW_PADDING, }; @@ -116,7 +115,7 @@ namespace osu.Game.Screens.Multi.Lounge protected override void OnFocus(FocusEvent e) { - Filter.TakeFocus(); + filter.TakeFocus(); } public override void OnEntering(IScreen last) @@ -140,19 +139,19 @@ namespace osu.Game.Screens.Multi.Lounge private void onReturning() { - Filter.HoldFocus = true; + filter.HoldFocus = true; } public override bool OnExiting(IScreen next) { - Filter.HoldFocus = false; + filter.HoldFocus = false; return base.OnExiting(next); } public override void OnSuspending(IScreen next) { base.OnSuspending(next); - Filter.HoldFocus = false; + filter.HoldFocus = false; } private void joinRequested(Room room) @@ -195,5 +194,7 @@ namespace osu.Game.Screens.Multi.Lounge this.Push(new MatchSubScreen(room)); } + + protected abstract FilterControl CreateFilterControl(); } } diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index 027fedaad6..b37ee45b84 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -143,7 +143,7 @@ namespace osu.Game.Screens.Multi screenStack.ScreenPushed += screenPushed; screenStack.ScreenExited += screenExited; - screenStack.Push(loungeSubScreen = new LoungeSubScreen()); + screenStack.Push(loungeSubScreen = CreateLounge()); } private readonly IBindable apiState = new Bindable(); @@ -361,6 +361,8 @@ namespace osu.Game.Screens.Multi protected abstract RoomManager CreateRoomManager(); + protected abstract LoungeSubScreen CreateLounge(); + private class MultiplayerWaveContainer : WaveContainer { protected override bool StartHidden => true; diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeFilterControl.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeFilterControl.cs new file mode 100644 index 0000000000..acd9a057e3 --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeFilterControl.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Screens.Multi.Lounge.Components; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer +{ + public class RealtimeFilterControl : FilterControl + { + protected override FilterCriteria CreateCriteria() + { + var criteria = base.CreateCriteria(); + criteria.Category = "realtime"; + return criteria; + } + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs new file mode 100644 index 0000000000..ed187e436f --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs @@ -0,0 +1,13 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Screens.Multi.Lounge; +using osu.Game.Screens.Multi.Lounge.Components; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer +{ + public class RealtimeLoungeSubScreen : LoungeSubScreen + { + protected override FilterControl CreateFilterControl() => new RealtimeFilterControl(); + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs index 075c552437..6455701d31 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs @@ -61,5 +61,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer } protected override RoomManager CreateRoomManager() => new RealtimeRoomManager(); + + protected override LoungeSubScreen CreateLounge() => new RealtimeLoungeSubScreen(); } } diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftLoungeSubScreen.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftLoungeSubScreen.cs new file mode 100644 index 0000000000..70fb1aef1d --- /dev/null +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftLoungeSubScreen.cs @@ -0,0 +1,13 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Screens.Multi.Lounge; +using osu.Game.Screens.Multi.Lounge.Components; + +namespace osu.Game.Screens.Multi.Timeshift +{ + public class TimeshiftLoungeSubScreen : LoungeSubScreen + { + protected override FilterControl CreateFilterControl() => new TimeshiftFilterControl(); + } +} diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs index d2d6a35a2e..a38b2a931e 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs @@ -45,5 +45,7 @@ namespace osu.Game.Screens.Multi.Timeshift } protected override RoomManager CreateRoomManager() => new TimeshiftRoomManager(); + + protected override LoungeSubScreen CreateLounge() => new TimeshiftLoungeSubScreen(); } } From a1ba4b6979f0a0029855bfb30b3215499d6905a1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 23:40:19 +0900 Subject: [PATCH 143/328] Split MatchSubScreen into abstract component + timeshift implementation --- ....cs => TestSceneTimeshiftRoomSubScreen.cs} | 12 +-- .../Screens/Multi/Lounge/LoungeSubScreen.cs | 4 +- osu.Game/Screens/Multi/Match/RoomSubScreen.cs | 74 ++++++++++++++++ osu.Game/Screens/Multi/Multiplayer.cs | 4 +- .../Multi/Timeshift/TimeshiftMultiplayer.cs | 2 +- .../TimeshiftRoomSubScreen.cs} | 88 +++---------------- 6 files changed, 97 insertions(+), 87 deletions(-) rename osu.Game.Tests/Visual/Multiplayer/{TestSceneMatchSubScreen.cs => TestSceneTimeshiftRoomSubScreen.cs} (94%) create mode 100644 osu.Game/Screens/Multi/Match/RoomSubScreen.cs rename osu.Game/Screens/Multi/{Match/MatchSubScreen.cs => Timeshift/TimeshiftRoomSubScreen.cs} (78%) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs similarity index 94% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs index bceb6efac1..f56f78ce89 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs @@ -16,15 +16,15 @@ using osu.Game.Online.Multiplayer; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Multi; -using osu.Game.Screens.Multi.Match; using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.Multi.Timeshift; using osu.Game.Tests.Beatmaps; using osu.Game.Users; using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMatchSubScreen : MultiplayerTestScene + public class TestSceneTimeshiftRoomSubScreen : MultiplayerTestScene { protected override bool UseOnlineAPI => true; @@ -34,7 +34,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private BeatmapManager manager; private RulesetStore rulesets; - private TestMatchSubScreen match; + private TestTimeshiftRoomSubScreen match; [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Multiplayer [SetUpSteps] public void SetupSteps() { - AddStep("load match", () => LoadScreen(match = new TestMatchSubScreen(Room))); + AddStep("load match", () => LoadScreen(match = new TestTimeshiftRoomSubScreen(Room))); AddUntilStep("wait for load", () => match.IsCurrentScreen()); } @@ -131,13 +131,13 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("match has original beatmap", () => match.Beatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty.CircleSize != 1); } - private class TestMatchSubScreen : MatchSubScreen + private class TestTimeshiftRoomSubScreen : TimeshiftRoomSubScreen { public new Bindable SelectedItem => base.SelectedItem; public new Bindable Beatmap => base.Beatmap; - public TestMatchSubScreen(Room room) + public TestTimeshiftRoomSubScreen(Room room) : base(room) { } diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs index 26e351fc2b..f4591d089e 100644 --- a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Overlays; using osu.Game.Screens.Multi.Lounge.Components; -using osu.Game.Screens.Multi.Match; +using osu.Game.Screens.Multi.Timeshift; using osu.Game.Users; namespace osu.Game.Screens.Multi.Lounge @@ -192,7 +192,7 @@ namespace osu.Game.Screens.Multi.Lounge selectedRoom.Value = room; - this.Push(new MatchSubScreen(room)); + this.Push(new TimeshiftRoomSubScreen(room)); } protected abstract FilterControl CreateFilterControl(); diff --git a/osu.Game/Screens/Multi/Match/RoomSubScreen.cs b/osu.Game/Screens/Multi/Match/RoomSubScreen.cs new file mode 100644 index 0000000000..0cc9a4354e --- /dev/null +++ b/osu.Game/Screens/Multi/Match/RoomSubScreen.cs @@ -0,0 +1,74 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Screens; +using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Screens.Multi.Match +{ + [Cached(typeof(IPreviewTrackOwner))] + public abstract class RoomSubScreen : MultiplayerSubScreen, IPreviewTrackOwner + { + protected readonly Bindable SelectedItem = new Bindable(); + + public override bool DisallowExternalBeatmapRulesetChanges => true; + + [Resolved(typeof(Room), nameof(Room.Playlist))] + protected BindableList Playlist { get; private set; } + + [Resolved] + private BeatmapManager beatmapManager { get; set; } + + private IBindable> managerUpdated; + + protected override void LoadComplete() + { + base.LoadComplete(); + + SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(selectedItemChanged)); + SelectedItem.Value = Playlist.FirstOrDefault(); + + managerUpdated = beatmapManager.ItemUpdated.GetBoundCopy(); + managerUpdated.BindValueChanged(beatmapUpdated); + } + + private void selectedItemChanged() + { + updateWorkingBeatmap(); + + var item = SelectedItem.Value; + + Mods.Value = item?.RequiredMods?.ToArray() ?? Array.Empty(); + + if (item?.Ruleset != null) + Ruleset.Value = item.Ruleset.Value; + } + + private void beatmapUpdated(ValueChangedEvent> weakSet) => Schedule(updateWorkingBeatmap); + + private void updateWorkingBeatmap() + { + var beatmap = SelectedItem.Value?.Beatmap.Value; + + // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info + var localBeatmap = beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineBeatmapID); + + Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); + } + + public override bool OnExiting(IScreen next) + { + RoomManager?.PartRoom(); + Mods.Value = Array.Empty(); + + return base.OnExiting(next); + } + } +} diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index b37ee45b84..eae779421d 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -308,7 +308,7 @@ namespace osu.Game.Screens.Multi headerBackground.MoveToX(0, MultiplayerSubScreen.X_MOVE_DURATION, Easing.OutQuint); break; - case MatchSubScreen _: + case RoomSubScreen _: header.ResizeHeightTo(135, MultiplayerSubScreen.APPEAR_DURATION, Easing.OutQuint); headerBackground.MoveToX(-MultiplayerSubScreen.X_SHIFT, MultiplayerSubScreen.X_MOVE_DURATION, Easing.OutQuint); break; @@ -330,7 +330,7 @@ namespace osu.Game.Screens.Multi private void updateTrack(ValueChangedEvent _ = null) { - if (screenStack.CurrentScreen is MatchSubScreen) + if (screenStack.CurrentScreen is RoomSubScreen) { var track = Beatmap.Value?.Track; diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs index a38b2a931e..2ea4857799 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Multi.Timeshift timeshiftManager.TimeBetweenSelectionPolls.Value = isIdle ? 120000 : 15000; break; - case MatchSubScreen _: + case RoomSubScreen _: timeshiftManager.TimeBetweenListingPolls.Value = 0; timeshiftManager.TimeBetweenSelectionPolls.Value = isIdle ? 30000 : 5000; break; diff --git a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs similarity index 78% rename from osu.Game/Screens/Multi/Match/MatchSubScreen.cs rename to osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs index 2f8aad4e65..433a980d60 100644 --- a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs @@ -1,7 +1,6 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; @@ -9,28 +8,21 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Screens; -using osu.Game.Audio; -using osu.Game.Beatmaps; using osu.Game.Online.API; using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.GameTypes; -using osu.Game.Rulesets.Mods; using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.Multi.Match; using osu.Game.Screens.Multi.Match.Components; using osu.Game.Screens.Multi.Play; using osu.Game.Screens.Multi.Ranking; using osu.Game.Screens.Play; using osu.Game.Screens.Select; using osu.Game.Users; -using Footer = osu.Game.Screens.Multi.Match.Components.Footer; -namespace osu.Game.Screens.Multi.Match +namespace osu.Game.Screens.Multi.Timeshift { - [Cached(typeof(IPreviewTrackOwner))] - public class MatchSubScreen : MultiplayerSubScreen, IPreviewTrackOwner + public class TimeshiftRoomSubScreen : RoomSubScreen { - public override bool DisallowExternalBeatmapRulesetChanges => true; - public override string Title { get; } public override string ShortTitle => "room"; @@ -38,27 +30,15 @@ namespace osu.Game.Screens.Multi.Match [Resolved(typeof(Room), nameof(Room.RoomID))] private Bindable roomId { get; set; } - [Resolved(typeof(Room), nameof(Room.Type))] - private Bindable type { get; set; } - - [Resolved(typeof(Room), nameof(Room.Playlist))] - private BindableList playlist { get; set; } - - [Resolved] - private BeatmapManager beatmapManager { get; set; } - [Resolved(canBeNull: true)] private Multiplayer multiplayer { get; set; } - protected readonly Bindable SelectedItem = new Bindable(); - private MatchSettingsOverlay settingsOverlay; private MatchLeaderboard leaderboard; - private IBindable> managerUpdated; private OverlinedHeader participantsHeader; - public MatchSubScreen(Room room) + public TimeshiftRoomSubScreen(Room room) { Title = room.RoomID.Value == null ? "New room" : room.Name.Value; Activity.Value = new UserActivity.InLobby(room); @@ -96,7 +76,7 @@ namespace osu.Game.Screens.Multi.Match }, Content = new[] { - new Drawable[] { new Components.Header() }, + new Drawable[] { new Match.Components.Header() }, new Drawable[] { participantsHeader = new OverlinedHeader("Participants") @@ -141,7 +121,7 @@ namespace osu.Game.Screens.Multi.Match new DrawableRoomPlaylistWithResults { RelativeSizeAxes = Axes.Both, - Items = { BindTarget = playlist }, + Items = { BindTarget = Playlist }, SelectedItem = { BindTarget = SelectedItem }, RequestShowResults = item => { @@ -195,7 +175,7 @@ namespace osu.Game.Screens.Multi.Match }, new Drawable[] { - new Footer + new Match.Components.Footer { OnStart = onStart, SelectedItem = { BindTarget = SelectedItem } @@ -234,61 +214,17 @@ namespace osu.Game.Screens.Multi.Match // Set the first playlist item. // This is scheduled since updating the room and playlist may happen in an arbitrary order (via Room.CopyFrom()). - Schedule(() => SelectedItem.Value = playlist.FirstOrDefault()); + Schedule(() => SelectedItem.Value = Playlist.FirstOrDefault()); } }, true); - - SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(selectedItemChanged)); - SelectedItem.Value = playlist.FirstOrDefault(); - - managerUpdated = beatmapManager.ItemUpdated.GetBoundCopy(); - managerUpdated.BindValueChanged(beatmapUpdated); - } - - public override bool OnExiting(IScreen next) - { - RoomManager?.PartRoom(); - Mods.Value = Array.Empty(); - - return base.OnExiting(next); - } - - private void selectedItemChanged() - { - updateWorkingBeatmap(); - - var item = SelectedItem.Value; - - Mods.Value = item?.RequiredMods?.ToArray() ?? Array.Empty(); - - if (item?.Ruleset != null) - Ruleset.Value = item.Ruleset.Value; - } - - private void beatmapUpdated(ValueChangedEvent> weakSet) => Schedule(updateWorkingBeatmap); - - private void updateWorkingBeatmap() - { - var beatmap = SelectedItem.Value?.Beatmap.Value; - - // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info - var localBeatmap = beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineBeatmapID); - - Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); } private void onStart() { - switch (type.Value) + multiplayer?.Push(new PlayerLoader(() => new TimeshiftPlayer(SelectedItem.Value) { - default: - case GameTypeTimeshift _: - multiplayer?.Push(new PlayerLoader(() => new TimeshiftPlayer(SelectedItem.Value) - { - Exited = () => leaderboard.RefreshScores() - })); - break; - } + Exited = () => leaderboard.RefreshScores() + })); } } } From a25cd910f83fe6ed012fdf63e1f2a20245ac625d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 14 Dec 2020 22:20:35 +0100 Subject: [PATCH 144/328] Prepare base DHO for HO application --- .../Objects/Drawables/DrawableTaikoHitObject.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index cf3aa69b6f..6041eccb51 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; -using osu.Framework.Allocation; +using JetBrains.Annotations; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private readonly Container nonProxiedContent; - protected DrawableTaikoHitObject(TaikoHitObject hitObject) + protected DrawableTaikoHitObject([CanBeNull] TaikoHitObject hitObject) : base(hitObject) { AddRangeInternal(new[] @@ -113,25 +113,23 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { public override Vector2 OriginPosition => new Vector2(DrawHeight / 2); - public new TObject HitObject; + public new TObject HitObject => (TObject)base.HitObject; protected Vector2 BaseSize; protected SkinnableDrawable MainPiece; - protected DrawableTaikoHitObject(TObject hitObject) + protected DrawableTaikoHitObject([CanBeNull] TObject hitObject) : base(hitObject) { - HitObject = hitObject; - Anchor = Anchor.CentreLeft; Origin = Anchor.Custom; RelativeSizeAxes = Axes.Both; } - [BackgroundDependencyLoader] - private void load() + protected override void OnApply() { + base.OnApply(); RecreatePieces(); } From 7b350fc8e5f61644d63700c236fe2c447eb39efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 14 Dec 2020 22:27:45 +0100 Subject: [PATCH 145/328] Prepare strongable DHO for HO application --- .../DrawableTaikoStrongableHitObject.cs | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs index af3e94d9c6..62f338ca91 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using osu.Framework.Allocation; +using JetBrains.Annotations; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; using osu.Game.Audio; @@ -16,28 +16,38 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables where TObject : TaikoStrongableHitObject where TStrongNestedObject : StrongNestedHitObject { - private readonly Bindable isStrong; + private readonly Bindable isStrong = new BindableBool(); private readonly Container strongHitContainer; - protected DrawableTaikoStrongableHitObject(TObject hitObject) + protected DrawableTaikoStrongableHitObject([CanBeNull] TObject hitObject) : base(hitObject) { - isStrong = HitObject.IsStrongBindable.GetBoundCopy(); - AddInternal(strongHitContainer = new Container()); } - [BackgroundDependencyLoader] - private void load() + protected override void OnApply() { + isStrong.BindTo(HitObject.IsStrongBindable); isStrong.BindValueChanged(_ => { - // will overwrite samples, should only be called on change. + // will overwrite samples, should only be called on subsequent changes + // after the initial application. updateSamplesFromStrong(); RecreatePieces(); }); + + base.OnApply(); + } + + protected override void OnFree() + { + base.OnFree(); + + isStrong.UnbindFrom(HitObject.IsStrongBindable); + // ensure the next application does not accidentally overwrite samples. + isStrong.UnbindEvents(); } private HitSampleInfo[] getStrongSamples() => HitObject.Samples.Where(s => s.Name == HitSampleInfo.HIT_FINISH).ToArray(); From a31e8d137f3c0bf2926e603a9ef294eb0f8f47c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 14 Dec 2020 22:53:00 +0100 Subject: [PATCH 146/328] Add guard when clearing samples --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 644c67ea59..da6da0ea97 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -303,7 +303,8 @@ namespace osu.Game.Rulesets.Objects.Drawables samplesBindable.CollectionChanged -= onSamplesChanged; // Release the samples for other hitobjects to use. - Samples.Samples = null; + if (Samples != null) + Samples.Samples = null; if (nestedHitObjects.IsValueCreated) { From 55cdff5be770414190ed13b7d0effea094c848bb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 20 Dec 2020 23:49:06 +0900 Subject: [PATCH 147/328] Renamespace ready button --- .../Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs | 2 +- .../RealtimeMultiplayer/{ => Match}/RealtimeReadyButton.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename osu.Game/Screens/Multi/RealtimeMultiplayer/{ => Match}/RealtimeReadyButton.cs (98%) diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs index 1f863028af..b7cd81fb32 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs @@ -11,7 +11,7 @@ using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Rulesets; -using osu.Game.Screens.Multi.RealtimeMultiplayer; +using osu.Game.Screens.Multi.RealtimeMultiplayer.Match; using osu.Game.Tests.Resources; using osu.Game.Users; using osuTK; diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeReadyButton.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs similarity index 98% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeReadyButton.cs rename to osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs index ea8fb04994..09487e9831 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeReadyButton.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs @@ -15,7 +15,7 @@ using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Screens.Multi.Components; using osuTK; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer +namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match { public class RealtimeReadyButton : RealtimeRoomComposite { From 232c0205b4d7927c3b84dac00a719ec2fa4be7ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 14 Dec 2020 22:51:35 +0100 Subject: [PATCH 148/328] Refactor hit object application scene to work reliably --- .../HitObjectApplicationTestScene.cs | 14 ++++++++++---- .../TestSceneBarLineApplication.cs | 7 ++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/HitObjectApplicationTestScene.cs b/osu.Game.Rulesets.Taiko.Tests/HitObjectApplicationTestScene.cs index 07c7b4d1db..a1d000386f 100644 --- a/osu.Game.Rulesets.Taiko.Tests/HitObjectApplicationTestScene.cs +++ b/osu.Game.Rulesets.Taiko.Tests/HitObjectApplicationTestScene.cs @@ -25,16 +25,22 @@ namespace osu.Game.Rulesets.Taiko.Tests private ScrollingHitObjectContainer hitObjectContainer; - [SetUpSteps] - public void SetUp() - => AddStep("create SHOC", () => Child = hitObjectContainer = new ScrollingHitObjectContainer + [BackgroundDependencyLoader] + private void load() + { + Child = hitObjectContainer = new ScrollingHitObjectContainer { RelativeSizeAxes = Axes.X, Height = 200, Anchor = Anchor.Centre, Origin = Anchor.Centre, Clock = new FramedClock(new StopwatchClock()) - }); + }; + } + + [SetUpSteps] + public void SetUp() + => AddStep("clear SHOC", () => hitObjectContainer.Clear(false)); protected void AddHitObject(DrawableHitObject hitObject) => AddStep("add to SHOC", () => hitObjectContainer.Add(hitObject)); diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineApplication.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineApplication.cs index 65230a07bc..a970965141 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineApplication.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineApplication.cs @@ -12,12 +12,13 @@ namespace osu.Game.Rulesets.Taiko.Tests [Test] public void TestApplyNewBarLine() { - DrawableBarLine barLine = new DrawableBarLine(PrepareObject(new BarLine + DrawableBarLine barLine = new DrawableBarLine(); + + AddStep("apply new bar line", () => barLine.Apply(PrepareObject(new BarLine { StartTime = 400, Major = true - })); - + }), null)); AddHitObject(barLine); RemoveHitObject(barLine); From 536df074a9a5505a9b14dddd29f616d42e243c93 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 00:02:49 +0900 Subject: [PATCH 149/328] Don't attempt to re-map existing beatmap/ruleset (for testing) --- osu.Game/Online/Multiplayer/PlaylistItem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Multiplayer/PlaylistItem.cs b/osu.Game/Online/Multiplayer/PlaylistItem.cs index 416091a1aa..4c4c071fc9 100644 --- a/osu.Game/Online/Multiplayer/PlaylistItem.cs +++ b/osu.Game/Online/Multiplayer/PlaylistItem.cs @@ -64,8 +64,8 @@ namespace osu.Game.Online.Multiplayer public void MapObjects(BeatmapManager beatmaps, RulesetStore rulesets) { - Beatmap.Value = apiBeatmap.ToBeatmap(rulesets); - Ruleset.Value = rulesets.GetRuleset(RulesetID); + Beatmap.Value ??= apiBeatmap.ToBeatmap(rulesets); + Ruleset.Value ??= rulesets.GetRuleset(RulesetID); Ruleset rulesetInstance = Ruleset.Value.CreateInstance(); From 1fdc19ee0fe9855a44eb95e94a8555be2103b0b7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 00:04:06 +0900 Subject: [PATCH 150/328] Add realtime match subscreen and related components --- .../TestSceneRealtimeMatchSubScreen.cs | 77 +++ .../Match/BeatmapSelectionControl.cs | 81 ++++ .../Match/RealtimeMatchFooter.cs | 48 ++ .../Match/RealtimeMatchHeader.cs | 106 +++++ .../Match/RealtimeMatchSettingsOverlay.cs | 441 ++++++++++++++++++ .../Participants/ParticipantsListHeader.cs | 31 ++ .../RealtimeMatchSongSelect.cs | 20 + .../RealtimeMatchSubScreen.cs | 201 ++++++++ .../RealtimeMultiplayer/RealtimePlayer.cs | 16 + 9 files changed, 1021 insertions(+) create mode 100644 osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMatchSubScreen.cs create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/Match/BeatmapSelectionControl.cs create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchFooter.cs create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchHeader.cs create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsListHeader.cs create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMatchSubScreen.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMatchSubScreen.cs new file mode 100644 index 0000000000..d31364d62e --- /dev/null +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMatchSubScreen.cs @@ -0,0 +1,77 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Screens; +using osu.Framework.Testing; +using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Multi.RealtimeMultiplayer; +using osu.Game.Screens.Multi.RealtimeMultiplayer.Match; +using osu.Game.Tests.Beatmaps; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.RealtimeMultiplayer +{ + public class TestSceneRealtimeMatchSubScreen : RealtimeMultiplayerTestScene + { + private RealtimeMatchSubScreen screen; + + public TestSceneRealtimeMatchSubScreen() + : base(false) + { + } + + [SetUp] + public new void Setup() => Schedule(() => + { + Room.Name.Value = "Test Room"; + }); + + [SetUpSteps] + public void SetupSteps() + { + AddStep("load match", () => LoadScreen(screen = new RealtimeMatchSubScreen(Room))); + AddUntilStep("wait for load", () => screen.IsCurrentScreen()); + } + + [Test] + public void TestSettingValidity() + { + AddAssert("create button not enabled", () => !this.ChildrenOfType().Single().Enabled.Value); + + AddStep("set playlist", () => + { + Room.Playlist.Add(new PlaylistItem + { + Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo }, + }); + }); + + AddAssert("create button enabled", () => this.ChildrenOfType().Single().Enabled.Value); + } + + [Test] + public void TestCreatedRoom() + { + AddStep("set playlist", () => + { + Room.Playlist.Add(new PlaylistItem + { + Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo }, + }); + }); + + AddStep("click create button", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + + AddWaitStep("wait", 500); + } + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/BeatmapSelectionControl.cs new file mode 100644 index 0000000000..1939744916 --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/BeatmapSelectionControl.cs @@ -0,0 +1,81 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Specialized; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Screens; +using osu.Game.Online.API; +using osu.Game.Screens.Multi.Match.Components; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match +{ + public class BeatmapSelectionControl : MultiplayerComposite + { + [Resolved] + private RealtimeMatchSubScreen matchSubScreen { get; set; } + + [Resolved] + private IAPIProvider api { get; set; } + + private Container beatmapPanelContainer; + private Button selectButton; + + public BeatmapSelectionControl() + { + AutoSizeAxes = Axes.Y; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + beatmapPanelContainer = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, + selectButton = new PurpleTriangleButton + { + RelativeSizeAxes = Axes.X, + Height = 40, + Text = "Select beatmap", + Action = () => matchSubScreen.Push(new RealtimeMatchSongSelect()), + Alpha = 0 + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Playlist.BindCollectionChanged(onPlaylistChanged, true); + Host.BindValueChanged(host => + { + if (RoomID.Value == null || host.NewValue?.Equals(api.LocalUser.Value) == true) + selectButton.Show(); + else + selectButton.Hide(); + }, true); + } + + private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (Playlist.Any()) + beatmapPanelContainer.Child = new DrawableRoomPlaylistItem(Playlist.Single(), false, false); + else + beatmapPanelContainer.Clear(); + } + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchFooter.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchFooter.cs new file mode 100644 index 0000000000..31871729f6 --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchFooter.cs @@ -0,0 +1,48 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Online.Multiplayer; +using osuTK; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match +{ + public class RealtimeMatchFooter : CompositeDrawable + { + public const float HEIGHT = 50; + + public readonly Bindable SelectedItem = new Bindable(); + + private readonly Drawable background; + + public RealtimeMatchFooter() + { + RelativeSizeAxes = Axes.X; + Height = HEIGHT; + + InternalChildren = new[] + { + background = new Box { RelativeSizeAxes = Axes.Both }, + new RealtimeReadyButton + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(600, 50), + SelectedItem = { BindTarget = SelectedItem } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = Color4Extensions.FromHex(@"28242d"); + } + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchHeader.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchHeader.cs new file mode 100644 index 0000000000..a9a10d1510 --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchHeader.cs @@ -0,0 +1,106 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API; +using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Users.Drawables; +using osuTK; +using FontWeight = osu.Game.Graphics.FontWeight; +using OsuColour = osu.Game.Graphics.OsuColour; +using OsuFont = osu.Game.Graphics.OsuFont; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match +{ + public class RealtimeMatchHeader : MultiplayerComposite + { + public const float HEIGHT = 50; + + public Action OpenSettings; + + private UpdateableAvatar avatar; + private LinkFlowContainer hostText; + private Button openSettingsButton; + + [Resolved] + private IAPIProvider api { get; set; } + + public RealtimeMatchHeader() + { + RelativeSizeAxes = Axes.X; + Height = HEIGHT; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + InternalChildren = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + avatar = new UpdateableAvatar + { + Size = new Vector2(50), + Masking = true, + CornerRadius = 10, + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new OsuSpriteText + { + Font = OsuFont.GetFont(size: 30), + Current = { BindTarget = RoomName } + }, + hostText = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 20)) + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + } + } + } + } + }, + openSettingsButton = new PurpleTriangleButton + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Size = new Vector2(150, HEIGHT), + Text = "Open settings", + Action = () => OpenSettings?.Invoke(), + Alpha = 0 + } + }; + + Host.BindValueChanged(host => + { + avatar.User = host.NewValue; + + hostText.Clear(); + + if (host.NewValue != null) + { + hostText.AddText("hosted by "); + hostText.AddUserLink(host.NewValue, s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); + } + + openSettingsButton.Alpha = host.NewValue?.Equals(api.LocalUser.Value) == true ? 1 : 0; + }, true); + } + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs new file mode 100644 index 0000000000..3b9603e1bd --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs @@ -0,0 +1,441 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +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.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Overlays; +using osu.Game.Rulesets; +using osu.Game.Screens.Multi.Match.Components; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match +{ + public class RealtimeMatchSettingsOverlay : FocusedOverlayContainer + { + private const float transition_duration = 350; + private const float field_padding = 45; + + protected MatchSettings Settings { get; private set; } + + [BackgroundDependencyLoader] + private void load() + { + Masking = true; + + Child = Settings = new MatchSettings + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Y, + SettingsApplied = Hide + }; + } + + protected override void PopIn() + { + Settings.MoveToY(0, transition_duration, Easing.OutQuint); + } + + protected override void PopOut() + { + Settings.MoveToY(-1, transition_duration, Easing.InSine); + } + + protected class MatchSettings : MultiplayerComposite + { + private const float disabled_alpha = 0.2f; + + public Action SettingsApplied; + + public OsuTextBox NameField, MaxParticipantsField; + public RoomAvailabilityPicker AvailabilityPicker; + public GameTypePicker TypePicker; + public TriangleButton ApplyButton; + + public OsuSpriteText ErrorText; + + private OsuSpriteText typeLabel; + private LoadingLayer loadingLayer; + private BeatmapSelectionControl initialBeatmapControl; + + [Resolved] + private RealtimeRoomManager manager { get; set; } + + [Resolved] + private StatefulMultiplayerClient client { get; set; } + + [Resolved] + private Bindable currentRoom { get; set; } + + [Resolved] + private Bindable beatmap { get; set; } + + [Resolved] + private Bindable ruleset { get; set; } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Container dimContent; + + InternalChildren = new Drawable[] + { + dimContent = new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"28242d"), + }, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.Distributed), + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new Drawable[] + { + new OsuScrollContainer + { + Padding = new MarginPadding + { + Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING, + Vertical = 10 + }, + RelativeSizeAxes = Axes.Both, + Children = new[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 10), + Children = new Drawable[] + { + new Container + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new SectionContainer + { + Padding = new MarginPadding { Right = field_padding / 2 }, + Children = new[] + { + new Section("Room name") + { + Child = NameField = new SettingsTextBox + { + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + }, + }, + new Section("Room visibility") + { + Alpha = disabled_alpha, + Child = AvailabilityPicker = new RoomAvailabilityPicker + { + Enabled = { Value = false } + }, + }, + new Section("Game type") + { + Alpha = disabled_alpha, + Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Spacing = new Vector2(7), + Children = new Drawable[] + { + TypePicker = new GameTypePicker + { + RelativeSizeAxes = Axes.X, + Enabled = { Value = false } + }, + typeLabel = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 14), + Colour = colours.Yellow + }, + }, + }, + }, + }, + }, + new SectionContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Padding = new MarginPadding { Left = field_padding / 2 }, + Children = new[] + { + new Section("Max participants") + { + Alpha = disabled_alpha, + Child = MaxParticipantsField = new SettingsNumberTextBox + { + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + ReadOnly = true, + }, + }, + new Section("Password (optional)") + { + Alpha = disabled_alpha, + Child = new SettingsPasswordTextBox + { + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + ReadOnly = true, + }, + }, + } + } + }, + }, + initialBeatmapControl = new BeatmapSelectionControl + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + Width = 0.5f + } + } + } + }, + }, + }, + new Drawable[] + { + new Container + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Y = 2, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"28242d").Darken(0.5f).Opacity(1f), + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Margin = new MarginPadding { Vertical = 20 }, + Padding = new MarginPadding { Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING }, + Children = new Drawable[] + { + ApplyButton = new CreateOrUpdateButton + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Size = new Vector2(230, 55), + Enabled = { Value = false }, + Action = apply, + }, + ErrorText = new OsuSpriteText + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Alpha = 0, + Depth = 1, + Colour = colours.RedDark + } + } + } + } + } + } + } + }, + } + }, + loadingLayer = new LoadingLayer(dimContent) + }; + + TypePicker.Current.BindValueChanged(type => typeLabel.Text = type.NewValue?.Name ?? string.Empty, true); + RoomName.BindValueChanged(name => NameField.Text = name.NewValue, true); + Availability.BindValueChanged(availability => AvailabilityPicker.Current.Value = availability.NewValue, true); + Type.BindValueChanged(type => TypePicker.Current.Value = type.NewValue, true); + MaxParticipants.BindValueChanged(count => MaxParticipantsField.Text = count.NewValue?.ToString(), true); + RoomID.BindValueChanged(roomId => initialBeatmapControl.Alpha = roomId.NewValue == null ? 1 : 0, true); + } + + protected override void Update() + { + base.Update(); + + ApplyButton.Enabled.Value = Playlist.Count > 0 && NameField.Text.Length > 0; + } + + private void apply() + { + if (!ApplyButton.Enabled.Value) + return; + + hideError(); + loadingLayer.Show(); + + // If the client is already in a room, update via the client. + // Otherwise, update the room directly in preparation for it to be submitted to the API on match creation. + if (client.Room != null) + { + client.ChangeSettings(name: NameField.Text); + onSuccess(currentRoom.Value); + } + else + { + currentRoom.Value.Name.Value = NameField.Text; + currentRoom.Value.Availability.Value = AvailabilityPicker.Current.Value; + currentRoom.Value.Type.Value = TypePicker.Current.Value; + + if (int.TryParse(MaxParticipantsField.Text, out int max)) + currentRoom.Value.MaxParticipants.Value = max; + else + currentRoom.Value.MaxParticipants.Value = null; + + manager?.CreateRoom(currentRoom.Value, onSuccess, onError); + } + } + + private void hideError() => ErrorText.FadeOut(50); + + private void onSuccess(Room room) + { + loadingLayer.Hide(); + SettingsApplied?.Invoke(); + } + + private void onError(string text) + { + ErrorText.Text = text; + ErrorText.FadeIn(50); + + loadingLayer.Hide(); + } + } + + private class SettingsTextBox : OsuTextBox + { + [BackgroundDependencyLoader] + private void load() + { + BackgroundUnfocused = Color4.Black; + BackgroundFocused = Color4.Black; + } + } + + private class SettingsNumberTextBox : SettingsTextBox + { + protected override bool CanAddCharacter(char character) => char.IsNumber(character); + } + + private class SettingsPasswordTextBox : OsuPasswordTextBox + { + [BackgroundDependencyLoader] + private void load() + { + BackgroundUnfocused = Color4.Black; + BackgroundFocused = Color4.Black; + } + } + + private class SectionContainer : FillFlowContainer
+ { + public SectionContainer() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Width = 0.5f; + Direction = FillDirection.Vertical; + Spacing = new Vector2(field_padding); + } + } + + private class Section : Container + { + private readonly Container content; + + protected override Container Content => content; + + public Section(string title) + { + AutoSizeAxes = Axes.Y; + RelativeSizeAxes = Axes.X; + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new OsuSpriteText + { + Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 12), + Text = title.ToUpper(), + }, + content = new Container + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + }, + }, + }; + } + } + + public class CreateOrUpdateButton : TriangleButton + { + [Resolved(typeof(Room), nameof(Room.RoomID))] + private Bindable roomId { get; set; } + + protected override void LoadComplete() + { + base.LoadComplete(); + roomId.BindValueChanged(id => Text = id.NewValue == null ? "Create" : "Update", true); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = colours.Yellow; + Triangles.ColourLight = colours.YellowLight; + Triangles.ColourDark = colours.YellowDark; + } + } + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsListHeader.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsListHeader.cs new file mode 100644 index 0000000000..0ca7d34005 --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsListHeader.cs @@ -0,0 +1,31 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Screens.Multi.Components; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants +{ + public class ParticipantsListHeader : OverlinedHeader + { + [Resolved] + private StatefulMultiplayerClient client { get; set; } + + public ParticipantsListHeader() + : base("Participants") + { + } + + protected override void Update() + { + base.Update(); + + var room = client.Room; + if (room == null) + return; + + Details.Value = room.Users.Count.ToString(); + } + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs new file mode 100644 index 0000000000..9bcc303065 --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs @@ -0,0 +1,20 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Screens.Select; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer +{ + public class RealtimeMatchSongSelect : SongSelect + { + protected override BeatmapDetailArea CreateBeatmapDetailArea() + { + throw new System.NotImplementedException(); + } + + protected override bool OnStart() + { + throw new System.NotImplementedException(); + } + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs new file mode 100644 index 0000000000..d8b42e065b --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs @@ -0,0 +1,201 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Specialized; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Screens; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.Multi.Match; +using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.Multi.RealtimeMultiplayer.Match; +using osu.Game.Screens.Multi.RealtimeMultiplayer.Participants; +using osu.Game.Screens.Play; +using osu.Game.Users; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer +{ + [Cached] + public class RealtimeMatchSubScreen : RoomSubScreen + { + public override string Title { get; } + + public override string ShortTitle => "match"; + + [Resolved(canBeNull: true)] + private Multiplayer multiplayer { get; set; } + + [Resolved] + private StatefulMultiplayerClient client { get; set; } + + private RealtimeMatchSettingsOverlay settingsOverlay; + + public RealtimeMatchSubScreen(Room room) + { + Title = room.RoomID.Value == null ? "New match" : room.Name.Value; + Activity.Value = new UserActivity.InLobby(room); + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding + { + Horizontal = 105, + Vertical = 20 + }, + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + }, + Content = new[] + { + new Drawable[] + { + new RealtimeMatchHeader + { + OpenSettings = () => settingsOverlay.Show() + } + }, + new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = 5, Vertical = 10 }, + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] { new ParticipantsListHeader() }, + new Drawable[] + { + new Participants.ParticipantsList + { + RelativeSizeAxes = Axes.Both + }, + } + } + } + }, + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = 5 }, + Children = new Drawable[] + { + new OverlinedHeader("Beatmap"), + new BeatmapSelectionControl { RelativeSizeAxes = Axes.X } + } + } + } + } + } + }, + new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] { new OverlinedHeader("Chat") }, + new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } + } + } + } + }, + } + } + }, + new Drawable[] + { + new Footer { SelectedItem = { BindTarget = SelectedItem } } + } + }, + RowDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + } + }, + settingsOverlay = new RealtimeMatchSettingsOverlay + { + RelativeSizeAxes = Axes.Both, + State = { Value = client.Room == null ? Visibility.Visible : Visibility.Hidden } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Playlist.BindCollectionChanged(onPlaylistChanged, true); + + client.LoadRequested += onLoadRequested; + } + + public override bool OnBackButton() + { + if (client.Room != null && settingsOverlay.State.Value == Visibility.Visible) + { + settingsOverlay.Hide(); + return true; + } + + return base.OnBackButton(); + } + + private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) => SelectedItem.Value = Playlist.FirstOrDefault(); + + private void onLoadRequested() => multiplayer?.Push(new PlayerLoader(() => new RealtimePlayer(SelectedItem.Value))); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (client != null) + client.LoadRequested -= onLoadRequested; + } + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs new file mode 100644 index 0000000000..d629027246 --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Online.Multiplayer; +using osu.Game.Screens.Multi.Play; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer +{ + public class RealtimePlayer : TimeshiftPlayer + { + public RealtimePlayer(PlaylistItem playlistItem) + : base(playlistItem) + { + } + } +} From 945ba59c8e3cb9c6df69fdba8ced4fc8322f9085 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 00:06:44 +0900 Subject: [PATCH 151/328] Make timeshift player able to not allow pause --- osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs index 41dcf61740..f86d8ff267 100644 --- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs +++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs @@ -35,7 +35,8 @@ namespace osu.Game.Screens.Multi.Play [Resolved] private IBindable ruleset { get; set; } - public TimeshiftPlayer(PlaylistItem playlistItem) + public TimeshiftPlayer(PlaylistItem playlistItem, bool allowPause = true) + : base(allowPause) { this.playlistItem = playlistItem; } From 07077b8f4e52e2aa3902d73a4f936fc2086e7e84 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 00:13:05 +0900 Subject: [PATCH 152/328] Add realtime player --- .../Screens/Multi/Play/TimeshiftPlayer.cs | 32 ++++----- .../RealtimeMultiplayer/RealtimePlayer.cs | 67 ++++++++++++++++++- .../RealtimeResultsScreen.cs | 17 +++++ 3 files changed, 99 insertions(+), 17 deletions(-) create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs index f86d8ff267..e8462088f1 100644 --- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs +++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs @@ -25,9 +25,11 @@ namespace osu.Game.Screens.Multi.Play public Action Exited; [Resolved(typeof(Room), nameof(Room.RoomID))] - private Bindable roomId { get; set; } + protected Bindable RoomId { get; private set; } - private readonly PlaylistItem playlistItem; + protected readonly PlaylistItem PlaylistItem; + + protected int? Token { get; private set; } [Resolved] private IAPIProvider api { get; set; } @@ -38,30 +40,28 @@ namespace osu.Game.Screens.Multi.Play public TimeshiftPlayer(PlaylistItem playlistItem, bool allowPause = true) : base(allowPause) { - this.playlistItem = playlistItem; + PlaylistItem = playlistItem; } - private int? token; - [BackgroundDependencyLoader] private void load() { - token = null; + Token = null; bool failed = false; // Sanity checks to ensure that TimeshiftPlayer matches the settings for the current PlaylistItem - if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != playlistItem.Beatmap.Value.OnlineBeatmapID) + if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != PlaylistItem.Beatmap.Value.OnlineBeatmapID) throw new InvalidOperationException("Current Beatmap does not match PlaylistItem's Beatmap"); - if (ruleset.Value.ID != playlistItem.Ruleset.Value.ID) + if (ruleset.Value.ID != PlaylistItem.Ruleset.Value.ID) throw new InvalidOperationException("Current Ruleset does not match PlaylistItem's Ruleset"); - if (!playlistItem.RequiredMods.All(m => Mods.Value.Any(m.Equals))) + if (!PlaylistItem.RequiredMods.All(m => Mods.Value.Any(m.Equals))) throw new InvalidOperationException("Current Mods do not match PlaylistItem's RequiredMods"); - var req = new CreateRoomScoreRequest(roomId.Value ?? 0, playlistItem.ID, Game.VersionHash); - req.Success += r => token = r.ID; + var req = new CreateRoomScoreRequest(RoomId.Value ?? 0, PlaylistItem.ID, Game.VersionHash); + req.Success += r => Token = r.ID; req.Failure += e => { failed = true; @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Multi.Play api.Queue(req); - while (!failed && !token.HasValue) + while (!failed && !Token.HasValue) Thread.Sleep(1000); } @@ -93,8 +93,8 @@ namespace osu.Game.Screens.Multi.Play protected override ResultsScreen CreateResults(ScoreInfo score) { - Debug.Assert(roomId.Value != null); - return new TimeshiftResultsScreen(score, roomId.Value.Value, playlistItem, true); + Debug.Assert(RoomId.Value != null); + return new TimeshiftResultsScreen(score, RoomId.Value.Value, PlaylistItem, true); } protected override Score CreateScore() @@ -108,10 +108,10 @@ namespace osu.Game.Screens.Multi.Play { await base.SubmitScore(score); - Debug.Assert(token != null); + Debug.Assert(Token != null); var tcs = new TaskCompletionSource(); - var request = new SubmitRoomScoreRequest(token.Value, roomId.Value ?? 0, playlistItem.ID, score.ScoreInfo); + var request = new SubmitRoomScoreRequest(Token.Value, RoomId.Value ?? 0, PlaylistItem.ID, score.ScoreInfo); request.Success += s => { diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index d629027246..d654496f40 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -1,16 +1,81 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using osu.Framework.Allocation; using osu.Game.Online.Multiplayer; +using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Scoring; using osu.Game.Screens.Multi.Play; +using osu.Game.Screens.Ranking; namespace osu.Game.Screens.Multi.RealtimeMultiplayer { public class RealtimePlayer : TimeshiftPlayer { + protected override bool PauseOnFocusLost => false; + + // Disallow fails in multiplayer for now. + protected override bool CheckModsAllowFailure() => false; + + [Resolved] + private StatefulMultiplayerClient client { get; set; } + + private readonly TaskCompletionSource resultsReady = new TaskCompletionSource(); + private bool started; + public RealtimePlayer(PlaylistItem playlistItem) - : base(playlistItem) + : base(playlistItem, false) { } + + [BackgroundDependencyLoader] + private void load() + { + if (Token == null) + return; // Todo: Somehow handle token retrieval failure. + + client.MatchStarted += onMatchStarted; + client.ResultsReady += onResultsReady; + client.ChangeState(MultiplayerUserState.Loaded); + + while (!started) + Thread.Sleep(100); + } + + private void onMatchStarted() => started = true; + + private void onResultsReady() => resultsReady.SetResult(true); + + protected override async Task SubmitScore(Score score) + { + await base.SubmitScore(score); + + await client.ChangeState(MultiplayerUserState.FinishedPlay); + + // Await up to 30 seconds for results to become available (3 api request timeouts). + // This is arbitrary just to not leave the player in an essentially deadlocked state if any connection issues occur. + await Task.WhenAny(resultsReady.Task, Task.Delay(TimeSpan.FromSeconds(30))); + } + + protected override ResultsScreen CreateResults(ScoreInfo score) + { + Debug.Assert(RoomId.Value != null); + return new RealtimeResultsScreen(score, RoomId.Value.Value, PlaylistItem); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (client != null) + { + client.MatchStarted -= onMatchStarted; + client.ResultsReady -= onResultsReady; + } + } } } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs new file mode 100644 index 0000000000..1598c8fbb5 --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Online.Multiplayer; +using osu.Game.Scoring; +using osu.Game.Screens.Multi.Ranking; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer +{ + public class RealtimeResultsScreen : TimeshiftResultsScreen + { + public RealtimeResultsScreen(ScoreInfo score, int roomId, PlaylistItem playlistItem) + : base(score, roomId, playlistItem, false) + { + } + } +} From 5b4197a9efb7194e955d2d6eb891f8ec67638f91 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 00:14:54 +0900 Subject: [PATCH 153/328] Disable watching replays from realtime results screen --- .../Multi/Ranking/TimeshiftResultsScreen.cs | 4 ++-- .../RealtimeResultsScreen.cs | 2 +- osu.Game/Screens/Ranking/ResultsScreen.cs | 23 +++++++++++-------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs b/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs index 3623208fa7..d3f1c19c7c 100644 --- a/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs +++ b/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs @@ -32,8 +32,8 @@ namespace osu.Game.Screens.Multi.Ranking [Resolved] private IAPIProvider api { get; set; } - public TimeshiftResultsScreen(ScoreInfo score, int roomId, PlaylistItem playlistItem, bool allowRetry) - : base(score, allowRetry) + public TimeshiftResultsScreen(ScoreInfo score, int roomId, PlaylistItem playlistItem, bool allowRetry, bool allowWatchingReplay = true) + : base(score, allowRetry, allowWatchingReplay) { this.roomId = roomId; this.playlistItem = playlistItem; diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs index 1598c8fbb5..3964a87eb6 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs @@ -10,7 +10,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer public class RealtimeResultsScreen : TimeshiftResultsScreen { public RealtimeResultsScreen(ScoreInfo score, int roomId, PlaylistItem playlistItem) - : base(score, roomId, playlistItem, false) + : base(score, roomId, playlistItem, false, false) { } } diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index 887e7ec8a9..528a1842af 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -57,11 +57,13 @@ namespace osu.Game.Screens.Ranking private APIRequest nextPageRequest; private readonly bool allowRetry; + private readonly bool allowWatchingReplay; - protected ResultsScreen(ScoreInfo score, bool allowRetry) + protected ResultsScreen(ScoreInfo score, bool allowRetry, bool allowWatchingReplay = true) { Score = score; this.allowRetry = allowRetry; + this.allowWatchingReplay = allowWatchingReplay; SelectedScore.Value = score; } @@ -128,15 +130,7 @@ namespace osu.Game.Screens.Ranking Origin = Anchor.Centre, AutoSizeAxes = Axes.Both, Spacing = new Vector2(5), - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - new ReplayDownloadButton(null) - { - Score = { BindTarget = SelectedScore }, - Width = 300 - }, - } + Direction = FillDirection.Horizontal } } } @@ -157,6 +151,15 @@ namespace osu.Game.Screens.Ranking ScorePanelList.AddScore(Score, shouldFlair); } + if (allowWatchingReplay) + { + buttons.Add(new ReplayDownloadButton(null) + { + Score = { BindTarget = SelectedScore }, + Width = 300 + }); + } + if (player != null && allowRetry) { buttons.Add(new RetryButton { Width = 300 }); From 15480c006b6353620b64dce0affcb935d935e3a7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 00:21:30 +0900 Subject: [PATCH 154/328] Create the correct room subscreen --- osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs | 6 ++++-- .../Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs | 4 ++++ .../Screens/Multi/Timeshift/TimeshiftLoungeSubScreen.cs | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs index f4591d089e..44c893363b 100644 --- a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Overlays; using osu.Game.Screens.Multi.Lounge.Components; -using osu.Game.Screens.Multi.Timeshift; +using osu.Game.Screens.Multi.Match; using osu.Game.Users; namespace osu.Game.Screens.Multi.Lounge @@ -192,9 +192,11 @@ namespace osu.Game.Screens.Multi.Lounge selectedRoom.Value = room; - this.Push(new TimeshiftRoomSubScreen(room)); + this.Push(CreateRoomSubScreen(room)); } protected abstract FilterControl CreateFilterControl(); + + protected abstract RoomSubScreen CreateRoomSubScreen(Room room); } } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs index ed187e436f..9fbf0c4654 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs @@ -1,13 +1,17 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Lounge.Components; +using osu.Game.Screens.Multi.Match; namespace osu.Game.Screens.Multi.RealtimeMultiplayer { public class RealtimeLoungeSubScreen : LoungeSubScreen { protected override FilterControl CreateFilterControl() => new RealtimeFilterControl(); + + protected override RoomSubScreen CreateRoomSubScreen(Room room) => new RealtimeMatchSubScreen(room); } } diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftLoungeSubScreen.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftLoungeSubScreen.cs index 70fb1aef1d..8e426ffbcc 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftLoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftLoungeSubScreen.cs @@ -1,13 +1,17 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Lounge.Components; +using osu.Game.Screens.Multi.Match; namespace osu.Game.Screens.Multi.Timeshift { public class TimeshiftLoungeSubScreen : LoungeSubScreen { protected override FilterControl CreateFilterControl() => new TimeshiftFilterControl(); + + protected override RoomSubScreen CreateRoomSubScreen(Room room) => new TimeshiftRoomSubScreen(room); } } From 959959dbedf50b76d470d5f0457c260988e7c15b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 00:21:41 +0900 Subject: [PATCH 155/328] Add multiplayer client to OsuGameBase --- osu.Game/OsuGameBase.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 150569f1dd..eb27821d82 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -30,6 +30,7 @@ using osu.Game.Database; using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.IO; +using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Online.Spectator; using osu.Game.Overlays; using osu.Game.Resources; @@ -78,6 +79,7 @@ namespace osu.Game protected IAPIProvider API; private SpectatorStreamingClient spectatorStreaming; + private StatefulMultiplayerClient multiplayerClient; protected MenuCursorContainer MenuCursorContainer; @@ -211,6 +213,7 @@ namespace osu.Game dependencies.CacheAs(API ??= new APIAccess(LocalConfig)); dependencies.CacheAs(spectatorStreaming = new SpectatorStreamingClient()); + dependencies.CacheAs(multiplayerClient = new RealtimeMultiplayerClient()); var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures); @@ -277,6 +280,7 @@ namespace osu.Game if (API is APIAccess apiAccess) AddInternal(apiAccess); AddInternal(spectatorStreaming); + AddInternal(multiplayerClient); AddInternal(RulesetConfigCache); From 275efd12b84bf8d775313bcf93d75840c48ad370 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 00:21:48 +0900 Subject: [PATCH 156/328] Fix room manager reference --- .../RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs index 3b9603e1bd..924c736472 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs @@ -71,7 +71,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match private BeatmapSelectionControl initialBeatmapControl; [Resolved] - private RealtimeRoomManager manager { get; set; } + private IRoomManager manager { get; set; } [Resolved] private StatefulMultiplayerClient client { get; set; } From e32b1c34cac0436c39a5087896f386af30239d06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 14 Dec 2020 22:53:46 +0100 Subject: [PATCH 157/328] Implement hit application --- .../TestSceneHitApplication.cs | 37 ++++++++++++++++ .../Objects/Drawables/DrawableHit.cs | 44 ++++++++++++++----- 2 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko.Tests/TestSceneHitApplication.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneHitApplication.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneHitApplication.cs new file mode 100644 index 0000000000..52fd440857 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneHitApplication.cs @@ -0,0 +1,37 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Objects.Drawables; + +namespace osu.Game.Rulesets.Taiko.Tests +{ + public class TestSceneHitApplication : HitObjectApplicationTestScene + { + [Test] + public void TestApplyNewHit() + { + var hit = new DrawableHit(); + + AddStep("apply new hit", () => hit.Apply(PrepareObject(new Hit + { + Type = HitType.Rim, + IsStrong = false, + StartTime = 300 + }), null)); + + AddHitObject(hit); + RemoveHitObject(hit); + + AddStep("apply new hit", () => hit.Apply(PrepareObject(new Hit + { + Type = HitType.Centre, + IsStrong = true, + StartTime = 500 + }), null)); + + AddHitObject(hit); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 431f2980ec..5a479e1f53 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using osu.Framework.Allocation; +using JetBrains.Annotations; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Audio; @@ -36,29 +36,51 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private bool pressHandledThisFrame; - private readonly Bindable type; + private readonly Bindable type = new Bindable(); - public DrawableHit(Hit hit) - : base(hit) + public DrawableHit() + : this(null) { - type = HitObject.TypeBindable.GetBoundCopy(); - FillMode = FillMode.Fit; - - updateActionsFromType(); } - [BackgroundDependencyLoader] - private void load() + public DrawableHit([CanBeNull] Hit hit) + : base(hit) { + FillMode = FillMode.Fit; + } + + protected override void OnApply() + { + type.BindTo(HitObject.TypeBindable); type.BindValueChanged(_ => { updateActionsFromType(); - // will overwrite samples, should only be called on change. + // will overwrite samples, should only be called on subsequent changes + // after the initial application. updateSamplesFromTypeChange(); RecreatePieces(); }); + + // action update also has to happen immediately on application. + updateActionsFromType(); + + base.OnApply(); + } + + protected override void OnFree() + { + base.OnFree(); + + type.UnbindFrom(HitObject.TypeBindable); + type.UnbindEvents(); + + UnproxyContent(); + + HitActions = null; + HitAction = null; + validActionPressed = pressHandledThisFrame = false; } private HitSampleInfo[] getRimSamples() => HitObject.Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray(); From 8b6bc09b8f0c0dd48879fe05adb5f614aeb4dc29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 14 Dec 2020 23:02:33 +0100 Subject: [PATCH 158/328] Implement drum roll application --- .../TestSceneDrumRollApplication.cs | 39 +++++++++++++++++++ .../Objects/Drawables/DrawableDrumRoll.cs | 34 ++++++++++------ 2 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollApplication.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollApplication.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollApplication.cs new file mode 100644 index 0000000000..54450e27db --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollApplication.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Objects.Drawables; + +namespace osu.Game.Rulesets.Taiko.Tests +{ + public class TestSceneDrumRollApplication : HitObjectApplicationTestScene + { + [Test] + public void TestApplyNewDrumRoll() + { + var drumRoll = new DrawableDrumRoll(); + + AddStep("apply new drum roll", () => drumRoll.Apply(PrepareObject(new DrumRoll + { + StartTime = 300, + Duration = 500, + IsStrong = false, + TickRate = 2 + }), null)); + + AddHitObject(drumRoll); + RemoveHitObject(drumRoll); + + AddStep("apply new drum roll", () => drumRoll.Apply(PrepareObject(new DrumRoll + { + StartTime = 150, + Duration = 400, + IsStrong = true, + TickRate = 16 + }), null)); + + AddHitObject(drumRoll); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 4925b6fdfc..ede7453804 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Utils; using osu.Game.Graphics; @@ -31,15 +32,26 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ///
private int rollingHits; - private Container tickContainer; + private readonly Container tickContainer; private Color4 colourIdle; private Color4 colourEngaged; - public DrawableDrumRoll(DrumRoll drumRoll) + public DrawableDrumRoll() + : this(null) + { + } + + public DrawableDrumRoll([CanBeNull] DrumRoll drumRoll) : base(drumRoll) { RelativeSizeAxes = Axes.Y; + + Content.Add(tickContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Depth = float.MinValue + }); } [BackgroundDependencyLoader] @@ -47,12 +59,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { colourIdle = colours.YellowDark; colourEngaged = colours.YellowDarker; - - Content.Add(tickContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Depth = float.MinValue - }); } protected override void LoadComplete() @@ -68,6 +74,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables updateColour(); } + protected override void OnFree() + { + base.OnFree(); + rollingHits = 0; + } + protected override void AddNestedHitObject(DrawableHitObject hitObject) { base.AddNestedHitObject(hitObject); @@ -114,7 +126,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables rollingHits = Math.Clamp(rollingHits, 0, rolling_hits_for_engaged_colour); - updateColour(); + updateColour(100); } protected override void CheckForResult(bool userTriggered, double timeOffset) @@ -156,10 +168,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override DrawableStrongNestedHit CreateStrongNestedHit(DrumRoll.StrongNestedHit hitObject) => new StrongNestedHit(hitObject, this); - private void updateColour() + private void updateColour(double fadeDuration = 0) { Color4 newColour = Interpolation.ValueAt((float)rollingHits / rolling_hits_for_engaged_colour, colourIdle, colourEngaged, 0, 1); - (MainPiece.Drawable as IHasAccentColour)?.FadeAccent(newColour, 100); + (MainPiece.Drawable as IHasAccentColour)?.FadeAccent(newColour, fadeDuration); } private class StrongNestedHit : DrawableStrongNestedHit From e3b6eaa39059ba8afc2e71a0d034bc3b227fe49f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 14 Dec 2020 23:06:22 +0100 Subject: [PATCH 159/328] Implement swell application Also removes a weird sizing application that seems to have no effect (introduced in 27e63eb; compare removals for other taiko DHO types in 9d00e5b and 58bf288). --- .../Objects/Drawables/DrawableSwell.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 229d581d0c..9798a79450 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -35,7 +36,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private readonly CircularContainer targetRing; private readonly CircularContainer expandingRing; - public DrawableSwell(Swell swell) + public DrawableSwell() + : this(null) + { + } + + public DrawableSwell([CanBeNull] Swell swell) : base(swell) { FillMode = FillMode.Fit; @@ -123,12 +129,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables Origin = Anchor.Centre, }); - protected override void LoadComplete() + protected override void OnFree() { - base.LoadComplete(); + base.OnFree(); - // We need to set this here because RelativeSizeAxes won't/can't set our size by default with a different RelativeChildSize - Width *= Parent.RelativeChildSize.X; + UnproxyContent(); + + lastWasCentre = null; } protected override void AddNestedHitObject(DrawableHitObject hitObject) From 3bd42795899eda793b9b0d346abdae7902585ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 14 Dec 2020 23:10:19 +0100 Subject: [PATCH 160/328] Implement drum roll tick application --- .../Objects/Drawables/DrawableDrumRollTick.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index c6761de5e3..e7d8ef1e12 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using JetBrains.Annotations; using osu.Framework.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Skinning.Default; @@ -16,7 +17,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ///
public HitType JudgementType; - public DrawableDrumRollTick(DrumRollTick tick) + public DrawableDrumRollTick() + : this(null) + { + } + + public DrawableDrumRollTick([CanBeNull] DrumRollTick tick) : base(tick) { FillMode = FillMode.Fit; From d823c77a63e315207bbe7f282ef07ef3eeb8bf1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 14 Dec 2020 23:11:51 +0100 Subject: [PATCH 161/328] Implement swell tick application --- .../Objects/Drawables/DrawableSwellTick.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs index 14c86d151f..47fc7e5ab3 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using JetBrains.Annotations; using osu.Framework.Graphics; using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; @@ -11,7 +12,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { public override bool DisplayResult => false; - public DrawableSwellTick(SwellTick hitObject) + public DrawableSwellTick() + : this(null) + { + } + + public DrawableSwellTick([CanBeNull] SwellTick hitObject) : base(hitObject) { } From ae6dedacaf1edb784c9ca7bdfb4a871f6e0821f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 14 Dec 2020 23:21:19 +0100 Subject: [PATCH 162/328] Implement nested strong hit application --- .../Objects/Drawables/DrawableDrumRoll.cs | 17 ++++++++---- .../Objects/Drawables/DrawableDrumRollTick.cs | 17 ++++++++---- .../Objects/Drawables/DrawableHit.cs | 27 +++++++++++-------- .../Drawables/DrawableStrongNestedHit.cs | 7 +++-- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 2 +- 5 files changed, 44 insertions(+), 26 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index ede7453804..01336ea2e4 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -166,7 +166,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables Content.X = DrawHeight / 2; } - protected override DrawableStrongNestedHit CreateStrongNestedHit(DrumRoll.StrongNestedHit hitObject) => new StrongNestedHit(hitObject, this); + protected override DrawableStrongNestedHit CreateStrongNestedHit(DrumRoll.StrongNestedHit hitObject) => new StrongNestedHit(hitObject); private void updateColour(double fadeDuration = 0) { @@ -176,17 +176,24 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private class StrongNestedHit : DrawableStrongNestedHit { - public StrongNestedHit(DrumRoll.StrongNestedHit nestedHit, DrawableDrumRoll drumRoll) - : base(nestedHit, drumRoll) + public new DrawableDrumRoll ParentHitObject => (DrawableDrumRoll)base.ParentHitObject; + + public StrongNestedHit() + : this(null) + { + } + + public StrongNestedHit([CanBeNull] DrumRoll.StrongNestedHit nestedHit) + : base(nestedHit) { } protected override void CheckForResult(bool userTriggered, double timeOffset) { - if (!MainObject.Judged) + if (!ParentHitObject.Judged) return; - ApplyResult(r => r.Type = MainObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult); + ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult); } public override bool OnPressed(TaikoAction action) => false; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index e7d8ef1e12..1e625d91d6 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -67,21 +67,28 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return UpdateResult(true); } - protected override DrawableStrongNestedHit CreateStrongNestedHit(DrumRollTick.StrongNestedHit hitObject) => new StrongNestedHit(hitObject, this); + protected override DrawableStrongNestedHit CreateStrongNestedHit(DrumRollTick.StrongNestedHit hitObject) => new StrongNestedHit(hitObject); private class StrongNestedHit : DrawableStrongNestedHit { - public StrongNestedHit(DrumRollTick.StrongNestedHit nestedHit, DrawableDrumRollTick tick) - : base(nestedHit, tick) + public new DrawableDrumRollTick ParentHitObject => (DrawableDrumRollTick)base.ParentHitObject; + + public StrongNestedHit() + : this(null) + { + } + + public StrongNestedHit([CanBeNull] DrumRollTick.StrongNestedHit nestedHit) + : base(nestedHit) { } protected override void CheckForResult(bool userTriggered, double timeOffset) { - if (!MainObject.Judged) + if (!ParentHitObject.Judged) return; - ApplyResult(r => r.Type = MainObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult); + ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult); } public override bool OnPressed(TaikoAction action) => false; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 5a479e1f53..73ebd7c117 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -250,32 +250,37 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } } - protected override DrawableStrongNestedHit CreateStrongNestedHit(Hit.StrongNestedHit hitObject) => new StrongNestedHit(hitObject, this); + protected override DrawableStrongNestedHit CreateStrongNestedHit(Hit.StrongNestedHit hitObject) => new StrongNestedHit(hitObject); private class StrongNestedHit : DrawableStrongNestedHit { + public new DrawableHit ParentHitObject => (DrawableHit)base.ParentHitObject; + /// /// The lenience for the second key press. /// This does not adjust by map difficulty in ScoreV2 yet. /// private const double second_hit_window = 30; - public new DrawableHit MainObject => (DrawableHit)base.MainObject; + public StrongNestedHit() + : this(null) + { + } - public StrongNestedHit(Hit.StrongNestedHit nestedHit, DrawableHit hit) - : base(nestedHit, hit) + public StrongNestedHit([CanBeNull] Hit.StrongNestedHit nestedHit) + : base(nestedHit) { } protected override void CheckForResult(bool userTriggered, double timeOffset) { - if (!MainObject.Result.HasResult) + if (!ParentHitObject.Result.HasResult) { base.CheckForResult(userTriggered, timeOffset); return; } - if (!MainObject.Result.IsHit) + if (!ParentHitObject.Result.IsHit) { ApplyResult(r => r.Type = r.Judgement.MinResult); return; @@ -283,27 +288,27 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables if (!userTriggered) { - if (timeOffset - MainObject.Result.TimeOffset > second_hit_window) + if (timeOffset - ParentHitObject.Result.TimeOffset > second_hit_window) ApplyResult(r => r.Type = r.Judgement.MinResult); return; } - if (Math.Abs(timeOffset - MainObject.Result.TimeOffset) <= second_hit_window) + if (Math.Abs(timeOffset - ParentHitObject.Result.TimeOffset) <= second_hit_window) ApplyResult(r => r.Type = r.Judgement.MaxResult); } public override bool OnPressed(TaikoAction action) { // Don't process actions until the main hitobject is hit - if (!MainObject.IsHit) + if (!ParentHitObject.IsHit) return false; // Don't process actions if the pressed button was released - if (MainObject.HitAction == null) + if (ParentHitObject.HitAction == null) return false; // Don't handle invalid hit action presses - if (!MainObject.HitActions.Contains(action)) + if (!ParentHitObject.HitActions.Contains(action)) return false; return UpdateResult(true); diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs index d2e8888197..9c22e34387 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Rulesets.Objects.Drawables; +using JetBrains.Annotations; using osu.Game.Rulesets.Taiko.Judgements; namespace osu.Game.Rulesets.Taiko.Objects.Drawables @@ -11,12 +11,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ///
public abstract class DrawableStrongNestedHit : DrawableTaikoHitObject { - public readonly DrawableHitObject MainObject; + public new DrawableTaikoHitObject ParentHitObject => (DrawableTaikoHitObject)base.ParentHitObject; - protected DrawableStrongNestedHit(StrongNestedHitObject nestedHit, DrawableHitObject mainObject) + protected DrawableStrongNestedHit([CanBeNull] StrongNestedHitObject nestedHit) : base(nestedHit) { - MainObject = mainObject; } } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index d20b190c86..8682495b41 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -248,7 +248,7 @@ namespace osu.Game.Rulesets.Taiko.UI { case TaikoStrongJudgement _: if (result.IsHit) - hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).MainObject)?.VisualiseSecondHit(); + hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).ParentHitObject)?.VisualiseSecondHit(); break; case TaikoDrumRollTickJudgement _: From 3af702453f66663cef225445e11f5cfc5d2cf4b4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 00:37:13 +0900 Subject: [PATCH 163/328] Implement realtime match song select --- .../RealtimeMatchSongSelect.cs | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs index 9bcc303065..157216e9bb 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs @@ -1,20 +1,53 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; +using Humanizer; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Screens; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Screens.Select; namespace osu.Game.Screens.Multi.RealtimeMultiplayer { - public class RealtimeMatchSongSelect : SongSelect + public class RealtimeMatchSongSelect : SongSelect, IMultiplayerSubScreen { - protected override BeatmapDetailArea CreateBeatmapDetailArea() - { - throw new System.NotImplementedException(); - } + public string ShortTitle => "song selection"; + + public override string Title => ShortTitle.Humanize(); + + [Resolved(typeof(Room), nameof(Room.Playlist))] + private BindableList playlist { get; set; } + + [Resolved] + private StatefulMultiplayerClient client { get; set; } protected override bool OnStart() { - throw new System.NotImplementedException(); + var item = new PlaylistItem(); + + item.Beatmap.Value = Beatmap.Value.BeatmapInfo; + item.Ruleset.Value = Ruleset.Value; + + item.RequiredMods.Clear(); + item.RequiredMods.AddRange(Mods.Value.Select(m => m.CreateCopy())); + + // If the client is already in a room, update via the client. + // Otherwise, update the playlist directly in preparation for it to be submitted to the API on match creation. + if (client.Room != null) + client.ChangeSettings(item: item); + else + { + playlist.Clear(); + playlist.Add(item); + } + + this.Exit(); + return true; } + + protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); } } From d127494c2dedfd133012e574f7fe68d15049073d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 00:39:31 +0900 Subject: [PATCH 164/328] Fix thread-unsafe room removal --- .../Multi/RealtimeMultiplayer/RealtimeRoomManager.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index a50628a5fa..734d00b9aa 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -54,9 +54,12 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer multiplayerClient.LeaveRoom().Wait(); // Todo: This is not the way to do this. Basically when we're the only participant and the room closes, there's no way to know if this is actually the case. - RemoveRoom(joinedRoom); // This is delayed one frame because upon exiting the match subscreen, multiplayer updates the polling rate and messes with polling. - Schedule(() => listingPollingComponent.PollImmediately()); + Schedule(() => + { + RemoveRoom(joinedRoom); + listingPollingComponent.PollImmediately(); + }); } private void joinMultiplayerRoom(Room room, Action onSuccess = null) From a893360c0e07d3c2b31206ace178ad33cf85a47f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 00:41:14 +0900 Subject: [PATCH 165/328] Reword comment --- .../Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index 8d3b161804..0065b425ec 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -71,7 +71,9 @@ namespace osu.Game.Online.RealtimeMultiplayer private RulesetStore rulesets { get; set; } = null!; private Room? apiRoom; - private int playlistItemId; // Todo: THIS IS SUPER TEMPORARY!! + + // Todo: This is temporary, until the multiplayer server returns the item id on match start or otherwise. + private int playlistItemId; /// /// Joins the for a given API . From 0c5333bd586dfea1f40e3f6e6d4144bd887713a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 20 Dec 2020 17:57:19 +0100 Subject: [PATCH 166/328] Adjust top-level hitobjects to support nested pooling --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs | 2 +- .../Objects/Drawables/DrawableTaikoStrongableHitObject.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 01336ea2e4..d085b95f35 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override void ClearNestedHitObjects() { base.ClearNestedHitObjects(); - tickContainer.Clear(); + tickContainer.Clear(false); } protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 9798a79450..60f9521996 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -153,7 +153,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override void ClearNestedHitObjects() { base.ClearNestedHitObjects(); - ticks.Clear(); + ticks.Clear(false); } protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs index 62f338ca91..4f1523eb3f 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs @@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override void ClearNestedHitObjects() { base.ClearNestedHitObjects(); - strongHitContainer.Clear(); + strongHitContainer.Clear(false); } protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject) From 370f56eadbb97aa1ed05d7bc1952e3b35924430f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 20 Dec 2020 18:02:31 +0100 Subject: [PATCH 167/328] Make strong hit DHOs public for pool registration --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs | 2 +- .../Objects/Drawables/DrawableDrumRollTick.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index d085b95f35..d066abf767 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -174,7 +174,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables (MainPiece.Drawable as IHasAccentColour)?.FadeAccent(newColour, fadeDuration); } - private class StrongNestedHit : DrawableStrongNestedHit + public class StrongNestedHit : DrawableStrongNestedHit { public new DrawableDrumRoll ParentHitObject => (DrawableDrumRoll)base.ParentHitObject; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index 1e625d91d6..0df45c424d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override DrawableStrongNestedHit CreateStrongNestedHit(DrumRollTick.StrongNestedHit hitObject) => new StrongNestedHit(hitObject); - private class StrongNestedHit : DrawableStrongNestedHit + public class StrongNestedHit : DrawableStrongNestedHit { public new DrawableDrumRollTick ParentHitObject => (DrawableDrumRollTick)base.ParentHitObject; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 73ebd7c117..38cda69a46 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -252,7 +252,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override DrawableStrongNestedHit CreateStrongNestedHit(Hit.StrongNestedHit hitObject) => new StrongNestedHit(hitObject); - private class StrongNestedHit : DrawableStrongNestedHit + public class StrongNestedHit : DrawableStrongNestedHit { public new DrawableHit ParentHitObject => (DrawableHit)base.ParentHitObject; From 62da4eff37db8dfc1cfeaeac7d35190eab54356a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 20 Dec 2020 18:07:59 +0100 Subject: [PATCH 168/328] Route new result callback via playfield Follows route taken by osu! and catch (and required for proper pooling support). --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 8682495b41..6b001d6c70 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -149,6 +149,12 @@ namespace osu.Game.Rulesets.Taiko.UI }; } + protected override void LoadComplete() + { + base.LoadComplete(); + NewResult += OnNewResult; + } + protected override void Update() { base.Update(); @@ -208,7 +214,6 @@ namespace osu.Game.Rulesets.Taiko.UI break; case DrawableTaikoHitObject taikoObject: - h.OnNewResult += OnNewResult; topLevelHitContainer.Add(taikoObject.CreateProxiedContent()); base.Add(h); break; @@ -226,7 +231,6 @@ namespace osu.Game.Rulesets.Taiko.UI return barLinePlayfield.Remove(barLine); case DrawableTaikoHitObject _: - h.OnNewResult -= OnNewResult; // todo: consider tidying of proxied content if required. return base.Remove(h); From 5d575d2a9b8dd95d8c06e9ef9f1b91214b7794d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 20 Dec 2020 18:11:29 +0100 Subject: [PATCH 169/328] Accept proxied content via OnNewDrawableHitObject In the non-pooled case, `OnNewDrawableHitObject()` will be called automatically on each new DHO via `Playfield.Add(DrawableHitObject)`. In the pooled case, it will be called via `Playfield`'s implementation of `GetPooledDrawableRepresentation(HitObject, DrawableHitObject)`. --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 6b001d6c70..b3bf0974c3 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -155,6 +155,14 @@ namespace osu.Game.Rulesets.Taiko.UI NewResult += OnNewResult; } + protected override void OnNewDrawableHitObject(DrawableHitObject drawableHitObject) + { + base.OnNewDrawableHitObject(drawableHitObject); + + var taikoObject = (DrawableTaikoHitObject)drawableHitObject; + topLevelHitContainer.Add(taikoObject.CreateProxiedContent()); + } + protected override void Update() { base.Update(); @@ -213,8 +221,7 @@ namespace osu.Game.Rulesets.Taiko.UI barLinePlayfield.Add(barLine); break; - case DrawableTaikoHitObject taikoObject: - topLevelHitContainer.Add(taikoObject.CreateProxiedContent()); + case DrawableTaikoHitObject _: base.Add(h); break; @@ -231,7 +238,6 @@ namespace osu.Game.Rulesets.Taiko.UI return barLinePlayfield.Remove(barLine); case DrawableTaikoHitObject _: - // todo: consider tidying of proxied content if required. return base.Remove(h); default: From b24fc1922e11b103243ef24e361609376c353b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 20 Dec 2020 18:16:05 +0100 Subject: [PATCH 170/328] Enable pooling for taiko DHOs --- .../UI/DrawableTaikoRuleset.cs | 18 +----------------- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index 9cf931ee0a..ed8e6859a2 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -7,7 +7,6 @@ using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects; -using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.Taiko.Replays; using osu.Framework.Input; @@ -64,22 +63,7 @@ namespace osu.Game.Rulesets.Taiko.UI protected override Playfield CreatePlayfield() => new TaikoPlayfield(Beatmap.ControlPointInfo); - public override DrawableHitObject CreateDrawableRepresentation(TaikoHitObject h) - { - switch (h) - { - case Hit hit: - return new DrawableHit(hit); - - case DrumRoll drumRoll: - return new DrawableDrumRoll(drumRoll); - - case Swell swell: - return new DrawableSwell(swell); - } - - return null; - } + public override DrawableHitObject CreateDrawableRepresentation(TaikoHitObject h) => null; protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new TaikoFramedReplayInputHandler(replay); diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index b3bf0974c3..148ec7755e 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -147,6 +147,18 @@ namespace osu.Game.Rulesets.Taiko.UI }, drumRollHitContainer.CreateProxy(), }; + + RegisterPool(50); + RegisterPool(50); + + RegisterPool(5); + RegisterPool(5); + + RegisterPool(100); + RegisterPool(100); + + RegisterPool(5); + RegisterPool(100); } protected override void LoadComplete() From 6e21806873976561322499602e516ee0a6c29d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 20 Dec 2020 18:25:49 +0100 Subject: [PATCH 171/328] Adjust sample test to pass with pooling --- .../TestSceneSampleOutput.cs | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneSampleOutput.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneSampleOutput.cs index 4ba9c447fb..296468d98d 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneSampleOutput.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneSampleOutput.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using System.Linq; using osu.Framework.Testing; using osu.Game.Audio; @@ -18,24 +19,33 @@ namespace osu.Game.Rulesets.Taiko.Tests public override void SetUpSteps() { base.SetUpSteps(); - AddAssert("has correct samples", () => + + var expectedSampleNames = new[] { - var names = Player.DrawableRuleset.Playfield.AllHitObjects.OfType().Select(h => string.Join(',', h.GetSamples().Select(s => s.Name))); + string.Empty, + string.Empty, + string.Empty, + string.Empty, + HitSampleInfo.HIT_FINISH, + HitSampleInfo.HIT_WHISTLE, + HitSampleInfo.HIT_WHISTLE, + HitSampleInfo.HIT_WHISTLE, + }; + var actualSampleNames = new List(); - var expected = new[] - { - string.Empty, - string.Empty, - string.Empty, - string.Empty, - HitSampleInfo.HIT_FINISH, - HitSampleInfo.HIT_WHISTLE, - HitSampleInfo.HIT_WHISTLE, - HitSampleInfo.HIT_WHISTLE, - }; + // due to pooling we can't access all samples right away due to object re-use, + // so we need to collect as we go. + AddStep("collect sample names", () => Player.DrawableRuleset.Playfield.NewResult += (dho, _) => + { + if (!(dho is DrawableHit h)) + return; - return names.SequenceEqual(expected); + actualSampleNames.Add(string.Join(',', h.GetSamples().Select(s => s.Name))); }); + + AddUntilStep("all samples collected", () => actualSampleNames.Count == expectedSampleNames.Length); + + AddAssert("samples are correct", () => actualSampleNames.SequenceEqual(expectedSampleNames)); } protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TaikoBeatmapConversionTest().GetBeatmap("sample-to-type-conversions"); From a8569fe15cdf663685d960e69356205b11944f8a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Dec 2020 13:35:46 +0900 Subject: [PATCH 172/328] Fix a couple of simple cases of incorrect TextureLoaderStore initialisation --- osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs | 3 ++- osu.Game/Storyboards/Drawables/DrawableStoryboard.cs | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs b/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs index a9b2a15b35..b13b20dae2 100644 --- a/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs +++ b/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs @@ -13,6 +13,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; +using osu.Framework.Platform; using osu.Game.Rulesets.Configuration; namespace osu.Game.Rulesets.UI @@ -46,7 +47,7 @@ namespace osu.Game.Rulesets.UI if (resources != null) { - TextureStore = new TextureStore(new TextureLoaderStore(new NamespacedResourceStore(resources, @"Textures"))); + TextureStore = new TextureStore(parent.Get().CreateTextureLoaderStore(new NamespacedResourceStore(resources, @"Textures"))); CacheAs(TextureStore = new FallbackTextureStore(TextureStore, parent.Get())); SampleStore = parent.Get().GetSampleStore(new NamespacedResourceStore(resources, @"Samples")); diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index 4bc28e6cef..af4615c895 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; +using osu.Framework.Platform; using osu.Game.IO; using osu.Game.Screens.Play; @@ -59,12 +60,12 @@ namespace osu.Game.Storyboards.Drawables } [BackgroundDependencyLoader(true)] - private void load(FileStore fileStore, GameplayClock clock, CancellationToken? cancellationToken) + private void load(FileStore fileStore, GameplayClock clock, CancellationToken? cancellationToken, GameHost host) { if (clock != null) Clock = clock; - dependencies.Cache(new TextureStore(new TextureLoaderStore(fileStore.Store), false, scaleAdjust: 1)); + dependencies.Cache(new TextureStore(host.CreateTextureLoaderStore(fileStore.Store), false, scaleAdjust: 1)); foreach (var layer in Storyboard.Layers) { From 7c804be4d3c0dd28ba9cbe3c8eabb771bcc32670 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Dec 2020 14:06:33 +0900 Subject: [PATCH 173/328] Rename textureStore to make its purpose more clear --- osu.Game/Beatmaps/BeatmapManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 33e024fa28..c9d507d068 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -68,7 +68,7 @@ namespace osu.Game.Beatmaps private readonly RulesetStore rulesets; private readonly BeatmapStore beatmaps; private readonly AudioManager audioManager; - private readonly TextureStore textureStore; + private readonly LargeTextureStore largeTextureStore; private readonly ITrackStore trackStore; [CanBeNull] @@ -92,7 +92,7 @@ namespace osu.Game.Beatmaps if (performOnlineLookups) onlineLookupQueue = new BeatmapOnlineLookupQueue(api, storage); - textureStore = new LargeTextureStore(host?.CreateTextureLoaderStore(Files.Store)); + largeTextureStore = new LargeTextureStore(host?.CreateTextureLoaderStore(Files.Store)); trackStore = audioManager.GetTrackStore(Files.Store); } @@ -302,7 +302,7 @@ namespace osu.Game.Beatmaps beatmapInfo.Metadata ??= beatmapInfo.BeatmapSet.Metadata; - workingCache.Add(working = new BeatmapManagerWorkingBeatmap(Files.Store, textureStore, trackStore, beatmapInfo, audioManager)); + workingCache.Add(working = new BeatmapManagerWorkingBeatmap(Files.Store, largeTextureStore, trackStore, beatmapInfo, audioManager)); return working; } From 0ffbe12fcc2c13af237d71aa06d1e0ccc170651b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Dec 2020 14:06:50 +0900 Subject: [PATCH 174/328] Expose resources to beatmaps in a saner way --- osu.Game/Beatmaps/BeatmapManager.cs | 16 ++++++-- .../Beatmaps/BeatmapManager_WorkingBeatmap.cs | 28 +++++-------- osu.Game/Beatmaps/IBeatmapResourceProvider.cs | 40 +++++++++++++++++++ 3 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 osu.Game/Beatmaps/IBeatmapResourceProvider.cs diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index c9d507d068..4b334952ef 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -16,6 +16,7 @@ using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics.Textures; +using osu.Framework.IO.Stores; using osu.Framework.Lists; using osu.Framework.Logging; using osu.Framework.Platform; @@ -28,8 +29,8 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Rulesets; using osu.Game.Rulesets.Objects; -using osu.Game.Users; using osu.Game.Skinning; +using osu.Game.Users; using Decoder = osu.Game.Beatmaps.Formats.Decoder; namespace osu.Game.Beatmaps @@ -38,7 +39,7 @@ namespace osu.Game.Beatmaps /// Handles the storage and retrieval of Beatmaps/WorkingBeatmaps. /// [ExcludeFromDynamicCompile] - public partial class BeatmapManager : DownloadableArchiveModelManager, IDisposable + public partial class BeatmapManager : DownloadableArchiveModelManager, IDisposable, IBeatmapResourceProvider { /// /// Fired when a single difficulty has been hidden. @@ -71,6 +72,8 @@ namespace osu.Game.Beatmaps private readonly LargeTextureStore largeTextureStore; private readonly ITrackStore trackStore; + private readonly GameHost host; + [CanBeNull] private readonly BeatmapOnlineLookupQueue onlineLookupQueue; @@ -80,6 +83,7 @@ namespace osu.Game.Beatmaps { this.rulesets = rulesets; this.audioManager = audioManager; + this.host = host; DefaultBeatmap = defaultBeatmap; @@ -302,7 +306,7 @@ namespace osu.Game.Beatmaps beatmapInfo.Metadata ??= beatmapInfo.BeatmapSet.Metadata; - workingCache.Add(working = new BeatmapManagerWorkingBeatmap(Files.Store, largeTextureStore, trackStore, beatmapInfo, audioManager)); + workingCache.Add(working = new BeatmapManagerWorkingBeatmap(beatmapInfo, this)); return working; } @@ -492,6 +496,12 @@ namespace osu.Game.Beatmaps onlineLookupQueue?.Dispose(); } + TextureStore IBeatmapResourceProvider.LargeTextureStore => largeTextureStore; + ITrackStore IBeatmapResourceProvider.Tracks => trackStore; + AudioManager IBeatmapResourceProvider.AudioManager => audioManager; + IResourceStore IBeatmapResourceProvider.Files => Files.Store; + IResourceStore IBeatmapResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore); + /// /// A dummy WorkingBeatmap for the purpose of retrieving a beatmap for star difficulty calculation. /// diff --git a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs index f5c0d97c1f..1d9a496e36 100644 --- a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs @@ -3,10 +3,8 @@ using System; using System.Linq; -using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Graphics.Textures; -using osu.Framework.IO.Stores; using osu.Framework.Logging; using osu.Framework.Testing; using osu.Game.Beatmaps.Formats; @@ -21,16 +19,12 @@ namespace osu.Game.Beatmaps [ExcludeFromDynamicCompile] private class BeatmapManagerWorkingBeatmap : WorkingBeatmap { - private readonly IResourceStore store; - private readonly TextureStore textureStore; - private readonly ITrackStore trackStore; + private readonly IBeatmapResourceProvider resources; - public BeatmapManagerWorkingBeatmap(IResourceStore store, TextureStore textureStore, ITrackStore trackStore, BeatmapInfo beatmapInfo, AudioManager audioManager) - : base(beatmapInfo, audioManager) + public BeatmapManagerWorkingBeatmap(BeatmapInfo beatmapInfo, IBeatmapResourceProvider resources) + : base(beatmapInfo, resources?.AudioManager) { - this.store = store; - this.textureStore = textureStore; - this.trackStore = trackStore; + this.resources = resources; } protected override IBeatmap GetBeatmap() @@ -40,7 +34,7 @@ namespace osu.Game.Beatmaps try { - using (var stream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) + using (var stream = new LineBufferedReader(resources.Files.GetStream(getPathForFile(BeatmapInfo.Path)))) return Decoder.GetDecoder(stream).Decode(stream); } catch (Exception e) @@ -61,7 +55,7 @@ namespace osu.Game.Beatmaps try { - return textureStore.Get(getPathForFile(Metadata.BackgroundFile)); + return resources.LargeTextureStore.Get(getPathForFile(Metadata.BackgroundFile)); } catch (Exception e) { @@ -77,7 +71,7 @@ namespace osu.Game.Beatmaps try { - return trackStore.Get(getPathForFile(Metadata.AudioFile)); + return resources.Tracks.Get(getPathForFile(Metadata.AudioFile)); } catch (Exception e) { @@ -93,7 +87,7 @@ namespace osu.Game.Beatmaps try { - var trackData = store.GetStream(getPathForFile(Metadata.AudioFile)); + var trackData = resources.Files.GetStream(getPathForFile(Metadata.AudioFile)); return trackData == null ? null : new Waveform(trackData); } catch (Exception e) @@ -109,7 +103,7 @@ namespace osu.Game.Beatmaps try { - using (var stream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) + using (var stream = new LineBufferedReader(resources.Files.GetStream(getPathForFile(BeatmapInfo.Path)))) { var decoder = Decoder.GetDecoder(stream); @@ -118,7 +112,7 @@ namespace osu.Game.Beatmaps storyboard = decoder.Decode(stream); else { - using (var secondaryStream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile)))) + using (var secondaryStream = new LineBufferedReader(resources.Files.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile)))) storyboard = decoder.Decode(stream, secondaryStream); } } @@ -138,7 +132,7 @@ namespace osu.Game.Beatmaps { try { - return new LegacyBeatmapSkin(BeatmapInfo, store, AudioManager); + return new LegacyBeatmapSkin(BeatmapInfo, resources.Files, AudioManager); } catch (Exception e) { diff --git a/osu.Game/Beatmaps/IBeatmapResourceProvider.cs b/osu.Game/Beatmaps/IBeatmapResourceProvider.cs new file mode 100644 index 0000000000..43d1a60784 --- /dev/null +++ b/osu.Game/Beatmaps/IBeatmapResourceProvider.cs @@ -0,0 +1,40 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Audio; +using osu.Framework.Audio.Track; +using osu.Framework.Graphics.Textures; +using osu.Framework.IO.Stores; + +namespace osu.Game.Beatmaps +{ + public interface IBeatmapResourceProvider + { + /// + /// Retrieve a global large texture store, used for loading beatmap backgrounds. + /// + TextureStore LargeTextureStore { get; } + + /// + /// Access a global track store for retrieving beatmap tracks from. + /// + ITrackStore Tracks { get; } + + /// + /// Retrieve the game-wide audio manager. + /// + AudioManager AudioManager { get; } + + /// + /// Access game-wide user files. + /// + IResourceStore Files { get; } + + /// + /// Create a texture loader store based on an underlying data store. + /// + /// The underlying provider of texture data (in arbitrary image formats). + /// A texture loader store. + IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore); + } +} From a5bcf1dc20b31f6fb318dd3bdc7f7be40ae078f8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Dec 2020 15:14:32 +0900 Subject: [PATCH 175/328] Expose resources to skin via interface (and share common pieces with beatmap) --- .../Gameplay/TestSceneStoryboardSamples.cs | 28 +++++++++++------- osu.Game/Beatmaps/BeatmapManager.cs | 6 ++-- .../Beatmaps/BeatmapManager_WorkingBeatmap.cs | 2 +- osu.Game/Beatmaps/IBeatmapResourceProvider.cs | 22 ++------------ osu.Game/IO/IStorageResourceProvider.cs | 29 +++++++++++++++++++ osu.Game/Skinning/DefaultLegacySkin.cs | 6 ++-- osu.Game/Skinning/LegacyBeatmapSkin.cs | 6 ++-- osu.Game/Skinning/LegacySkin.cs | 11 ++++--- osu.Game/Skinning/SkinManager.cs | 19 ++++++++---- .../Tests/Beatmaps/HitObjectSampleTest.cs | 20 +++++++++---- .../Tests/Visual/LegacySkinPlayerTestScene.cs | 5 ++-- osu.Game/Tests/Visual/SkinnableTestScene.cs | 23 ++++++++++----- 12 files changed, 109 insertions(+), 68 deletions(-) create mode 100644 osu.Game/IO/IStorageResourceProvider.cs diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs index d46769a7c0..36f99c5599 100644 --- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs @@ -10,9 +10,11 @@ using NUnit.Framework; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Graphics.Audio; +using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Framework.Testing; using osu.Game.Audio; +using osu.Game.IO; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; @@ -27,7 +29,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Gameplay { [HeadlessTest] - public class TestSceneStoryboardSamples : OsuTestScene + public class TestSceneStoryboardSamples : OsuTestScene, IStorageResourceProvider { [Test] public void TestRetrieveTopLevelSample() @@ -35,7 +37,7 @@ namespace osu.Game.Tests.Gameplay ISkin skin = null; SampleChannel channel = null; - AddStep("create skin", () => skin = new TestSkin("test-sample", Audio)); + AddStep("create skin", () => skin = new TestSkin("test-sample", this)); AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("test-sample"))); AddAssert("sample is non-null", () => channel != null); @@ -47,7 +49,7 @@ namespace osu.Game.Tests.Gameplay ISkin skin = null; SampleChannel channel = null; - AddStep("create skin", () => skin = new TestSkin("folder/test-sample", Audio)); + AddStep("create skin", () => skin = new TestSkin("folder/test-sample", this)); AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("folder/test-sample"))); AddAssert("sample is non-null", () => channel != null); @@ -105,7 +107,7 @@ namespace osu.Game.Tests.Gameplay AddStep("setup storyboard sample", () => { - Beatmap.Value = new TestCustomSkinWorkingBeatmap(new OsuRuleset().RulesetInfo, Audio); + Beatmap.Value = new TestCustomSkinWorkingBeatmap(new OsuRuleset().RulesetInfo, this); SelectedMods.Value = new[] { testedMod }; var beatmapSkinSourceContainer = new BeatmapSkinProvidingContainer(Beatmap.Value.Skin); @@ -128,8 +130,8 @@ namespace osu.Game.Tests.Gameplay private class TestSkin : LegacySkin { - public TestSkin(string resourceName, AudioManager audioManager) - : base(DefaultLegacySkin.Info, new TestResourceStore(resourceName), audioManager, "skin.ini") + public TestSkin(string resourceName, IStorageResourceProvider resources) + : base(DefaultLegacySkin.Info, new TestResourceStore(resourceName), resources, "skin.ini") { } } @@ -158,15 +160,15 @@ namespace osu.Game.Tests.Gameplay private class TestCustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap { - private readonly AudioManager audio; + private readonly IStorageResourceProvider resources; - public TestCustomSkinWorkingBeatmap(RulesetInfo ruleset, AudioManager audio) - : base(ruleset, null, audio) + public TestCustomSkinWorkingBeatmap(RulesetInfo ruleset, IStorageResourceProvider resources) + : base(ruleset, null, resources.AudioManager) { - this.audio = audio; + this.resources = resources; } - protected override ISkin GetSkin() => new TestSkin("test-sample", audio); + protected override ISkin GetSkin() => new TestSkin("test-sample", resources); } private class TestDrawableStoryboardSample : DrawableStoryboardSample @@ -176,5 +178,9 @@ namespace osu.Game.Tests.Gameplay { } } + + public AudioManager AudioManager => Audio; + public IResourceStore Files => null; + public IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => null; } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 4b334952ef..3cf691da9a 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -498,9 +498,9 @@ namespace osu.Game.Beatmaps TextureStore IBeatmapResourceProvider.LargeTextureStore => largeTextureStore; ITrackStore IBeatmapResourceProvider.Tracks => trackStore; - AudioManager IBeatmapResourceProvider.AudioManager => audioManager; - IResourceStore IBeatmapResourceProvider.Files => Files.Store; - IResourceStore IBeatmapResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore); + AudioManager IStorageResourceProvider.AudioManager => audioManager; + IResourceStore IStorageResourceProvider.Files => Files.Store; + IResourceStore IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore); /// /// A dummy WorkingBeatmap for the purpose of retrieving a beatmap for star difficulty calculation. diff --git a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs index 1d9a496e36..5d298dbccc 100644 --- a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs @@ -132,7 +132,7 @@ namespace osu.Game.Beatmaps { try { - return new LegacyBeatmapSkin(BeatmapInfo, resources.Files, AudioManager); + return new LegacyBeatmapSkin(BeatmapInfo, resources.Files, resources); } catch (Exception e) { diff --git a/osu.Game/Beatmaps/IBeatmapResourceProvider.cs b/osu.Game/Beatmaps/IBeatmapResourceProvider.cs index 43d1a60784..dfea0c7a30 100644 --- a/osu.Game/Beatmaps/IBeatmapResourceProvider.cs +++ b/osu.Game/Beatmaps/IBeatmapResourceProvider.cs @@ -1,14 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Graphics.Textures; -using osu.Framework.IO.Stores; +using osu.Game.IO; namespace osu.Game.Beatmaps { - public interface IBeatmapResourceProvider + public interface IBeatmapResourceProvider : IStorageResourceProvider { /// /// Retrieve a global large texture store, used for loading beatmap backgrounds. @@ -19,22 +18,5 @@ namespace osu.Game.Beatmaps /// Access a global track store for retrieving beatmap tracks from. /// ITrackStore Tracks { get; } - - /// - /// Retrieve the game-wide audio manager. - /// - AudioManager AudioManager { get; } - - /// - /// Access game-wide user files. - /// - IResourceStore Files { get; } - - /// - /// Create a texture loader store based on an underlying data store. - /// - /// The underlying provider of texture data (in arbitrary image formats). - /// A texture loader store. - IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore); } } diff --git a/osu.Game/IO/IStorageResourceProvider.cs b/osu.Game/IO/IStorageResourceProvider.cs new file mode 100644 index 0000000000..cbd1039807 --- /dev/null +++ b/osu.Game/IO/IStorageResourceProvider.cs @@ -0,0 +1,29 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Audio; +using osu.Framework.Graphics.Textures; +using osu.Framework.IO.Stores; + +namespace osu.Game.IO +{ + public interface IStorageResourceProvider + { + /// + /// Retrieve the game-wide audio manager. + /// + AudioManager AudioManager { get; } + + /// + /// Access game-wide user files. + /// + IResourceStore Files { get; } + + /// + /// Create a texture loader store based on an underlying data store. + /// + /// The underlying provider of texture data (in arbitrary image formats). + /// A texture loader store. + IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore); + } +} diff --git a/osu.Game/Skinning/DefaultLegacySkin.cs b/osu.Game/Skinning/DefaultLegacySkin.cs index 2758a4cbba..4027cc650d 100644 --- a/osu.Game/Skinning/DefaultLegacySkin.cs +++ b/osu.Game/Skinning/DefaultLegacySkin.cs @@ -1,16 +1,16 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Audio; using osu.Framework.IO.Stores; +using osu.Game.IO; using osuTK.Graphics; namespace osu.Game.Skinning { public class DefaultLegacySkin : LegacySkin { - public DefaultLegacySkin(IResourceStore storage, AudioManager audioManager) - : base(Info, storage, audioManager, string.Empty) + public DefaultLegacySkin(IResourceStore storage, IStorageResourceProvider resources) + : base(Info, storage, resources, string.Empty) { Configuration.CustomColours["SliderBall"] = new Color4(2, 170, 255, 255); Configuration.AddComboColours( diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index d647bc4a2d..fdcb81b574 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -1,12 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.IO.Stores; using osu.Game.Audio; using osu.Game.Beatmaps; +using osu.Game.IO; using osu.Game.Rulesets.Objects.Legacy; namespace osu.Game.Skinning @@ -16,8 +16,8 @@ namespace osu.Game.Skinning protected override bool AllowManiaSkin => false; protected override bool UseCustomSampleBanks => true; - public LegacyBeatmapSkin(BeatmapInfo beatmap, IResourceStore storage, AudioManager audioManager) - : base(createSkinInfo(beatmap), new LegacySkinResourceStore(beatmap.BeatmapSet, storage), audioManager, beatmap.Path) + public LegacyBeatmapSkin(BeatmapInfo beatmap, IResourceStore storage, IStorageResourceProvider resources) + : base(createSkinInfo(beatmap), new LegacySkinResourceStore(beatmap.BeatmapSet, storage), resources, beatmap.Path) { // Disallow default colours fallback on beatmap skins to allow using parent skin combo colours. (via SkinProvidingContainer) Configuration.AllowDefaultComboColoursFallback = false; diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 80b2fef35c..5a7ad095f6 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -7,7 +7,6 @@ using System.Diagnostics; using System.IO; using System.Linq; using JetBrains.Annotations; -using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -54,12 +53,12 @@ namespace osu.Game.Skinning private readonly Dictionary maniaConfigurations = new Dictionary(); - public LegacySkin(SkinInfo skin, IResourceStore storage, AudioManager audioManager) - : this(skin, new LegacySkinResourceStore(skin, storage), audioManager, "skin.ini") + public LegacySkin(SkinInfo skin, IStorageResourceProvider resources) + : this(skin, new LegacySkinResourceStore(skin, resources.Files), resources, "skin.ini") { } - protected LegacySkin(SkinInfo skin, IResourceStore storage, AudioManager audioManager, string filename) + protected LegacySkin(SkinInfo skin, IResourceStore storage, IStorageResourceProvider resources, string filename) : base(skin) { using (var stream = storage?.GetStream(filename)) @@ -85,12 +84,12 @@ namespace osu.Game.Skinning if (storage != null) { - var samples = audioManager?.GetSampleStore(storage); + var samples = resources?.AudioManager?.GetSampleStore(storage); if (samples != null) samples.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY; Samples = samples; - Textures = new TextureStore(new TextureLoaderStore(storage)); + Textures = new TextureStore(resources?.CreateTextureLoaderStore(storage)); (storage as ResourceStore)?.AddExtension("ogg"); } diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 9b69a1eecd..2ee940c02d 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -22,15 +22,18 @@ using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Audio; using osu.Game.Database; +using osu.Game.IO; using osu.Game.IO.Archives; namespace osu.Game.Skinning { [ExcludeFromDynamicCompile] - public class SkinManager : ArchiveModelManager, ISkinSource + public class SkinManager : ArchiveModelManager, ISkinSource, IStorageResourceProvider { private readonly AudioManager audio; + private readonly GameHost host; + private readonly IResourceStore legacyDefaultResources; public readonly Bindable CurrentSkin = new Bindable(new DefaultSkin()); @@ -42,10 +45,12 @@ namespace osu.Game.Skinning protected override string ImportFromStablePath => "Skins"; - public SkinManager(Storage storage, DatabaseContextFactory contextFactory, IIpcHost importHost, AudioManager audio, IResourceStore legacyDefaultResources) - : base(storage, contextFactory, new SkinStore(contextFactory, storage), importHost) + public SkinManager(Storage storage, DatabaseContextFactory contextFactory, GameHost host, AudioManager audio, IResourceStore legacyDefaultResources) + : base(storage, contextFactory, new SkinStore(contextFactory, storage), host) { this.audio = audio; + this.host = host; + this.legacyDefaultResources = legacyDefaultResources; CurrentSkinInfo.ValueChanged += skin => CurrentSkin.Value = GetSkin(skin.NewValue); @@ -148,9 +153,9 @@ namespace osu.Game.Skinning return new DefaultSkin(); if (skinInfo == DefaultLegacySkin.Info) - return new DefaultLegacySkin(legacyDefaultResources, audio); + return new DefaultLegacySkin(legacyDefaultResources, this); - return new LegacySkin(skinInfo, Files.Store, audio); + return new LegacySkin(skinInfo, this); } /// @@ -169,5 +174,9 @@ namespace osu.Game.Skinning public SampleChannel GetSample(ISampleInfo sampleInfo) => CurrentSkin.Value.GetSample(sampleInfo); public IBindable GetConfig(TLookup lookup) => CurrentSkin.Value.GetConfig(lookup); + + AudioManager IStorageResourceProvider.AudioManager => audio; + IResourceStore IStorageResourceProvider.Files => Files.Store; + IResourceStore IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore); } } diff --git a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs index e3557222d5..dd1979a7e3 100644 --- a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs +++ b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Framework.Testing; using osu.Framework.Timing; @@ -25,7 +26,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Beatmaps { [HeadlessTest] - public abstract class HitObjectSampleTest : PlayerTestScene + public abstract class HitObjectSampleTest : PlayerTestScene, IStorageResourceProvider { protected abstract IResourceStore Resources { get; } protected LegacySkin Skin { get; private set; } @@ -58,7 +59,7 @@ namespace osu.Game.Tests.Beatmaps protected sealed override IBeatmap CreateBeatmap(RulesetInfo ruleset) => currentTestBeatmap; protected sealed override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) - => new TestWorkingBeatmap(beatmapInfo, beatmapSkinResourceStore, beatmap, storyboard, Clock, Audio); + => new TestWorkingBeatmap(beatmapInfo, beatmapSkinResourceStore, beatmap, storyboard, Clock, this); protected override TestPlayer CreatePlayer(Ruleset ruleset) => new TestPlayer(false); @@ -109,7 +110,7 @@ namespace osu.Game.Tests.Beatmaps }; // Need to refresh the cached skin source to refresh the skin resource store. - dependencies.SkinSource = new SkinProvidingContainer(Skin = new LegacySkin(userSkinInfo, userSkinResourceStore, Audio)); + dependencies.SkinSource = new SkinProvidingContainer(Skin = new LegacySkin(userSkinInfo, this)); }); } @@ -122,6 +123,10 @@ namespace osu.Game.Tests.Beatmaps protected void AssertNoLookup(string name) => AddAssert($"\"{name}\" not looked up", () => !beatmapSkinResourceStore.PerformedLookups.Contains(name) && !userSkinResourceStore.PerformedLookups.Contains(name)); + public AudioManager AudioManager => Audio; + public IResourceStore Files => userSkinResourceStore; + public IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => null; + private class SkinSourceDependencyContainer : IReadOnlyDependencyContainer { public ISkinSource SkinSource; @@ -191,14 +196,17 @@ namespace osu.Game.Tests.Beatmaps private readonly BeatmapInfo skinBeatmapInfo; private readonly IResourceStore resourceStore; - public TestWorkingBeatmap(BeatmapInfo skinBeatmapInfo, IResourceStore resourceStore, IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock referenceClock, AudioManager audio) - : base(beatmap, storyboard, referenceClock, audio) + private readonly IStorageResourceProvider resources; + + public TestWorkingBeatmap(BeatmapInfo skinBeatmapInfo, IResourceStore resourceStore, IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock referenceClock, IStorageResourceProvider resources) + : base(beatmap, storyboard, referenceClock, resources.AudioManager) { this.skinBeatmapInfo = skinBeatmapInfo; this.resourceStore = resourceStore; + this.resources = resources; } - protected override ISkin GetSkin() => new LegacyBeatmapSkin(skinBeatmapInfo, resourceStore, AudioManager); + protected override ISkin GetSkin() => new LegacyBeatmapSkin(skinBeatmapInfo, resourceStore, resources); } } } diff --git a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs index 054f72400e..c186525757 100644 --- a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs +++ b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs @@ -3,7 +3,6 @@ using NUnit.Framework; using osu.Framework.Allocation; -using osu.Framework.Audio; using osu.Framework.IO.Stores; using osu.Game.Rulesets; using osu.Game.Skinning; @@ -18,9 +17,9 @@ namespace osu.Game.Tests.Visual protected override TestPlayer CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(legacySkinSource); [BackgroundDependencyLoader] - private void load(AudioManager audio, OsuGameBase game) + private void load(OsuGameBase game, SkinManager skins) { - var legacySkin = new DefaultLegacySkin(new NamespacedResourceStore(game.Resources, "Skins/Legacy"), audio); + var legacySkin = new DefaultLegacySkin(new NamespacedResourceStore(game.Resources, "Skins/Legacy"), skins); legacySkinSource = new SkinProvidingContainer(legacySkin); } diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index 68098f9d3b..3a9c33788a 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -13,8 +13,10 @@ using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; +using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Graphics.Sprites; +using osu.Game.IO; using osu.Game.Rulesets; using osu.Game.Skinning; using osuTK; @@ -22,13 +24,16 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual { - public abstract class SkinnableTestScene : OsuGridTestScene + public abstract class SkinnableTestScene : OsuGridTestScene, IStorageResourceProvider { private Skin metricsSkin; private Skin defaultSkin; private Skin specialSkin; private Skin oldSkin; + [Resolved] + private GameHost host { get; set; } + protected SkinnableTestScene() : base(2, 3) { @@ -39,10 +44,10 @@ namespace osu.Game.Tests.Visual { var dllStore = new DllResourceStore(DynamicCompilationOriginal.GetType().Assembly); - metricsSkin = new TestLegacySkin(new SkinInfo { Name = "metrics-skin" }, new NamespacedResourceStore(dllStore, "Resources/metrics_skin"), audio, true); - defaultSkin = new DefaultLegacySkin(new NamespacedResourceStore(game.Resources, "Skins/Legacy"), audio); - specialSkin = new TestLegacySkin(new SkinInfo { Name = "special-skin" }, new NamespacedResourceStore(dllStore, "Resources/special_skin"), audio, true); - oldSkin = new TestLegacySkin(new SkinInfo { Name = "old-skin" }, new NamespacedResourceStore(dllStore, "Resources/old_skin"), audio, true); + metricsSkin = new TestLegacySkin(new SkinInfo { Name = "metrics-skin" }, new NamespacedResourceStore(dllStore, "Resources/metrics_skin"), this, true); + defaultSkin = new DefaultLegacySkin(new NamespacedResourceStore(game.Resources, "Skins/Legacy"), this); + specialSkin = new TestLegacySkin(new SkinInfo { Name = "special-skin" }, new NamespacedResourceStore(dllStore, "Resources/special_skin"), this, true); + oldSkin = new TestLegacySkin(new SkinInfo { Name = "old-skin" }, new NamespacedResourceStore(dllStore, "Resources/old_skin"), this, true); } private readonly List createdDrawables = new List(); @@ -147,6 +152,10 @@ namespace osu.Game.Tests.Visual protected virtual IBeatmap CreateBeatmapForSkinProvider() => CreateWorkingBeatmap(Ruleset.Value).GetPlayableBeatmap(Ruleset.Value); + public AudioManager AudioManager => Audio; + public IResourceStore Files => null; + public IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore); + private class OutlineBox : CompositeDrawable { public OutlineBox() @@ -170,8 +179,8 @@ namespace osu.Game.Tests.Visual { private readonly bool extrapolateAnimations; - public TestLegacySkin(SkinInfo skin, IResourceStore storage, AudioManager audioManager, bool extrapolateAnimations) - : base(skin, storage, audioManager, "skin.ini") + public TestLegacySkin(SkinInfo skin, IResourceStore storage, IStorageResourceProvider resources, bool extrapolateAnimations) + : base(skin, storage, resources, "skin.ini") { this.extrapolateAnimations = extrapolateAnimations; } From 82cf58353ce15e45770bea510181769abeaee846 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 15:38:20 +0900 Subject: [PATCH 176/328] Fix incorrect joinedroom null checks --- osu.Game/Screens/Multi/Components/RoomManager.cs | 2 +- .../Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/Components/RoomManager.cs b/osu.Game/Screens/Multi/Components/RoomManager.cs index 276a5a6148..482ee5492c 100644 --- a/osu.Game/Screens/Multi/Components/RoomManager.cs +++ b/osu.Game/Screens/Multi/Components/RoomManager.cs @@ -112,7 +112,7 @@ namespace osu.Game.Screens.Multi.Components { currentJoinRoomRequest?.Cancel(); - if (JoinedRoom == null) + if (JoinedRoom.Value == null) return; api.Queue(new PartRoomRequest(joinedRoom.Value)); diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index b81ca7aade..e0fca3ce4c 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -45,7 +45,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer public override void PartRoom() { - if (JoinedRoom == null) + if (JoinedRoom.Value == null) return; var joinedRoom = JoinedRoom.Value; From a59124dd938a8c98a276c85299cbbb144f87b190 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 16:18:39 +0900 Subject: [PATCH 177/328] Make room duration/endsat nullable --- .../Visual/Multiplayer/TestSceneRoomStatus.cs | 12 +++++++++--- osu.Game/Online/Multiplayer/Room.cs | 16 +++++++++++----- .../Screens/Multi/Components/RoomStatusInfo.cs | 11 +++++++++-- .../Match/Components/MatchSettingsOverlay.cs | 2 +- osu.Game/Screens/Multi/MultiplayerComposite.cs | 4 ++-- .../Multi/Timeshift/TimeshiftReadyButton.cs | 4 ++-- 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs index c1dfb94464..a6dd1437f7 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs @@ -22,22 +22,28 @@ namespace osu.Game.Tests.Visual.Multiplayer { new DrawableRoom(new Room { - Name = { Value = "Room 1" }, + Name = { Value = "Open - ending in 1 day" }, Status = { Value = new RoomStatusOpen() }, EndDate = { Value = DateTimeOffset.Now.AddDays(1) } }) { MatchingFilter = true }, new DrawableRoom(new Room { - Name = { Value = "Room 2" }, + Name = { Value = "Playing - ending in 1 day" }, Status = { Value = new RoomStatusPlaying() }, EndDate = { Value = DateTimeOffset.Now.AddDays(1) } }) { MatchingFilter = true }, new DrawableRoom(new Room { - Name = { Value = "Room 3" }, + Name = { Value = "Ended" }, Status = { Value = new RoomStatusEnded() }, EndDate = { Value = DateTimeOffset.Now } }) { MatchingFilter = true }, + new DrawableRoom(new Room + { + Name = { Value = "Open (realtime)" }, + Status = { Value = new RoomStatusOpen() }, + Category = { Value = RoomCategory.Realtime } + }) { MatchingFilter = true }, } }; } diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs index 9a21543b2e..ee8992e399 100644 --- a/osu.Game/Online/Multiplayer/Room.cs +++ b/osu.Game/Online/Multiplayer/Room.cs @@ -40,7 +40,7 @@ namespace osu.Game.Online.Multiplayer [Cached] [JsonIgnore] - public readonly Bindable Duration = new Bindable(TimeSpan.FromMinutes(30)); + public readonly Bindable Duration = new Bindable(); [Cached] [JsonIgnore] @@ -78,16 +78,22 @@ namespace osu.Game.Online.Multiplayer } [JsonProperty("duration")] - private int duration + private int? duration { - get => (int)Duration.Value.TotalMinutes; - set => Duration.Value = TimeSpan.FromMinutes(value); + get => (int?)Duration.Value?.TotalMinutes; + set + { + if (value == null) + Duration.Value = null; + else + Duration.Value = TimeSpan.FromMinutes(value.Value); + } } // Only supports retrieval for now [Cached] [JsonProperty("ends_at")] - public readonly Bindable EndDate = new Bindable(); + public readonly Bindable EndDate = new Bindable(); // Todo: Find a better way to do this (https://github.com/ppy/osu-framework/issues/1930) [JsonProperty("max_attempts", DefaultValueHandling = DefaultValueHandling.Ignore)] diff --git a/osu.Game/Screens/Multi/Components/RoomStatusInfo.cs b/osu.Game/Screens/Multi/Components/RoomStatusInfo.cs index d799f846c2..b5676692a4 100644 --- a/osu.Game/Screens/Multi/Components/RoomStatusInfo.cs +++ b/osu.Game/Screens/Multi/Components/RoomStatusInfo.cs @@ -48,16 +48,23 @@ namespace osu.Game.Screens.Multi.Components private class EndDatePart : DrawableDate { - public readonly IBindable EndDate = new Bindable(); + public readonly IBindable EndDate = new Bindable(); public EndDatePart() : base(DateTimeOffset.UtcNow) { - EndDate.BindValueChanged(date => Date = date.NewValue); + EndDate.BindValueChanged(date => + { + // If null, set a very large future date to prevent unnecessary schedules. + Date = date.NewValue ?? DateTimeOffset.Now.AddYears(1); + }, true); } protected override string Format() { + if (EndDate.Value == null) + return string.Empty; + var diffToNow = Date.Subtract(DateTimeOffset.Now); if (diffToNow.TotalSeconds < -5) diff --git a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs index b8003b9774..1859e8db8a 100644 --- a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs +++ b/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs @@ -325,7 +325,7 @@ namespace osu.Game.Screens.Multi.Match.Components Availability.BindValueChanged(availability => AvailabilityPicker.Current.Value = availability.NewValue, true); Type.BindValueChanged(type => TypePicker.Current.Value = type.NewValue, true); MaxParticipants.BindValueChanged(count => MaxParticipantsField.Text = count.NewValue?.ToString(), true); - Duration.BindValueChanged(duration => DurationField.Current.Value = duration.NewValue, true); + Duration.BindValueChanged(duration => DurationField.Current.Value = duration.NewValue ?? TimeSpan.FromMinutes(30), true); playlist.Items.BindTo(Playlist); Playlist.BindCollectionChanged(onPlaylistChanged, true); diff --git a/osu.Game/Screens/Multi/MultiplayerComposite.cs b/osu.Game/Screens/Multi/MultiplayerComposite.cs index e612e77748..6e0c69d712 100644 --- a/osu.Game/Screens/Multi/MultiplayerComposite.cs +++ b/osu.Game/Screens/Multi/MultiplayerComposite.cs @@ -40,12 +40,12 @@ namespace osu.Game.Screens.Multi protected Bindable MaxParticipants { get; private set; } [Resolved(typeof(Room))] - protected Bindable EndDate { get; private set; } + protected Bindable EndDate { get; private set; } [Resolved(typeof(Room))] protected Bindable Availability { get; private set; } [Resolved(typeof(Room))] - protected Bindable Duration { get; private set; } + protected Bindable Duration { get; private set; } } } diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs index ba639c29f4..c878451eee 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs @@ -13,7 +13,7 @@ namespace osu.Game.Screens.Multi.Timeshift public class TimeshiftReadyButton : ReadyButton { [Resolved(typeof(Room), nameof(Room.EndDate))] - private Bindable endDate { get; set; } + private Bindable endDate { get; set; } public TimeshiftReadyButton() { @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Multi.Timeshift { base.Update(); - Enabled.Value = DateTimeOffset.UtcNow.AddSeconds(30).AddMilliseconds(GameBeatmap.Value.Track.Length) < endDate.Value; + Enabled.Value = endDate.Value != null && DateTimeOffset.UtcNow.AddSeconds(30).AddMilliseconds(GameBeatmap.Value.Track.Length) < endDate.Value; } } } From c3d1eaf36dec71ff703f623b1f274192e6f1275c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 16:21:05 +0900 Subject: [PATCH 178/328] Make RealtimeMultiplayerTestScene abstract --- .../RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs b/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs index b52106551e..aec70d8be4 100644 --- a/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs +++ b/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs @@ -12,7 +12,7 @@ using osu.Game.Screens.Multi.RealtimeMultiplayer; namespace osu.Game.Tests.Visual.RealtimeMultiplayer { - public class RealtimeMultiplayerTestScene : MultiplayerTestScene + public abstract class RealtimeMultiplayerTestScene : MultiplayerTestScene { [Cached(typeof(StatefulMultiplayerClient))] public TestRealtimeMultiplayerClient Client { get; } @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer private readonly bool joinRoom; - public RealtimeMultiplayerTestScene(bool joinRoom = true) + protected RealtimeMultiplayerTestScene(bool joinRoom = true) { this.joinRoom = joinRoom; base.Content.Add(content = new TestRealtimeRoomContainer { RelativeSizeAxes = Axes.Both }); From 64a32723f3b544fec8f02b120f00986ffcd3e65e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 16:23:42 +0900 Subject: [PATCH 179/328] One more case --- osu.Game/Online/Multiplayer/Room.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs index ee8992e399..e3444d6b7e 100644 --- a/osu.Game/Online/Multiplayer/Room.cs +++ b/osu.Game/Online/Multiplayer/Room.cs @@ -139,7 +139,7 @@ namespace osu.Game.Online.Multiplayer ParticipantCount.Value = other.ParticipantCount.Value; EndDate.Value = other.EndDate.Value; - if (DateTimeOffset.Now >= EndDate.Value) + if (EndDate.Value != null && DateTimeOffset.Now >= EndDate.Value) Status.Value = new RoomStatusEnded(); if (!Playlist.SequenceEqual(other.Playlist)) From 5d73359bd7c0e95a9e18c202319d0ecf77071e18 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 16:35:19 +0900 Subject: [PATCH 180/328] Make participant count non-nullable --- osu.Game/Online/Multiplayer/Room.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs index 9a21543b2e..5930a624bc 100644 --- a/osu.Game/Online/Multiplayer/Room.cs +++ b/osu.Game/Online/Multiplayer/Room.cs @@ -67,15 +67,8 @@ namespace osu.Game.Online.Multiplayer public readonly BindableList RecentParticipants = new BindableList(); [Cached] - public readonly Bindable ParticipantCount = new Bindable(); - - // todo: TEMPORARY [JsonProperty("participant_count")] - private int? participantCount - { - get => ParticipantCount.Value; - set => ParticipantCount.Value = value ?? 0; - } + public readonly Bindable ParticipantCount = new Bindable(); [JsonProperty("duration")] private int duration From d096f2f8f6445eb3524df9612e8d7a891528bebe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Dec 2020 16:39:46 +0900 Subject: [PATCH 181/328] Fix potential cross-thread operation during chat channel load The callbacks are scheduled to the API thread, but hooked up in BDL load. This causes a potential case of cross-thread collection enumeration. I've tested and it seems like the schedule logic should be fine for short term. Longer term, we probably want to re-think how this works so background operations aren't performed on the `DrawableChannel` in the first place (chat shouldn't have an overhead like this when not visible). Closes #11231. --- osu.Game/Overlays/Chat/DrawableChannel.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index d63faebae4..5926d11c03 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -103,7 +103,7 @@ namespace osu.Game.Overlays.Chat Colour = colours.ChatBlue.Lighten(0.7f), }; - private void newMessagesArrived(IEnumerable newMessages) + private void newMessagesArrived(IEnumerable newMessages) => Schedule(() => { if (newMessages.Min(m => m.Id) < chatLines.Max(c => c.Message.Id)) { @@ -155,9 +155,9 @@ namespace osu.Game.Overlays.Chat if (shouldScrollToEnd) scrollToEnd(); - } + }); - private void pendingMessageResolved(Message existing, Message updated) + private void pendingMessageResolved(Message existing, Message updated) => Schedule(() => { var found = chatLines.LastOrDefault(c => c.Message == existing); @@ -169,12 +169,12 @@ namespace osu.Game.Overlays.Chat found.Message = updated; ChatLineFlow.Add(found); } - } + }); - private void messageRemoved(Message removed) + private void messageRemoved(Message removed) => Schedule(() => { chatLines.FirstOrDefault(c => c.Message == removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); - } + }); private IEnumerable chatLines => ChatLineFlow.Children.OfType(); From a021aaf54673acf78c5272d077e757b1ded87bc8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 16:42:21 +0900 Subject: [PATCH 182/328] Fix room category being serialised as ints --- osu.Game/Online/Multiplayer/Room.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs index 9a21543b2e..53ae142ad4 100644 --- a/osu.Game/Online/Multiplayer/Room.cs +++ b/osu.Game/Online/Multiplayer/Room.cs @@ -35,9 +35,22 @@ namespace osu.Game.Online.Multiplayer public readonly Bindable ChannelId = new Bindable(); [Cached] - [JsonProperty("category")] + [JsonIgnore] public readonly Bindable Category = new Bindable(); + // Todo: osu-framework bug (https://github.com/ppy/osu-framework/issues/4106) + [JsonProperty("category")] + private string categoryString + { + get => Category.Value.ToString().ToLower(); + set + { + if (!Enum.TryParse(value, true, out var enumValue)) + enumValue = RoomCategory.Normal; + Category.Value = enumValue; + } + } + [Cached] [JsonIgnore] public readonly Bindable Duration = new Bindable(TimeSpan.FromMinutes(30)); From e23d81bfc64594c80d21ea1043ec085a47161f25 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 16:56:45 +0900 Subject: [PATCH 183/328] Use enum property --- .../Converters/SnakeCaseStringEnumConverter.cs | 16 ++++++++++++++++ osu.Game/Online/Multiplayer/Room.cs | 13 +++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) create mode 100644 osu.Game/IO/Serialization/Converters/SnakeCaseStringEnumConverter.cs diff --git a/osu.Game/IO/Serialization/Converters/SnakeCaseStringEnumConverter.cs b/osu.Game/IO/Serialization/Converters/SnakeCaseStringEnumConverter.cs new file mode 100644 index 0000000000..1d82a5bc87 --- /dev/null +++ b/osu.Game/IO/Serialization/Converters/SnakeCaseStringEnumConverter.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; + +namespace osu.Game.IO.Serialization.Converters +{ + public class SnakeCaseStringEnumConverter : StringEnumConverter + { + public SnakeCaseStringEnumConverter() + { + NamingStrategy = new SnakeCaseNamingStrategy(); + } + } +} diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs index 53ae142ad4..66e3e8975a 100644 --- a/osu.Game/Online/Multiplayer/Room.cs +++ b/osu.Game/Online/Multiplayer/Room.cs @@ -6,6 +6,7 @@ using System.Linq; using Newtonsoft.Json; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Game.IO.Serialization.Converters; using osu.Game.Online.Multiplayer.GameTypes; using osu.Game.Online.Multiplayer.RoomStatuses; using osu.Game.Users; @@ -40,15 +41,11 @@ namespace osu.Game.Online.Multiplayer // Todo: osu-framework bug (https://github.com/ppy/osu-framework/issues/4106) [JsonProperty("category")] - private string categoryString + [JsonConverter(typeof(SnakeCaseStringEnumConverter))] + private RoomCategory category { - get => Category.Value.ToString().ToLower(); - set - { - if (!Enum.TryParse(value, true, out var enumValue)) - enumValue = RoomCategory.Normal; - Category.Value = enumValue; - } + get => Category.Value; + set => Category.Value = value; } [Cached] From eb46c9ce9be47341a18e08fedeeb65408ac5847c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 17:11:30 +0900 Subject: [PATCH 184/328] Fix metadata lost in beatmapset deserialisation --- .../Online/API/Requests/Responses/APIBeatmapSet.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index 6d0160fbc4..720d6bfff4 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -80,7 +80,7 @@ namespace osu.Game.Online.API.Requests.Responses public BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets) { - return new BeatmapSetInfo + var beatmapSet = new BeatmapSetInfo { OnlineBeatmapSetID = OnlineBeatmapSetID, Metadata = this, @@ -104,8 +104,17 @@ namespace osu.Game.Online.API.Requests.Responses Genre = genre, Language = language }, - Beatmaps = beatmaps?.Select(b => b.ToBeatmap(rulesets)).ToList(), }; + + beatmapSet.Beatmaps = beatmaps?.Select(b => + { + var beatmap = b.ToBeatmap(rulesets); + beatmap.BeatmapSet = beatmapSet; + beatmap.Metadata = beatmapSet.Metadata; + return beatmap; + }).ToList(); + + return beatmapSet; } } } From e1b2de27a6395f051e4f9f71aa52dfe6398cc4fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Dec 2020 17:19:29 +0900 Subject: [PATCH 185/328] Update osu!mania legacy skin's judgement animation to match stable --- .../Legacy/LegacyManiaJudgementPiece.cs | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs index 9684cbb167..e275e1c0ca 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs @@ -5,11 +5,11 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; +using osu.Framework.Utils; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; -using osuTK; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { @@ -56,31 +56,30 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy (animation as IFramedAnimation)?.GotoFrame(0); + this.FadeInFromZero(20, Easing.Out) + .Then().Delay(160) + .FadeOutFromOne(40, Easing.In); + switch (result) { case HitResult.None: break; case HitResult.Miss: - animation.ScaleTo(1.6f); - animation.ScaleTo(1, 100, Easing.In); - - animation.MoveTo(Vector2.Zero); - animation.MoveToOffset(new Vector2(0, 100), 800, Easing.InQuint); + animation.ScaleTo(1.2f).Then().ScaleTo(1, 100, Easing.Out); animation.RotateTo(0); - animation.RotateTo(40, 800, Easing.InQuint); - - this.FadeOutFromOne(800); + animation.RotateTo(RNG.NextSingle(-18, 18), 100, Easing.Out); break; default: - animation.ScaleTo(0.8f); - animation.ScaleTo(1, 250, Easing.OutElastic); - - animation.Delay(50).ScaleTo(0.75f, 250); - - this.Delay(50).FadeOut(200); + animation.ScaleTo(0.8f) + .Then().ScaleTo(1, 40) + // this is actually correct to match stable; there were overlapping transforms. + .Then().ScaleTo(0.85f) + .Then().ScaleTo(0.7f, 40) + .Then().Delay(100) + .Then().ScaleTo(0.4f, 40, Easing.In); break; } } From 9fa1f60b7d2f0fcae3537148374a5e9214ac907b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 17:31:15 +0900 Subject: [PATCH 186/328] Fix incorrect footer being used --- .../Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs index d8b42e065b..cdab1435c0 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs @@ -149,7 +149,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer }, new Drawable[] { - new Footer { SelectedItem = { BindTarget = SelectedItem } } + new RealtimeMatchFooter { SelectedItem = { BindTarget = SelectedItem } } } }, RowDimensions = new[] From 83f1350d7d218ba69082bffe0fc7f495b428cf34 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Dec 2020 17:49:10 +0900 Subject: [PATCH 187/328] Fix editor background not being correctly cleaned up on forced exit Closes #11214. Should be pretty obvious why. --- osu.Game/Screens/Edit/Editor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index ca7e5fbf20..223c678fba 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -461,7 +461,7 @@ namespace osu.Game.Screens.Edit if (dialogOverlay == null || dialogOverlay.CurrentDialog is PromptForSaveDialog) { confirmExit(); - return false; + return base.OnExiting(next); } if (isNewBeatmap || HasUnsavedChanges) From d11d754715220e5e84c991d497e91d561126444a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Dec 2020 18:09:37 +0900 Subject: [PATCH 188/328] Increase size of circle display on timeline --- .../Compose/Components/Timeline/TimelineHitObjectBlueprint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs index 657c5834b2..ae2a82fa10 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { private const float thickness = 5; private const float shadow_radius = 5; - private const float circle_size = 24; + private const float circle_size = 34; public Action OnDragHandled; From d1be7c23d96ec9efe7d4edaaa87fd43c155af259 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Dec 2020 18:09:56 +0900 Subject: [PATCH 189/328] Increase height of timeline drag area --- .../Compose/Components/Timeline/TimelineBlueprintContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index 2f14c607c2..ead1aa5c62 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline Anchor = Anchor.Centre; Origin = Anchor.Centre; - Height = 0.4f; + Height = 0.6f; AddInternal(new Box { From 423c6158e16bda8c5382de4f99eeabcd776cfb97 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Dec 2020 18:10:11 +0900 Subject: [PATCH 190/328] Highlight timeline drag area when hovered for better visibility --- .../Timeline/TimelineBlueprintContainer.cs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index ead1aa5c62..1fc529910b 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Framework.Utils; +using osu.Game.Graphics; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts; @@ -25,10 +26,15 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline [Resolved] private EditorBeatmap beatmap { get; set; } + [Resolved] + private OsuColour colours { get; set; } + private DragEvent lastDragEvent; private Bindable placement; private SelectionBlueprint placementBlueprint; + private readonly Box backgroundBox; + public TimelineBlueprintContainer(HitObjectComposer composer) : base(composer) { @@ -38,7 +44,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline Height = 0.6f; - AddInternal(new Box + AddInternal(backgroundBox = new Box { Colour = Color4.Black, RelativeSizeAxes = Axes.Both, @@ -77,6 +83,18 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline protected override Container CreateSelectionBlueprintContainer() => new TimelineSelectionBlueprintContainer { RelativeSizeAxes = Axes.Both }; + protected override bool OnHover(HoverEvent e) + { + backgroundBox.FadeColour(colours.BlueLighter, 120, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + backgroundBox.FadeColour(Color4.Black, 600, Easing.OutQuint); + base.OnHoverLost(e); + } + protected override void OnDrag(DragEvent e) { handleScrollViaDrag(e); From 0566ed1a9b15a105530ab800865077bc68ab5a9e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 18:38:44 +0900 Subject: [PATCH 191/328] Add button to main menu --- osu.Game/Screens/Menu/ButtonSystem.cs | 11 +++++------ osu.Game/Screens/Menu/MainMenu.cs | 5 +++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 4becdd58cd..0014f6768f 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -42,8 +42,7 @@ namespace osu.Game.Screens.Menu public Action OnBeatmapListing; public Action OnSolo; public Action OnSettings; - public Action OnMulti; - public Action OnChart; + public Action OnMulti; public const float BUTTON_WIDTH = 140f; public const float WEDGE_WIDTH = 20; @@ -124,8 +123,8 @@ namespace osu.Game.Screens.Menu private void load(AudioManager audio, IdleTracker idleTracker, GameHost host) { buttonsPlay.Add(new Button(@"solo", @"button-solo-select", FontAwesome.Solid.User, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P)); - buttonsPlay.Add(new Button(@"multi", @"button-generic-select", FontAwesome.Solid.Users, new Color4(94, 63, 186, 255), onMulti, 0, Key.M)); - buttonsPlay.Add(new Button(@"chart", @"button-generic-select", OsuIcon.Charts, new Color4(80, 53, 160, 255), () => OnChart?.Invoke())); + buttonsPlay.Add(new Button(@"multi", @"button-generic-select", OsuIcon.Charts, new Color4(94, 63, 186, 255), () => onMulti(true), 0, Key.M)); + buttonsPlay.Add(new Button(@"timeshift", @"button-generic-select", FontAwesome.Solid.Users, new Color4(94, 63, 186, 255), () => onMulti(false), 0, Key.L)); buttonsPlay.ForEach(b => b.VisibleState = ButtonSystemState.Play); buttonsTopLevel.Add(new Button(@"play", @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P)); @@ -154,7 +153,7 @@ namespace osu.Game.Screens.Menu sampleBack = audio.Samples.Get(@"Menu/button-back-select"); } - private void onMulti() + private void onMulti(bool realtime) { if (!api.IsLoggedIn) { @@ -172,7 +171,7 @@ namespace osu.Game.Screens.Menu return; } - OnMulti?.Invoke(); + OnMulti?.Invoke(realtime); } private void updateIdleState(bool isIdle) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index b781c347f0..391bbf8429 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -17,6 +17,8 @@ using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; +using osu.Game.Screens.Multi; +using osu.Game.Screens.Multi.RealtimeMultiplayer; using osu.Game.Screens.Multi.Timeshift; using osu.Game.Screens.Select; @@ -104,7 +106,7 @@ namespace osu.Game.Screens.Menu this.Push(new Editor()); }, OnSolo = onSolo, - OnMulti = delegate { this.Push(new TimeshiftMultiplayer()); }, + OnMulti = realtime => this.Push(realtime ? (Multiplayer)new RealtimeMultiplayer() : new TimeshiftMultiplayer()), OnExit = confirmAndExit, } } @@ -136,7 +138,6 @@ namespace osu.Game.Screens.Menu buttons.OnSettings = () => settings?.ToggleVisibility(); buttons.OnBeatmapListing = () => beatmapListing?.ToggleVisibility(); - buttons.OnChart = () => rankings?.ShowSpotlights(); LoadComponentAsync(background = new BackgroundScreenDefault()); preloadSongSelect(); From 8427ee1b8e6425b2d6e2bc837a737dba2f7e6e85 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 18:42:23 +0900 Subject: [PATCH 192/328] Fix incorrect cached type --- .../RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs | 4 ++-- .../Visual/RealtimeMultiplayer/TestRealtimeRoomContainer.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs b/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs index aec70d8be4..30bd3ebc32 100644 --- a/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs +++ b/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs @@ -7,8 +7,8 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Screens.Multi; using osu.Game.Screens.Multi.Lounge.Components; -using osu.Game.Screens.Multi.RealtimeMultiplayer; namespace osu.Game.Tests.Visual.RealtimeMultiplayer { @@ -17,7 +17,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer [Cached(typeof(StatefulMultiplayerClient))] public TestRealtimeMultiplayerClient Client { get; } - [Cached(typeof(RealtimeRoomManager))] + [Cached(typeof(IRoomManager))] public TestRealtimeRoomManager RoomManager { get; } [Cached] diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomContainer.cs b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomContainer.cs index aa75968cca..3565d6ac5d 100644 --- a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomContainer.cs +++ b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomContainer.cs @@ -6,8 +6,8 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Screens.Multi; using osu.Game.Screens.Multi.Lounge.Components; -using osu.Game.Screens.Multi.RealtimeMultiplayer; namespace osu.Game.Tests.Visual.RealtimeMultiplayer { @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer [Cached(typeof(StatefulMultiplayerClient))] public readonly TestRealtimeMultiplayerClient Client; - [Cached(typeof(RealtimeRoomManager))] + [Cached(typeof(IRoomManager))] public readonly TestRealtimeRoomManager RoomManager; [Cached] From 56bd3d8a82230fd626fad39c23a40a3fd0729e1a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 18:42:31 +0900 Subject: [PATCH 193/328] Add realtime multiplayer test scene --- .../TestSceneRealtimeMultiplayer.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs new file mode 100644 index 0000000000..80955ca380 --- /dev/null +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Screens.Multi.Components; + +namespace osu.Game.Tests.Visual.RealtimeMultiplayer +{ + public class TestSceneRealtimeMultiplayer : RealtimeMultiplayerTestScene + { + public TestSceneRealtimeMultiplayer() + { + var multi = new TestRealtimeMultiplayer(); + + AddStep("show", () => LoadScreen(multi)); + AddUntilStep("wait for loaded", () => multi.IsLoaded); + } + + private class TestRealtimeMultiplayer : Screens.Multi.RealtimeMultiplayer.RealtimeMultiplayer + { + protected override RoomManager CreateRoomManager() => new TestRealtimeRoomManager(); + } + } +} From f21b4a269fb7620ef6d612f7709c88f35093c3ed Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 21 Dec 2020 18:42:55 +0900 Subject: [PATCH 194/328] Reduce wait length --- .../RealtimeMultiplayer/TestSceneRealtimeMatchSubScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMatchSubScreen.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMatchSubScreen.cs index d31364d62e..a059bb1cc0 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMatchSubScreen.cs @@ -71,7 +71,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer InputManager.Click(MouseButton.Left); }); - AddWaitStep("wait", 500); + AddWaitStep("wait", 10); } } } From 10c2745682db8b3be8f35f81b8ef42345a4f3e44 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 12:01:09 +0900 Subject: [PATCH 195/328] Add region specifications around implicit interface implementations --- osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs | 4 ++++ osu.Game/Beatmaps/BeatmapManager.cs | 4 ++++ osu.Game/Skinning/SkinManager.cs | 4 ++++ osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs | 4 ++++ osu.Game/Tests/Visual/SkinnableTestScene.cs | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs index 36f99c5599..38cb6729c3 100644 --- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs @@ -179,8 +179,12 @@ namespace osu.Game.Tests.Gameplay } } + #region IResourceStorageProvider + public AudioManager AudioManager => Audio; public IResourceStore Files => null; public IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => null; + + #endregion } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 3cf691da9a..8a2991af90 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -496,12 +496,16 @@ namespace osu.Game.Beatmaps onlineLookupQueue?.Dispose(); } + #region IResourceStorageProvider + TextureStore IBeatmapResourceProvider.LargeTextureStore => largeTextureStore; ITrackStore IBeatmapResourceProvider.Tracks => trackStore; AudioManager IStorageResourceProvider.AudioManager => audioManager; IResourceStore IStorageResourceProvider.Files => Files.Store; IResourceStore IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore); + #endregion + /// /// A dummy WorkingBeatmap for the purpose of retrieving a beatmap for star difficulty calculation. /// diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 2ee940c02d..99c64b13a4 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -175,8 +175,12 @@ namespace osu.Game.Skinning public IBindable GetConfig(TLookup lookup) => CurrentSkin.Value.GetConfig(lookup); + #region IResourceStorageProvider + AudioManager IStorageResourceProvider.AudioManager => audio; IResourceStore IStorageResourceProvider.Files => Files.Store; IResourceStore IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore); + + #endregion } } diff --git a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs index dd1979a7e3..62814d4ed4 100644 --- a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs +++ b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs @@ -123,10 +123,14 @@ namespace osu.Game.Tests.Beatmaps protected void AssertNoLookup(string name) => AddAssert($"\"{name}\" not looked up", () => !beatmapSkinResourceStore.PerformedLookups.Contains(name) && !userSkinResourceStore.PerformedLookups.Contains(name)); + #region IResourceStorageProvider + public AudioManager AudioManager => Audio; public IResourceStore Files => userSkinResourceStore; public IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => null; + #endregion + private class SkinSourceDependencyContainer : IReadOnlyDependencyContainer { public ISkinSource SkinSource; diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index 3a9c33788a..3d2c68c2ad 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -152,10 +152,14 @@ namespace osu.Game.Tests.Visual protected virtual IBeatmap CreateBeatmapForSkinProvider() => CreateWorkingBeatmap(Ruleset.Value).GetPlayableBeatmap(Ruleset.Value); + #region IResourceStorageProvider + public AudioManager AudioManager => Audio; public IResourceStore Files => null; public IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore); + #endregion + private class OutlineBox : CompositeDrawable { public OutlineBox() From a97a2b2a6637b2ec49ff2430dd7dce1cbd935099 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 12:03:25 +0900 Subject: [PATCH 196/328] Add nullability to BeatmapManager's GameHost reference --- osu.Game/Beatmaps/BeatmapManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 8a2991af90..42418e532b 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -72,6 +72,7 @@ namespace osu.Game.Beatmaps private readonly LargeTextureStore largeTextureStore; private readonly ITrackStore trackStore; + [CanBeNull] private readonly GameHost host; [CanBeNull] @@ -502,7 +503,7 @@ namespace osu.Game.Beatmaps ITrackStore IBeatmapResourceProvider.Tracks => trackStore; AudioManager IStorageResourceProvider.AudioManager => audioManager; IResourceStore IStorageResourceProvider.Files => Files.Store; - IResourceStore IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore); + IResourceStore IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host?.CreateTextureLoaderStore(underlyingStore); #endregion From 85518b4d9919973a685d2467530064c0518fc605 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 12:06:10 +0900 Subject: [PATCH 197/328] Enforce non-null for BeatmapManager WorkingBeatmap resources --- osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs index 5d298dbccc..62cf29dc03 100644 --- a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using osu.Framework.Audio.Track; using osu.Framework.Graphics.Textures; @@ -19,10 +20,11 @@ namespace osu.Game.Beatmaps [ExcludeFromDynamicCompile] private class BeatmapManagerWorkingBeatmap : WorkingBeatmap { + [NotNull] private readonly IBeatmapResourceProvider resources; - public BeatmapManagerWorkingBeatmap(BeatmapInfo beatmapInfo, IBeatmapResourceProvider resources) - : base(beatmapInfo, resources?.AudioManager) + public BeatmapManagerWorkingBeatmap(BeatmapInfo beatmapInfo, [NotNull] IBeatmapResourceProvider resources) + : base(beatmapInfo, resources.AudioManager) { this.resources = resources; } From 13ef097a53933e2e84608911aa6fd5976a73c945 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 12:08:40 +0900 Subject: [PATCH 198/328] Annotate potentially null parameters in protected ctor of LegacySkin --- osu.Game/Skinning/LegacySkin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 5a7ad095f6..e4e5bf2f75 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -58,7 +58,7 @@ namespace osu.Game.Skinning { } - protected LegacySkin(SkinInfo skin, IResourceStore storage, IStorageResourceProvider resources, string filename) + protected LegacySkin(SkinInfo skin, [CanBeNull] IResourceStore storage, [CanBeNull] IStorageResourceProvider resources, string filename) : base(skin) { using (var stream = storage?.GetStream(filename)) From bf39aa5980819bc4c0171251173111e47573fb4e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 12:18:42 +0900 Subject: [PATCH 199/328] Fix incorrectly converted rotation values --- .../Skinning/Legacy/LegacyManiaJudgementPiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs index e275e1c0ca..5d662c18d3 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy animation.ScaleTo(1.2f).Then().ScaleTo(1, 100, Easing.Out); animation.RotateTo(0); - animation.RotateTo(RNG.NextSingle(-18, 18), 100, Easing.Out); + animation.RotateTo(RNG.NextSingle(-5.73f, 5.73f), 100, Easing.Out); break; default: From 87176edca142a2fbbfe4aea1076902449fda1c79 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 12:52:30 +0900 Subject: [PATCH 200/328] Fix crash when attempting to scale two hitobjects on the same axis --- osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index ec8c68005f..660e1844aa 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -157,10 +157,16 @@ namespace osu.Game.Rulesets.Osu.Edit foreach (var h in hitObjects) { - h.Position = new Vector2( - quad.TopLeft.X + (h.X - quad.TopLeft.X) / quad.Width * (quad.Width + scale.X), - quad.TopLeft.Y + (h.Y - quad.TopLeft.Y) / quad.Height * (quad.Height + scale.Y) - ); + var newPosition = h.Position; + + // guard against no-ops and NaN. + if (scale.X != 0 && quad.Width > 0) + newPosition.X = quad.TopLeft.X + (h.X - quad.TopLeft.X) / quad.Width * (quad.Width + scale.X); + + if (scale.Y != 0 && quad.Height > 0) + newPosition.Y = quad.TopLeft.Y + (h.Y - quad.TopLeft.Y) / quad.Height * (quad.Height + scale.Y); + + h.Position = newPosition; } } From 7c5964fad8471635aa98a4fa1f81ef43ee9d5351 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 13:04:39 +0900 Subject: [PATCH 201/328] Revert window modes to previous code to correctly apply framework restrictions --- osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs | 3 ++- osu.Game/Overlays/Settings/SettingsDropdown.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 3df2a78552..3ef60c8fcd 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -59,9 +59,10 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics Children = new Drawable[] { - windowModeDropdown = new SettingsEnumDropdown + windowModeDropdown = new SettingsDropdown { LabelText = "Screen mode", + ItemSource = windowModes, Current = config.GetBindable(FrameworkSetting.WindowMode), }, resolutionSettingsContainer = new Container diff --git a/osu.Game/Overlays/Settings/SettingsDropdown.cs b/osu.Game/Overlays/Settings/SettingsDropdown.cs index e1c6333aa0..1175ddaab8 100644 --- a/osu.Game/Overlays/Settings/SettingsDropdown.cs +++ b/osu.Game/Overlays/Settings/SettingsDropdown.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings { - public abstract class SettingsDropdown : SettingsItem + public class SettingsDropdown : SettingsItem { protected new OsuDropdown Control => (OsuDropdown)base.Control; From dab5924a63c869dc0ce74b3c22e8c797a6485169 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 22 Dec 2020 08:02:15 +0300 Subject: [PATCH 202/328] Fix resolution dropdown not respecting current display changes --- .../Sections/Graphics/LayoutSettings.cs | 103 ++++++++---------- 1 file changed, 45 insertions(+), 58 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 62dc1dc806..ff3b580c7e 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; using System.Drawing; using System.Linq; using osu.Framework.Allocation; @@ -25,9 +24,13 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics private FillFlowContainer> scalingSettings; + private readonly IBindable currentDisplay = new Bindable(); + private readonly IBindableList windowModes = new BindableList(); + private Bindable scalingMode; private Bindable sizeFullscreen; - private readonly IBindableList windowModes = new BindableList(); + + private readonly BindableList resolutions = new BindableList(new[] { new Size(9999, 9999) }); [Resolved] private OsuGameBase game { get; set; } @@ -53,9 +56,10 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics scalingPositionY = osuConfig.GetBindable(OsuSetting.ScalingPositionY); if (host.Window != null) + { + currentDisplay.BindTo(host.Window.CurrentDisplayBindable); windowModes.BindTo(host.Window.SupportedWindowModes); - - Container resolutionSettingsContainer; + } Children = new Drawable[] { @@ -65,10 +69,12 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics Current = config.GetBindable(FrameworkSetting.WindowMode), ItemSource = windowModes, }, - resolutionSettingsContainer = new Container + resolutionDropdown = new ResolutionSettingsDropdown { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y + LabelText = "Resolution", + ShowsDefaultIndicator = false, + ItemSource = resolutions, + Current = sizeFullscreen }, new SettingsSlider { @@ -126,31 +132,34 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics }, }; - scalingSettings.ForEach(s => bindPreviewEvent(s.Current)); - - var resolutions = getResolutions(); - - if (resolutions.Count > 1) + windowModes.BindCollectionChanged((sender, args) => { - resolutionSettingsContainer.Child = resolutionDropdown = new ResolutionSettingsDropdown - { - LabelText = "Resolution", - ShowsDefaultIndicator = false, - Items = resolutions, - Current = sizeFullscreen - }; + if (windowModes.Count > 1) + windowModeDropdown.Show(); + else + windowModeDropdown.Hide(); + }, true); - windowModeDropdown.Current.BindValueChanged(mode => + windowModeDropdown.Current.ValueChanged += v => updateResolutionDropdown(); + + currentDisplay.BindValueChanged(v => Schedule(() => + { + resolutions.RemoveRange(1, resolutions.Count - 1); + + if (v.NewValue != null) { - if (mode.NewValue == WindowMode.Fullscreen) - { - resolutionDropdown.Show(); - sizeFullscreen.TriggerChange(); - } - else - resolutionDropdown.Hide(); - }, true); - } + resolutions.AddRange(v.NewValue.DisplayModes + .Where(m => m.Size.Width >= 800 && m.Size.Height >= 600) + .OrderByDescending(m => m.Size.Width) + .ThenByDescending(m => m.Size.Height) + .Select(m => m.Size) + .Distinct()); + } + + updateResolutionDropdown(); + }), true); + + scalingSettings.ForEach(s => bindPreviewEvent(s.Current)); scalingMode.BindValueChanged(mode => { @@ -163,17 +172,13 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics scalingSettings.ForEach(s => s.TransferValueOnCommit = mode.NewValue == ScalingMode.Everything); }, true); - windowModes.CollectionChanged += (sender, args) => windowModesChanged(); - - windowModesChanged(); - } - - private void windowModesChanged() - { - if (windowModes.Count > 1) - windowModeDropdown.Show(); - else - windowModeDropdown.Hide(); + void updateResolutionDropdown() + { + if (resolutions.Count > 1 && windowModeDropdown.Current.Value == WindowMode.Fullscreen) + resolutionDropdown.Show(); + else + resolutionDropdown.Hide(); + } } /// @@ -205,24 +210,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics preview.Expire(); } - private IReadOnlyList getResolutions() - { - var resolutions = new List { new Size(9999, 9999) }; - var currentDisplay = game.Window?.CurrentDisplayBindable.Value; - - if (currentDisplay != null) - { - resolutions.AddRange(currentDisplay.DisplayModes - .Where(m => m.Size.Width >= 800 && m.Size.Height >= 600) - .OrderByDescending(m => m.Size.Width) - .ThenByDescending(m => m.Size.Height) - .Select(m => m.Size) - .Distinct()); - } - - return resolutions; - } - private class ScalingPreview : ScalingContainer { public ScalingPreview() From dff865f335c8c4c70ed8b4ec7bf1975fc2f52440 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 14:12:02 +0900 Subject: [PATCH 203/328] Tidy up comments, code, and multiple linq enumeration --- osu.Game/OsuGame.cs | 18 ++++++------------ .../Screens/Select/DifficultyRecommender.cs | 2 ++ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index d2c27b766c..d76bd163e1 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -364,25 +364,19 @@ namespace osu.Game // we might even already be at the song if (Beatmap.Value.BeatmapSetInfo.Hash == databasedSet.Hash && (difficultyCriteria?.Invoke(Beatmap.Value.BeatmapInfo) ?? true)) - { return; - } // Find beatmaps that match our predicate. - var beatmaps = databasedSet.Beatmaps.Where(b => difficultyCriteria?.Invoke(b) ?? true); + var beatmaps = databasedSet.Beatmaps.Where(b => difficultyCriteria?.Invoke(b) ?? true).ToList(); // Use all beatmaps if predicate matched nothing - if (!beatmaps.Any()) + if (beatmaps.Count == 0) beatmaps = databasedSet.Beatmaps; - // Try to select recommended beatmap - // This should give us a beatmap from current ruleset if there are any in our matched beatmaps - var selection = DifficultyRecommender.GetRecommendedBeatmap(beatmaps); - // Fallback if a difficulty can't be recommended, maybe we are offline - // First try to find a beatmap in current ruleset - selection ??= beatmaps.FirstOrDefault(b => b.Ruleset.Equals(Ruleset.Value)); - // Otherwise use first beatmap - selection ??= beatmaps.First(); + // Prefer recommended beatmap if recommendations are available, else fallback to a sane selection. + var selection = DifficultyRecommender.GetRecommendedBeatmap(beatmaps) + ?? beatmaps.FirstOrDefault(b => b.Ruleset.Equals(Ruleset.Value)) + ?? beatmaps.First(); Ruleset.Value = selection.Ruleset; Beatmap.Value = BeatmapManager.GetWorkingBeatmap(selection); diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index fa48316e9d..3b3fc812e6 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.IEnumerableExtensions; @@ -47,6 +48,7 @@ namespace osu.Game.Screens.Select /// /// A collection of beatmaps to select a difficulty from. /// The recommended difficulty, or null if a recommendation could not be provided. + [CanBeNull] public BeatmapInfo GetRecommendedBeatmap(IEnumerable beatmaps) { if (!recommendedStarDifficulty.Any()) From 626b7615ad86ca6b93b68cf0dd32e5f23b30b03d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 14:23:33 +0900 Subject: [PATCH 204/328] Move and rename some fields for better readability --- osu.Game/OsuGameBase.cs | 6 +++--- osu.Game/Screens/Select/DifficultyRecommender.cs | 13 ++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 5fcd6882a6..f6ec541bcb 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -99,6 +99,9 @@ namespace osu.Game [Cached(typeof(IBindable>))] protected readonly Bindable> SelectedMods = new Bindable>(Array.Empty()); + [Cached] + protected readonly DifficultyRecommender DifficultyRecommender = new DifficultyRecommender(); + /// /// Mods available for the current . /// @@ -117,9 +120,6 @@ namespace osu.Game public bool IsDeployedBuild => AssemblyVersion.Major > 0; - [Cached] - protected readonly DifficultyRecommender DifficultyRecommender = new DifficultyRecommender(); - public virtual string Version { get diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Screens/Select/DifficultyRecommender.cs index 3b3fc812e6..5c031b5d6e 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Screens/Select/DifficultyRecommender.cs @@ -27,7 +27,10 @@ namespace osu.Game.Screens.Select [Resolved] private Bindable ruleset { get; set; } - private int storedUserId; + /// + /// The user for which the last requests were run. + /// + private int? requestedUserId; private readonly Dictionary recommendedStarDifficulty = new Dictionary(); @@ -73,12 +76,12 @@ namespace osu.Game.Screens.Select return beatmap; } - private void calculateRecommendedDifficulties() + private void fetchRecommendedValues() { - if (recommendedStarDifficulty.Any() && api.LocalUser.Value.Id == storedUserId) + if (recommendedStarDifficulty.Count > 0 && api.LocalUser.Value.Id == requestedUserId) return; - storedUserId = api.LocalUser.Value.Id; + requestedUserId = api.LocalUser.Value.Id; // only query API for built-in rulesets rulesets.AvailableRulesets.Where(ruleset => ruleset.ID <= ILegacyRuleset.MAX_LEGACY_RULESET_ID).ForEach(rulesetInfo => @@ -125,7 +128,7 @@ namespace osu.Game.Screens.Select switch (state.NewValue) { case APIState.Online: - calculateRecommendedDifficulties(); + fetchRecommendedValues(); break; } }); From 8cc2ed3faeb362e8c78c8a924b4f8c5889690660 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 14:28:26 +0900 Subject: [PATCH 205/328] Move from OsuGameBase to OsuGame Also moves to a more suitable namespace. --- .../{Screens/Select => Beatmaps}/DifficultyRecommender.cs | 7 +++++-- osu.Game/OsuGame.cs | 7 ++++++- osu.Game/OsuGameBase.cs | 6 ------ 3 files changed, 11 insertions(+), 9 deletions(-) rename osu.Game/{Screens/Select => Beatmaps}/DifficultyRecommender.cs (94%) diff --git a/osu.Game/Screens/Select/DifficultyRecommender.cs b/osu.Game/Beatmaps/DifficultyRecommender.cs similarity index 94% rename from osu.Game/Screens/Select/DifficultyRecommender.cs rename to osu.Game/Beatmaps/DifficultyRecommender.cs index 5c031b5d6e..f870e8f89f 100644 --- a/osu.Game/Screens/Select/DifficultyRecommender.cs +++ b/osu.Game/Beatmaps/DifficultyRecommender.cs @@ -9,13 +9,16 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; -using osu.Game.Beatmaps; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Rulesets; -namespace osu.Game.Screens.Select +namespace osu.Game.Beatmaps { + /// + /// A class which will recommend the most suitable difficulty for the local user from a beatmap set. + /// This requires the user to be logged in, as it sources from the user's online profile. + /// public class DifficultyRecommender : Component { [Resolved] diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index d76bd163e1..bb51c55551 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -80,6 +80,9 @@ namespace osu.Game private BeatmapSetOverlay beatmapSetOverlay; + [Cached] + private readonly DifficultyRecommender difficultyRecommender = new DifficultyRecommender(); + [Cached] private readonly ScreenshotManager screenshotManager = new ScreenshotManager(); @@ -374,7 +377,7 @@ namespace osu.Game beatmaps = databasedSet.Beatmaps; // Prefer recommended beatmap if recommendations are available, else fallback to a sane selection. - var selection = DifficultyRecommender.GetRecommendedBeatmap(beatmaps) + var selection = difficultyRecommender.GetRecommendedBeatmap(beatmaps) ?? beatmaps.FirstOrDefault(b => b.Ruleset.Equals(Ruleset.Value)) ?? beatmaps.First(); @@ -639,6 +642,8 @@ namespace osu.Game GetStableStorage = GetStorageForStableInstall }, Add, true); + loadComponentSingleFile(difficultyRecommender, Add); + loadComponentSingleFile(screenshotManager, Add); // dependency on notification overlay, dependent by settings overlay diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index f6ec541bcb..150569f1dd 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -36,7 +36,6 @@ using osu.Game.Resources; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; -using osu.Game.Screens.Select; using osu.Game.Skinning; using osuTK.Input; using RuntimeInfo = osu.Framework.RuntimeInfo; @@ -99,9 +98,6 @@ namespace osu.Game [Cached(typeof(IBindable>))] protected readonly Bindable> SelectedMods = new Bindable>(Array.Empty()); - [Cached] - protected readonly DifficultyRecommender DifficultyRecommender = new DifficultyRecommender(); - /// /// Mods available for the current . /// @@ -306,8 +302,6 @@ namespace osu.Game AddInternal(MusicController = new MusicController()); dependencies.CacheAs(MusicController); - Add(DifficultyRecommender); - Ruleset.BindValueChanged(onRulesetChanged); } From df5e1d83bd24fb0311868aa93034f790e7b47758 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 14:36:52 +0900 Subject: [PATCH 206/328] Allow recommender to potentially be null --- osu.Game/Screens/Select/SongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 2847b31e98..a5252fdc96 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -118,7 +118,7 @@ namespace osu.Game.Screens.Select BleedBottom = Footer.HEIGHT, SelectionChanged = updateSelectedBeatmap, BeatmapSetsChanged = carouselBeatmapsLoaded, - GetRecommendedBeatmap = recommender.GetRecommendedBeatmap, + GetRecommendedBeatmap = s => recommender?.GetRecommendedBeatmap(s), }, c => carouselContainer.Child = c); AddRangeInternal(new Drawable[] From c6be969e336e153d7e59fd5e23a5d3eeb8547f5a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 14:42:12 +0900 Subject: [PATCH 207/328] Remove unnecessary resolved recommender in test --- .../Visual/SongSelect/TestSceneBeatmapRecommendations.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index 75a33af247..53a956c77c 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Online.API; @@ -15,7 +14,6 @@ using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Taiko; -using osu.Game.Screens.Select; using osu.Game.Tests.Visual.Navigation; using osu.Game.Users; @@ -23,9 +21,6 @@ namespace osu.Game.Tests.Visual.SongSelect { public class TestSceneBeatmapRecommendations : OsuGameTestScene { - [Resolved] - private DifficultyRecommender recommender { get; set; } - [SetUpSteps] public override void SetUpSteps() { From 3bf670510ad61874b516255562c940da0f10c8b4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 22 Dec 2020 14:55:25 +0900 Subject: [PATCH 208/328] Split into two actions --- osu.Game/Screens/Menu/ButtonSystem.cs | 32 ++++++++++++++++++++++----- osu.Game/Screens/Menu/MainMenu.cs | 4 ++-- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 0014f6768f..b52ab2cb2f 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -42,7 +42,8 @@ namespace osu.Game.Screens.Menu public Action OnBeatmapListing; public Action OnSolo; public Action OnSettings; - public Action OnMulti; + public Action OnMultiplayer; + public Action OnTimeshift; public const float BUTTON_WIDTH = 140f; public const float WEDGE_WIDTH = 20; @@ -123,8 +124,8 @@ namespace osu.Game.Screens.Menu private void load(AudioManager audio, IdleTracker idleTracker, GameHost host) { buttonsPlay.Add(new Button(@"solo", @"button-solo-select", FontAwesome.Solid.User, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P)); - buttonsPlay.Add(new Button(@"multi", @"button-generic-select", OsuIcon.Charts, new Color4(94, 63, 186, 255), () => onMulti(true), 0, Key.M)); - buttonsPlay.Add(new Button(@"timeshift", @"button-generic-select", FontAwesome.Solid.Users, new Color4(94, 63, 186, 255), () => onMulti(false), 0, Key.L)); + buttonsPlay.Add(new Button(@"multi", @"button-generic-select", OsuIcon.Charts, new Color4(94, 63, 186, 255), onMultiplayer, 0, Key.M)); + buttonsPlay.Add(new Button(@"timeshift", @"button-generic-select", FontAwesome.Solid.Users, new Color4(94, 63, 186, 255), onTimeshift, 0, Key.L)); buttonsPlay.ForEach(b => b.VisibleState = ButtonSystemState.Play); buttonsTopLevel.Add(new Button(@"play", @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P)); @@ -153,7 +154,7 @@ namespace osu.Game.Screens.Menu sampleBack = audio.Samples.Get(@"Menu/button-back-select"); } - private void onMulti(bool realtime) + private void onMultiplayer() { if (!api.IsLoggedIn) { @@ -171,7 +172,28 @@ namespace osu.Game.Screens.Menu return; } - OnMulti?.Invoke(realtime); + OnMultiplayer?.Invoke(); + } + + private void onTimeshift() + { + if (!api.IsLoggedIn) + { + notifications?.Post(new SimpleNotification + { + Text = "You gotta be logged in to multi 'yo!", + Icon = FontAwesome.Solid.Globe, + Activated = () => + { + loginOverlay?.Show(); + return true; + } + }); + + return; + } + + OnTimeshift?.Invoke(); } private void updateIdleState(bool isIdle) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 391bbf8429..fa96ac9c51 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -17,7 +17,6 @@ using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; -using osu.Game.Screens.Multi; using osu.Game.Screens.Multi.RealtimeMultiplayer; using osu.Game.Screens.Multi.Timeshift; using osu.Game.Screens.Select; @@ -106,7 +105,8 @@ namespace osu.Game.Screens.Menu this.Push(new Editor()); }, OnSolo = onSolo, - OnMulti = realtime => this.Push(realtime ? (Multiplayer)new RealtimeMultiplayer() : new TimeshiftMultiplayer()), + OnMultiplayer = () => this.Push(new RealtimeMultiplayer()), + OnTimeshift = () => this.Push(new TimeshiftMultiplayer()), OnExit = confirmAndExit, } } From 807c1ecd1f47386554d4adc160d426e675413711 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 14:57:32 +0900 Subject: [PATCH 209/328] Refactor recommendation iteration code to read better --- osu.Game/Beatmaps/DifficultyRecommender.cs | 52 +++++++--------------- 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/osu.Game/Beatmaps/DifficultyRecommender.cs b/osu.Game/Beatmaps/DifficultyRecommender.cs index f870e8f89f..340c47d89b 100644 --- a/osu.Game/Beatmaps/DifficultyRecommender.cs +++ b/osu.Game/Beatmaps/DifficultyRecommender.cs @@ -35,7 +35,7 @@ namespace osu.Game.Beatmaps /// private int? requestedUserId; - private readonly Dictionary recommendedStarDifficulty = new Dictionary(); + private readonly Dictionary recommendedDifficultyMapping = new Dictionary(); private readonly IBindable apiState = new Bindable(); @@ -57,31 +57,27 @@ namespace osu.Game.Beatmaps [CanBeNull] public BeatmapInfo GetRecommendedBeatmap(IEnumerable beatmaps) { - if (!recommendedStarDifficulty.Any()) - return null; - - BeatmapInfo beatmap = null; - - foreach (var r in getBestRulesetOrder()) + foreach (var r in orderedRulesets) { - recommendedStarDifficulty.TryGetValue(r, out var stars); + if (!recommendedDifficultyMapping.TryGetValue(r, out var recommendation)) + continue; - beatmap = beatmaps.Where(b => b.Ruleset.Equals(r)).OrderBy(b => + BeatmapInfo beatmap = beatmaps.Where(b => b.Ruleset.Equals(r)).OrderBy(b => { - var difference = b.StarDifficulty - stars; + var difference = b.StarDifficulty - recommendation; return difference >= 0 ? difference * 2 : difference * -1; // prefer easier over harder }).FirstOrDefault(); if (beatmap != null) - break; + return beatmap; } - return beatmap; + return null; } private void fetchRecommendedValues() { - if (recommendedStarDifficulty.Count > 0 && api.LocalUser.Value.Id == requestedUserId) + if (recommendedDifficultyMapping.Count > 0 && api.LocalUser.Value.Id == requestedUserId) return; requestedUserId = api.LocalUser.Value.Id; @@ -94,7 +90,7 @@ namespace osu.Game.Beatmaps req.Success += result => { // algorithm taken from https://github.com/ppy/osu-web/blob/e6e2825516449e3d0f3f5e1852c6bdd3428c3437/app/Models/User.php#L1505 - recommendedStarDifficulty[rulesetInfo] = Math.Pow((double)(result.Statistics.PP ?? 0), 0.4) * 0.195; + recommendedDifficultyMapping[rulesetInfo] = Math.Pow((double)(result.Statistics.PP ?? 0), 0.4) * 0.195; }; api.Queue(req); @@ -102,29 +98,13 @@ namespace osu.Game.Beatmaps } /// - /// Rulesets ordered by highest recommended star difficulty, except currently selected ruleset first + /// Rulesets ordered descending by their respective recommended difficulties. + /// The currently selected ruleset will always be first. /// - private IEnumerable getBestRulesetOrder() - { - IEnumerable bestRulesetOrder = recommendedStarDifficulty.OrderByDescending(pair => pair.Value) - .Select(pair => pair.Key); - - List orderedRulesets; - - if (bestRulesetOrder.Contains(ruleset.Value)) - { - orderedRulesets = bestRulesetOrder.ToList(); - orderedRulesets.Remove(ruleset.Value); - orderedRulesets.Insert(0, ruleset.Value); - } - else - { - orderedRulesets = new List { ruleset.Value }; - orderedRulesets.AddRange(bestRulesetOrder); - } - - return orderedRulesets; - } + private IEnumerable orderedRulesets => + recommendedDifficultyMapping + .OrderByDescending(pair => pair.Value).Select(pair => pair.Key).Where(r => !r.Equals(ruleset.Value)) + .Prepend(ruleset.Value); private void onlineStateChanged(ValueChangedEvent state) => Schedule(() => { From dece41d050d2f063ed3002269475167484b2270c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 22 Dec 2020 14:58:47 +0900 Subject: [PATCH 210/328] Add todo --- osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index d654496f40..f4e84510bf 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -14,6 +14,7 @@ using osu.Game.Screens.Ranking; namespace osu.Game.Screens.Multi.RealtimeMultiplayer { + // Todo: The "room" part of TimeshiftPlayer should be split out into an abstract player class to be inherited instead. public class RealtimePlayer : TimeshiftPlayer { protected override bool PauseOnFocusLost => false; From 81e2edc73ff95d47d272c711d1c7034829a68870 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 22 Dec 2020 14:59:11 +0900 Subject: [PATCH 211/328] Use MRE with timeout to wait on match start --- .../RealtimeMultiplayer/RealtimePlayer.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index f4e84510bf..c6d44686b5 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -6,6 +6,8 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using osu.Framework.Allocation; +using osu.Framework.Logging; +using osu.Framework.Screens; using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Scoring; @@ -26,7 +28,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer private StatefulMultiplayerClient client { get; set; } private readonly TaskCompletionSource resultsReady = new TaskCompletionSource(); - private bool started; + private readonly ManualResetEventSlim startedEvent = new ManualResetEventSlim(); public RealtimePlayer(PlaylistItem playlistItem) : base(playlistItem, false) @@ -43,11 +45,19 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer client.ResultsReady += onResultsReady; client.ChangeState(MultiplayerUserState.Loaded); - while (!started) - Thread.Sleep(100); + if (!startedEvent.Wait(TimeSpan.FromSeconds(30))) + { + Logger.Log("Failed to start the multiplayer match in time.", LoggingTarget.Runtime, LogLevel.Important); + + Schedule(() => + { + ValidForResume = false; + this.Exit(); + }); + } } - private void onMatchStarted() => started = true; + private void onMatchStarted() => startedEvent.Set(); private void onResultsReady() => resultsReady.SetResult(true); From 3f966386ed563bd43c241068cf3bdd8ec10f8541 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 15:15:32 +0900 Subject: [PATCH 212/328] Fix compile time failure due to potentially null connection --- .../Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs index 6f18e1c922..75bb578a29 100644 --- a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs @@ -4,6 +4,7 @@ #nullable enable using System; +using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR.Client; @@ -99,6 +100,8 @@ namespace osu.Game.Online.RealtimeMultiplayer { try { + Debug.Assert(connection != null); + // reconnect on any failure await connection.StartAsync(); Logger.Log("Multiplayer client connected!", LoggingTarget.Network); From 85e93c5ddec913aa48515814867e89688c92e518 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 15:22:27 +0900 Subject: [PATCH 213/328] Fix main menu multiplayer icons being back to front --- osu.Game/Screens/Menu/ButtonSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index b52ab2cb2f..badfa3f693 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -124,8 +124,8 @@ namespace osu.Game.Screens.Menu private void load(AudioManager audio, IdleTracker idleTracker, GameHost host) { buttonsPlay.Add(new Button(@"solo", @"button-solo-select", FontAwesome.Solid.User, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P)); - buttonsPlay.Add(new Button(@"multi", @"button-generic-select", OsuIcon.Charts, new Color4(94, 63, 186, 255), onMultiplayer, 0, Key.M)); - buttonsPlay.Add(new Button(@"timeshift", @"button-generic-select", FontAwesome.Solid.Users, new Color4(94, 63, 186, 255), onTimeshift, 0, Key.L)); + buttonsPlay.Add(new Button(@"multi", @"button-generic-select", FontAwesome.Solid.Users, new Color4(94, 63, 186, 255), onMultiplayer, 0, Key.M)); + buttonsPlay.Add(new Button(@"timeshift", @"button-generic-select", OsuIcon.Charts, new Color4(94, 63, 186, 255), onTimeshift, 0, Key.L)); buttonsPlay.ForEach(b => b.VisibleState = ButtonSystemState.Play); buttonsTopLevel.Add(new Button(@"play", @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P)); From ab90db7c8df2ab778d3b84d964eae62823e41443 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 22 Dec 2020 15:27:49 +0900 Subject: [PATCH 214/328] Fix stuck lounge on join failure --- .../Multi/RealtimeMultiplayer/RealtimeRoomManager.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index e0fca3ce4c..0c9b58a0c4 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -38,10 +38,10 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer } public override void CreateRoom(Room room, Action onSuccess = null, Action onError = null) - => base.CreateRoom(room, r => joinMultiplayerRoom(r, onSuccess), onError); + => base.CreateRoom(room, r => joinMultiplayerRoom(r, onSuccess, onError), onError); public override void JoinRoom(Room room, Action onSuccess = null, Action onError = null) - => base.JoinRoom(room, r => joinMultiplayerRoom(r, onSuccess), onError); + => base.JoinRoom(room, r => joinMultiplayerRoom(r, onSuccess, onError), onError); public override void PartRoom() { @@ -62,7 +62,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer }); } - private void joinMultiplayerRoom(Room room, Action onSuccess = null) + private void joinMultiplayerRoom(Room room, Action onSuccess = null, Action onError = null) { Debug.Assert(room.RoomID.Value != null); @@ -73,6 +73,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer PartRoom(); if (t.Exception != null) Logger.Error(t.Exception, "Failed to join multiplayer room."); + onError?.Invoke(t.Exception?.ToString() ?? string.Empty); }, TaskContinuationOptions.NotOnRanToCompletion); } From 27e64bdb342aa33aa74da56fa155960662fc3a1e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 22 Dec 2020 15:31:07 +0900 Subject: [PATCH 215/328] Schedule callback continuations --- .../Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index 0c9b58a0c4..7ce031e0e9 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -67,13 +67,13 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer Debug.Assert(room.RoomID.Value != null); var joinTask = multiplayerClient.JoinRoom(room); - joinTask.ContinueWith(_ => onSuccess?.Invoke(room), TaskContinuationOptions.OnlyOnRanToCompletion); + joinTask.ContinueWith(_ => Schedule(() => onSuccess?.Invoke(room)), TaskContinuationOptions.OnlyOnRanToCompletion); joinTask.ContinueWith(t => { PartRoom(); if (t.Exception != null) Logger.Error(t.Exception, "Failed to join multiplayer room."); - onError?.Invoke(t.Exception?.ToString() ?? string.Empty); + Schedule(() => onError?.Invoke(t.Exception?.ToString() ?? string.Empty)); }, TaskContinuationOptions.NotOnRanToCompletion); } From 8201fa8e3463024ab3155738df934bc1cf967822 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 15:51:24 +0900 Subject: [PATCH 216/328] Split out common implementation and private classes in MatchSettingsOverlay --- .../TestSceneMatchSettingsOverlay.cs | 10 +- .../TestSceneTimeshiftRoomSubScreen.cs | 2 +- .../Match/Components/MatchSettingsOverlay.cs | 185 +++++++++--------- .../Match/RealtimeMatchSettingsOverlay.cs | 95 +-------- .../Multi/Timeshift/TimeshiftRoomSubScreen.cs | 5 +- 5 files changed, 108 insertions(+), 189 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs index 234374ee2b..90eef26b20 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs @@ -109,14 +109,14 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("error not displayed", () => !settings.ErrorText.IsPresent); } - private class TestRoomSettings : MatchSettingsOverlay + private class TestRoomSettings : TimeshiftMatchSettingsOverlay { - public TriangleButton ApplyButton => Settings.ApplyButton; + public TriangleButton ApplyButton => ((MatchSettings)Settings).ApplyButton; - public OsuTextBox NameField => Settings.NameField; - public OsuDropdown DurationField => Settings.DurationField; + public OsuTextBox NameField => ((MatchSettings)Settings).NameField; + public OsuDropdown DurationField => ((MatchSettings)Settings).DurationField; - public OsuSpriteText ErrorText => Settings.ErrorText; + public OsuSpriteText ErrorText => ((MatchSettings)Settings).ErrorText; } private class TestRoomManager : IRoomManager diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs index f56f78ce89..bbd7d84081 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs @@ -120,7 +120,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("create room", () => { - InputManager.MoveMouseTo(match.ChildrenOfType().Single()); + InputManager.MoveMouseTo(match.ChildrenOfType().Single()); InputManager.Click(MouseButton.Left); }); diff --git a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs index 1859e8db8a..d837ceaccf 100644 --- a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs +++ b/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs @@ -21,20 +21,108 @@ using osuTK.Graphics; namespace osu.Game.Screens.Multi.Match.Components { - public class MatchSettingsOverlay : FocusedOverlayContainer + public abstract class MatchSettingsOverlay : FocusedOverlayContainer { - private const float transition_duration = 350; - private const float field_padding = 45; + protected const float TRANSITION_DURATION = 350; + protected const float FIELD_PADDING = 45; - public Action EditPlaylist; - - protected MatchSettings Settings { get; private set; } + protected MultiplayerComposite Settings { get; set; } [BackgroundDependencyLoader] private void load() { Masking = true; + } + protected override void PopIn() + { + Settings.MoveToY(0, TRANSITION_DURATION, Easing.OutQuint); + } + + protected override void PopOut() + { + Settings.MoveToY(-1, TRANSITION_DURATION, Easing.InSine); + } + + protected class SettingsTextBox : OsuTextBox + { + [BackgroundDependencyLoader] + private void load() + { + BackgroundUnfocused = Color4.Black; + BackgroundFocused = Color4.Black; + } + } + + protected class SettingsNumberTextBox : SettingsTextBox + { + protected override bool CanAddCharacter(char character) => char.IsNumber(character); + } + + protected class SettingsPasswordTextBox : OsuPasswordTextBox + { + [BackgroundDependencyLoader] + private void load() + { + BackgroundUnfocused = Color4.Black; + BackgroundFocused = Color4.Black; + } + } + + protected class SectionContainer : FillFlowContainer
+ { + public SectionContainer() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Width = 0.5f; + Direction = FillDirection.Vertical; + Spacing = new Vector2(FIELD_PADDING); + } + } + + protected class Section : Container + { + private readonly Container content; + + protected override Container Content => content; + + public Section(string title) + { + AutoSizeAxes = Axes.Y; + RelativeSizeAxes = Axes.X; + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new OsuSpriteText + { + Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 12), + Text = title.ToUpper(), + }, + content = new Container + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + }, + }, + }; + } + } + } + + public class TimeshiftMatchSettingsOverlay : MatchSettingsOverlay + { + public Action EditPlaylist; + + [BackgroundDependencyLoader] + private void load() + { Child = Settings = new MatchSettings { RelativeSizeAxes = Axes.Both, @@ -43,16 +131,6 @@ namespace osu.Game.Screens.Multi.Match.Components }; } - protected override void PopIn() - { - Settings.MoveToY(0, transition_duration, Easing.OutQuint); - } - - protected override void PopOut() - { - Settings.MoveToY(-1, transition_duration, Easing.InSine); - } - protected class MatchSettings : MultiplayerComposite { private const float disabled_alpha = 0.2f; @@ -126,7 +204,7 @@ namespace osu.Game.Screens.Multi.Match.Components { new SectionContainer { - Padding = new MarginPadding { Right = field_padding / 2 }, + Padding = new MarginPadding { Right = FIELD_PADDING / 2 }, Children = new[] { new Section("Room name") @@ -216,7 +294,7 @@ namespace osu.Game.Screens.Multi.Match.Components { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Padding = new MarginPadding { Left = field_padding / 2 }, + Padding = new MarginPadding { Left = FIELD_PADDING / 2 }, Children = new[] { new Section("Playlist") @@ -379,77 +457,6 @@ namespace osu.Game.Screens.Multi.Match.Components } } - private class SettingsTextBox : OsuTextBox - { - [BackgroundDependencyLoader] - private void load() - { - BackgroundUnfocused = Color4.Black; - BackgroundFocused = Color4.Black; - } - } - - private class SettingsNumberTextBox : SettingsTextBox - { - protected override bool CanAddCharacter(char character) => char.IsNumber(character); - } - - private class SettingsPasswordTextBox : OsuPasswordTextBox - { - [BackgroundDependencyLoader] - private void load() - { - BackgroundUnfocused = Color4.Black; - BackgroundFocused = Color4.Black; - } - } - - private class SectionContainer : FillFlowContainer
- { - public SectionContainer() - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Width = 0.5f; - Direction = FillDirection.Vertical; - Spacing = new Vector2(field_padding); - } - } - - private class Section : Container - { - private readonly Container content; - - protected override Container Content => content; - - public Section(string title) - { - AutoSizeAxes = Axes.Y; - RelativeSizeAxes = Axes.X; - - InternalChild = new FillFlowContainer - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, - Spacing = new Vector2(5), - Children = new Drawable[] - { - new OsuSpriteText - { - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 12), - Text = title.ToUpper(), - }, - content = new Container - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - }, - }, - }; - } - } - public class CreateRoomButton : TriangleButton { public CreateRoomButton() diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs index 924c736472..5bd388cceb 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs @@ -19,22 +19,14 @@ using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Screens.Multi.Match.Components; using osuTK; -using osuTK.Graphics; namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match { - public class RealtimeMatchSettingsOverlay : FocusedOverlayContainer + public class RealtimeMatchSettingsOverlay : MatchSettingsOverlay { - private const float transition_duration = 350; - private const float field_padding = 45; - - protected MatchSettings Settings { get; private set; } - [BackgroundDependencyLoader] private void load() { - Masking = true; - Child = Settings = new MatchSettings { RelativeSizeAxes = Axes.Both, @@ -43,16 +35,6 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match }; } - protected override void PopIn() - { - Settings.MoveToY(0, transition_duration, Easing.OutQuint); - } - - protected override void PopOut() - { - Settings.MoveToY(-1, transition_duration, Easing.InSine); - } - protected class MatchSettings : MultiplayerComposite { private const float disabled_alpha = 0.2f; @@ -143,7 +125,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match { new SectionContainer { - Padding = new MarginPadding { Right = field_padding / 2 }, + Padding = new MarginPadding { Right = FIELD_PADDING / 2 }, Children = new[] { new Section("Room name") @@ -192,7 +174,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Padding = new MarginPadding { Left = field_padding / 2 }, + Padding = new MarginPadding { Left = FIELD_PADDING / 2 }, Children = new[] { new Section("Max participants") @@ -347,77 +329,6 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match } } - private class SettingsTextBox : OsuTextBox - { - [BackgroundDependencyLoader] - private void load() - { - BackgroundUnfocused = Color4.Black; - BackgroundFocused = Color4.Black; - } - } - - private class SettingsNumberTextBox : SettingsTextBox - { - protected override bool CanAddCharacter(char character) => char.IsNumber(character); - } - - private class SettingsPasswordTextBox : OsuPasswordTextBox - { - [BackgroundDependencyLoader] - private void load() - { - BackgroundUnfocused = Color4.Black; - BackgroundFocused = Color4.Black; - } - } - - private class SectionContainer : FillFlowContainer
- { - public SectionContainer() - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Width = 0.5f; - Direction = FillDirection.Vertical; - Spacing = new Vector2(field_padding); - } - } - - private class Section : Container - { - private readonly Container content; - - protected override Container Content => content; - - public Section(string title) - { - AutoSizeAxes = Axes.Y; - RelativeSizeAxes = Axes.X; - - InternalChild = new FillFlowContainer - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, - Spacing = new Vector2(5), - Children = new Drawable[] - { - new OsuSpriteText - { - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 12), - Text = title.ToUpper(), - }, - content = new Container - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - }, - }, - }; - } - } - public class CreateOrUpdateButton : TriangleButton { [Resolved(typeof(Room), nameof(Room.RoomID))] diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs index 433a980d60..fa901179e9 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs @@ -18,6 +18,7 @@ using osu.Game.Screens.Multi.Ranking; using osu.Game.Screens.Play; using osu.Game.Screens.Select; using osu.Game.Users; +using Footer = osu.Game.Screens.Multi.Match.Components.Footer; namespace osu.Game.Screens.Multi.Timeshift { @@ -175,7 +176,7 @@ namespace osu.Game.Screens.Multi.Timeshift }, new Drawable[] { - new Match.Components.Footer + new Footer { OnStart = onStart, SelectedItem = { BindTarget = SelectedItem } @@ -188,7 +189,7 @@ namespace osu.Game.Screens.Multi.Timeshift new Dimension(GridSizeMode.AutoSize), } }, - settingsOverlay = new MatchSettingsOverlay + settingsOverlay = new TimeshiftMatchSettingsOverlay { RelativeSizeAxes = Axes.Both, EditPlaylist = () => this.Push(new MatchSongSelect()), From 17d924c7554d561d028ed761681c6e4703286267 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 15:52:47 +0900 Subject: [PATCH 217/328] Move timeshift settings overlay to correct namespace --- .../TestSceneMatchSettingsOverlay.cs | 2 +- .../Match/Components/MatchSettingsOverlay.cs | 377 ----------------- .../TimeshiftMatchSettingsOverlay.cs | 391 ++++++++++++++++++ 3 files changed, 392 insertions(+), 378 deletions(-) create mode 100644 osu.Game/Screens/Multi/Timeshift/TimeshiftMatchSettingsOverlay.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs index 90eef26b20..1fcae9c709 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi; -using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.Multi.Timeshift; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs index d837ceaccf..0bb56d0cdf 100644 --- a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs +++ b/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs @@ -1,21 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using System.Collections.Specialized; -using Humanizer; using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Multiplayer; -using osu.Game.Overlays; using osuTK; using osuTK.Graphics; @@ -115,372 +106,4 @@ namespace osu.Game.Screens.Multi.Match.Components } } } - - public class TimeshiftMatchSettingsOverlay : MatchSettingsOverlay - { - public Action EditPlaylist; - - [BackgroundDependencyLoader] - private void load() - { - Child = Settings = new MatchSettings - { - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Y, - EditPlaylist = () => EditPlaylist?.Invoke() - }; - } - - protected class MatchSettings : MultiplayerComposite - { - private const float disabled_alpha = 0.2f; - - public Action EditPlaylist; - - public OsuTextBox NameField, MaxParticipantsField; - public OsuDropdown DurationField; - public RoomAvailabilityPicker AvailabilityPicker; - public GameTypePicker TypePicker; - public TriangleButton ApplyButton; - - public OsuSpriteText ErrorText; - - private OsuSpriteText typeLabel; - private LoadingLayer loadingLayer; - private DrawableRoomPlaylist playlist; - private OsuSpriteText playlistLength; - - [Resolved(CanBeNull = true)] - private IRoomManager manager { get; set; } - - [Resolved] - private Bindable currentRoom { get; set; } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Container dimContent; - - InternalChildren = new Drawable[] - { - dimContent = new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"28242d"), - }, - new GridContainer - { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] - { - new Dimension(GridSizeMode.Distributed), - new Dimension(GridSizeMode.AutoSize), - }, - Content = new[] - { - new Drawable[] - { - new OsuScrollContainer - { - Padding = new MarginPadding - { - Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING, - Vertical = 10 - }, - RelativeSizeAxes = Axes.Both, - Children = new[] - { - new Container - { - Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING }, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new SectionContainer - { - Padding = new MarginPadding { Right = FIELD_PADDING / 2 }, - Children = new[] - { - new Section("Room name") - { - Child = NameField = new SettingsTextBox - { - RelativeSizeAxes = Axes.X, - TabbableContentContainer = this, - LengthLimit = 100 - }, - }, - new Section("Duration") - { - Child = DurationField = new DurationDropdown - { - RelativeSizeAxes = Axes.X, - Items = new[] - { - TimeSpan.FromMinutes(30), - TimeSpan.FromHours(1), - TimeSpan.FromHours(2), - TimeSpan.FromHours(4), - TimeSpan.FromHours(8), - TimeSpan.FromHours(12), - //TimeSpan.FromHours(16), - TimeSpan.FromHours(24), - TimeSpan.FromDays(3), - TimeSpan.FromDays(7) - } - } - }, - new Section("Room visibility") - { - Alpha = disabled_alpha, - Child = AvailabilityPicker = new RoomAvailabilityPicker - { - Enabled = { Value = false } - }, - }, - new Section("Game type") - { - Alpha = disabled_alpha, - Child = new FillFlowContainer - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, - Spacing = new Vector2(7), - Children = new Drawable[] - { - TypePicker = new GameTypePicker - { - RelativeSizeAxes = Axes.X, - Enabled = { Value = false } - }, - typeLabel = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 14), - Colour = colours.Yellow - }, - }, - }, - }, - new Section("Max participants") - { - Alpha = disabled_alpha, - Child = MaxParticipantsField = new SettingsNumberTextBox - { - RelativeSizeAxes = Axes.X, - TabbableContentContainer = this, - ReadOnly = true, - }, - }, - new Section("Password (optional)") - { - Alpha = disabled_alpha, - Child = new SettingsPasswordTextBox - { - RelativeSizeAxes = Axes.X, - TabbableContentContainer = this, - ReadOnly = true, - }, - }, - }, - }, - new SectionContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Padding = new MarginPadding { Left = FIELD_PADDING / 2 }, - Children = new[] - { - new Section("Playlist") - { - Child = new GridContainer - { - RelativeSizeAxes = Axes.X, - Height = 300, - Content = new[] - { - new Drawable[] - { - playlist = new DrawableRoomPlaylist(true, true) { RelativeSizeAxes = Axes.Both } - }, - new Drawable[] - { - playlistLength = new OsuSpriteText - { - Margin = new MarginPadding { Vertical = 5 }, - Colour = colours.Yellow, - Font = OsuFont.GetFont(size: 12), - } - }, - new Drawable[] - { - new PurpleTriangleButton - { - RelativeSizeAxes = Axes.X, - Height = 40, - Text = "Edit playlist", - Action = () => EditPlaylist?.Invoke() - } - } - }, - RowDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize), - } - } - }, - }, - }, - }, - } - }, - }, - }, - new Drawable[] - { - new Container - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Y = 2, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"28242d").Darken(0.5f).Opacity(1f), - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 20), - Margin = new MarginPadding { Vertical = 20 }, - Padding = new MarginPadding { Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING }, - Children = new Drawable[] - { - ApplyButton = new CreateRoomButton - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Size = new Vector2(230, 55), - Enabled = { Value = false }, - Action = apply, - }, - ErrorText = new OsuSpriteText - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Alpha = 0, - Depth = 1, - Colour = colours.RedDark - } - } - } - } - } - } - } - }, - } - }, - loadingLayer = new LoadingLayer(dimContent) - }; - - TypePicker.Current.BindValueChanged(type => typeLabel.Text = type.NewValue?.Name ?? string.Empty, true); - RoomName.BindValueChanged(name => NameField.Text = name.NewValue, true); - Availability.BindValueChanged(availability => AvailabilityPicker.Current.Value = availability.NewValue, true); - Type.BindValueChanged(type => TypePicker.Current.Value = type.NewValue, true); - MaxParticipants.BindValueChanged(count => MaxParticipantsField.Text = count.NewValue?.ToString(), true); - Duration.BindValueChanged(duration => DurationField.Current.Value = duration.NewValue ?? TimeSpan.FromMinutes(30), true); - - playlist.Items.BindTo(Playlist); - Playlist.BindCollectionChanged(onPlaylistChanged, true); - } - - protected override void Update() - { - base.Update(); - - ApplyButton.Enabled.Value = hasValidSettings; - } - - private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) => - playlistLength.Text = $"Length: {Playlist.GetTotalDuration()}"; - - private bool hasValidSettings => RoomID.Value == null && NameField.Text.Length > 0 && Playlist.Count > 0; - - private void apply() - { - if (!ApplyButton.Enabled.Value) - return; - - hideError(); - - RoomName.Value = NameField.Text; - Availability.Value = AvailabilityPicker.Current.Value; - Type.Value = TypePicker.Current.Value; - - if (int.TryParse(MaxParticipantsField.Text, out int max)) - MaxParticipants.Value = max; - else - MaxParticipants.Value = null; - - Duration.Value = DurationField.Current.Value; - - manager?.CreateRoom(currentRoom.Value, onSuccess, onError); - - loadingLayer.Show(); - } - - private void hideError() => ErrorText.FadeOut(50); - - private void onSuccess(Room room) => loadingLayer.Hide(); - - private void onError(string text) - { - ErrorText.Text = text; - ErrorText.FadeIn(50); - - loadingLayer.Hide(); - } - } - - public class CreateRoomButton : TriangleButton - { - public CreateRoomButton() - { - Text = "Create"; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - BackgroundColour = colours.Yellow; - Triangles.ColourLight = colours.YellowLight; - Triangles.ColourDark = colours.YellowDark; - } - } - - private class DurationDropdown : OsuDropdown - { - public DurationDropdown() - { - Menu.MaxHeight = 100; - } - - protected override string GenerateItemText(TimeSpan item) => item.Humanize(); - } - } } diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftMatchSettingsOverlay.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftMatchSettingsOverlay.cs new file mode 100644 index 0000000000..7e1e9894d8 --- /dev/null +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftMatchSettingsOverlay.cs @@ -0,0 +1,391 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Specialized; +using Humanizer; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Multiplayer; +using osu.Game.Overlays; +using osu.Game.Screens.Multi.Match.Components; +using osuTK; + +namespace osu.Game.Screens.Multi.Timeshift +{ + public class TimeshiftMatchSettingsOverlay : MatchSettingsOverlay + { + public Action EditPlaylist; + + [BackgroundDependencyLoader] + private void load() + { + Child = Settings = new MatchSettings + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Y, + EditPlaylist = () => EditPlaylist?.Invoke() + }; + } + + protected class MatchSettings : MultiplayerComposite + { + private const float disabled_alpha = 0.2f; + + public Action EditPlaylist; + + public OsuTextBox NameField, MaxParticipantsField; + public OsuDropdown DurationField; + public RoomAvailabilityPicker AvailabilityPicker; + public GameTypePicker TypePicker; + public TriangleButton ApplyButton; + + public OsuSpriteText ErrorText; + + private OsuSpriteText typeLabel; + private LoadingLayer loadingLayer; + private DrawableRoomPlaylist playlist; + private OsuSpriteText playlistLength; + + [Resolved(CanBeNull = true)] + private IRoomManager manager { get; set; } + + [Resolved] + private Bindable currentRoom { get; set; } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Container dimContent; + + InternalChildren = new Drawable[] + { + dimContent = new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"28242d"), + }, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.Distributed), + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new Drawable[] + { + new OsuScrollContainer + { + Padding = new MarginPadding + { + Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING, + Vertical = 10 + }, + RelativeSizeAxes = Axes.Both, + Children = new[] + { + new Container + { + Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new SectionContainer + { + Padding = new MarginPadding { Right = FIELD_PADDING / 2 }, + Children = new[] + { + new Section("Room name") + { + Child = NameField = new SettingsTextBox + { + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + LengthLimit = 100 + }, + }, + new Section("Duration") + { + Child = DurationField = new DurationDropdown + { + RelativeSizeAxes = Axes.X, + Items = new[] + { + TimeSpan.FromMinutes(30), + TimeSpan.FromHours(1), + TimeSpan.FromHours(2), + TimeSpan.FromHours(4), + TimeSpan.FromHours(8), + TimeSpan.FromHours(12), + //TimeSpan.FromHours(16), + TimeSpan.FromHours(24), + TimeSpan.FromDays(3), + TimeSpan.FromDays(7) + } + } + }, + new Section("Room visibility") + { + Alpha = disabled_alpha, + Child = AvailabilityPicker = new RoomAvailabilityPicker + { + Enabled = { Value = false } + }, + }, + new Section("Game type") + { + Alpha = disabled_alpha, + Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Spacing = new Vector2(7), + Children = new Drawable[] + { + TypePicker = new GameTypePicker + { + RelativeSizeAxes = Axes.X, + Enabled = { Value = false } + }, + typeLabel = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 14), + Colour = colours.Yellow + }, + }, + }, + }, + new Section("Max participants") + { + Alpha = disabled_alpha, + Child = MaxParticipantsField = new SettingsNumberTextBox + { + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + ReadOnly = true, + }, + }, + new Section("Password (optional)") + { + Alpha = disabled_alpha, + Child = new SettingsPasswordTextBox + { + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + ReadOnly = true, + }, + }, + }, + }, + new SectionContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Padding = new MarginPadding { Left = FIELD_PADDING / 2 }, + Children = new[] + { + new Section("Playlist") + { + Child = new GridContainer + { + RelativeSizeAxes = Axes.X, + Height = 300, + Content = new[] + { + new Drawable[] + { + playlist = new DrawableRoomPlaylist(true, true) { RelativeSizeAxes = Axes.Both } + }, + new Drawable[] + { + playlistLength = new OsuSpriteText + { + Margin = new MarginPadding { Vertical = 5 }, + Colour = colours.Yellow, + Font = OsuFont.GetFont(size: 12), + } + }, + new Drawable[] + { + new PurpleTriangleButton + { + RelativeSizeAxes = Axes.X, + Height = 40, + Text = "Edit playlist", + Action = () => EditPlaylist?.Invoke() + } + } + }, + RowDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + } + } + }, + }, + }, + }, + } + }, + }, + }, + new Drawable[] + { + new Container + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Y = 2, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"28242d").Darken(0.5f).Opacity(1f), + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Margin = new MarginPadding { Vertical = 20 }, + Padding = new MarginPadding { Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING }, + Children = new Drawable[] + { + ApplyButton = new CreateRoomButton + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Size = new Vector2(230, 55), + Enabled = { Value = false }, + Action = apply, + }, + ErrorText = new OsuSpriteText + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Alpha = 0, + Depth = 1, + Colour = colours.RedDark + } + } + } + } + } + } + } + }, + } + }, + loadingLayer = new LoadingLayer(dimContent) + }; + + TypePicker.Current.BindValueChanged(type => typeLabel.Text = type.NewValue?.Name ?? string.Empty, true); + RoomName.BindValueChanged(name => NameField.Text = name.NewValue, true); + Availability.BindValueChanged(availability => AvailabilityPicker.Current.Value = availability.NewValue, true); + Type.BindValueChanged(type => TypePicker.Current.Value = type.NewValue, true); + MaxParticipants.BindValueChanged(count => MaxParticipantsField.Text = count.NewValue?.ToString(), true); + Duration.BindValueChanged(duration => DurationField.Current.Value = duration.NewValue ?? TimeSpan.FromMinutes(30), true); + + playlist.Items.BindTo(Playlist); + Playlist.BindCollectionChanged(onPlaylistChanged, true); + } + + protected override void Update() + { + base.Update(); + + ApplyButton.Enabled.Value = hasValidSettings; + } + + private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) => + playlistLength.Text = $"Length: {Playlist.GetTotalDuration()}"; + + private bool hasValidSettings => RoomID.Value == null && NameField.Text.Length > 0 && Playlist.Count > 0; + + private void apply() + { + if (!ApplyButton.Enabled.Value) + return; + + hideError(); + + RoomName.Value = NameField.Text; + Availability.Value = AvailabilityPicker.Current.Value; + Type.Value = TypePicker.Current.Value; + + if (int.TryParse(MaxParticipantsField.Text, out int max)) + MaxParticipants.Value = max; + else + MaxParticipants.Value = null; + + Duration.Value = DurationField.Current.Value; + + manager?.CreateRoom(currentRoom.Value, onSuccess, onError); + + loadingLayer.Show(); + } + + private void hideError() => ErrorText.FadeOut(50); + + private void onSuccess(Room room) => loadingLayer.Hide(); + + private void onError(string text) + { + ErrorText.Text = text; + ErrorText.FadeIn(50); + + loadingLayer.Hide(); + } + } + + public class CreateRoomButton : TriangleButton + { + public CreateRoomButton() + { + Text = "Create"; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = colours.Yellow; + Triangles.ColourLight = colours.YellowLight; + Triangles.ColourDark = colours.YellowDark; + } + } + + private class DurationDropdown : OsuDropdown + { + public DurationDropdown() + { + Menu.MaxHeight = 100; + } + + protected override string GenerateItemText(TimeSpan item) => item.Humanize(); + } + } +} From 34421c92327c00fb3574141271f6d6094f5f94da Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 15:58:57 +0900 Subject: [PATCH 218/328] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 2a08cb7867..fc01f9bf1d 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 960959f367..cbf9f6f1bd 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -26,7 +26,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index a5bcb91c74..adbcc0ef1c 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -88,7 +88,7 @@ - + From 3cf889b7c5c4d8f4e8382ab5245c30a551b1f7e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 16:19:19 +0900 Subject: [PATCH 219/328] Fix some errors being completely ignored --- osu.Game/Screens/Multi/Components/RoomManager.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Screens/Multi/Components/RoomManager.cs b/osu.Game/Screens/Multi/Components/RoomManager.cs index 482ee5492c..f78d0d979e 100644 --- a/osu.Game/Screens/Multi/Components/RoomManager.cs +++ b/osu.Game/Screens/Multi/Components/RoomManager.cs @@ -76,10 +76,7 @@ namespace osu.Game.Screens.Multi.Components req.Failure += exception => { - if (req.Result != null) - onError?.Invoke(req.Result.Error); - else - Logger.Log($"Failed to create the room: {exception}", level: LogLevel.Important); + onError?.Invoke(req.Result?.Error ?? exception.Message); }; api.Queue(req); From 2d7174d99cc6e24b30f3266a32cd86fe9c735c34 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 22 Dec 2020 16:23:06 +0900 Subject: [PATCH 220/328] Add padding to song select --- .../Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs index 157216e9bb..b2ae5402a1 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs @@ -5,6 +5,7 @@ using System.Linq; using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; @@ -24,6 +25,11 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer [Resolved] private StatefulMultiplayerClient client { get; set; } + public RealtimeMatchSongSelect() + { + Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; + } + protected override bool OnStart() { var item = new PlaylistItem(); From 12876d7fb642500d7c5db31827a718a0af7b1798 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 16:50:30 +0900 Subject: [PATCH 221/328] Add very basic error handling on ChangeSettings calls --- .../StatefulMultiplayerClient.cs | 6 +++--- .../Match/RealtimeMatchSettingsOverlay.cs | 9 +++++++-- .../RealtimeMultiplayer/RealtimeMatchSongSelect.cs | 13 +++++++++++-- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index f56499f040..4ebd648689 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -127,10 +127,10 @@ namespace osu.Game.Online.RealtimeMultiplayer /// /// The new room name, if any. /// The new room playlist item, if any. - public void ChangeSettings(Optional name = default, Optional item = default) + public Task ChangeSettings(Optional name = default, Optional item = default) { if (Room == null) - return; + throw new InvalidOperationException("Must be joined to a match to change settings."); // A dummy playlist item filled with the current room settings (except mods). var existingPlaylistItem = new PlaylistItem @@ -146,7 +146,7 @@ namespace osu.Game.Online.RealtimeMultiplayer RulesetID = Room.Settings.RulesetID }; - ChangeSettings(new MultiplayerRoomSettings + return ChangeSettings(new MultiplayerRoomSettings { Name = name.GetOr(Room.Settings.Name), BeatmapID = item.GetOr(existingPlaylistItem).BeatmapID, diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs index 5bd388cceb..3e495b490f 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs @@ -294,8 +294,13 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match // Otherwise, update the room directly in preparation for it to be submitted to the API on match creation. if (client.Room != null) { - client.ChangeSettings(name: NameField.Text); - onSuccess(currentRoom.Value); + client.ChangeSettings(name: NameField.Text).ContinueWith(t => Schedule(() => + { + if (t.IsCompletedSuccessfully) + onSuccess(currentRoom.Value); + else + onError(t.Exception?.Message ?? "Error changing settings."); + })); } else { diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs index b2ae5402a1..0feeed6fe5 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs @@ -6,6 +6,7 @@ using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; @@ -43,14 +44,22 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer // If the client is already in a room, update via the client. // Otherwise, update the playlist directly in preparation for it to be submitted to the API on match creation. if (client.Room != null) - client.ChangeSettings(item: item); + { + client.ChangeSettings(item: item).ContinueWith(t => Schedule(() => + { + if (t.IsCompletedSuccessfully) + this.Exit(); + else + Logger.Log($"Could not use current beatmap ({t.Exception?.Message})", level: LogLevel.Important); + })); + } else { playlist.Clear(); playlist.Add(item); + this.Exit(); } - this.Exit(); return true; } From 30357a9447a077e09b7e0a11006fd48a156890a5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 17:08:02 +0900 Subject: [PATCH 222/328] Add loading layer to multi song select to show during settings confirmation --- .../RealtimeMatchSongSelect.cs | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs index 0feeed6fe5..d4308d361c 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs @@ -2,12 +2,14 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; +using System.Threading; using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Logging; using osu.Framework.Screens; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Screens.Select; @@ -26,11 +28,19 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer [Resolved] private StatefulMultiplayerClient client { get; set; } + private LoadingLayer loadingLayer; + public RealtimeMatchSongSelect() { Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; } + [BackgroundDependencyLoader] + private void load() + { + AddInternal(loadingLayer = new LoadingLayer(Carousel)); + } + protected override bool OnStart() { var item = new PlaylistItem(); @@ -45,13 +55,20 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer // Otherwise, update the playlist directly in preparation for it to be submitted to the API on match creation. if (client.Room != null) { - client.ChangeSettings(item: item).ContinueWith(t => Schedule(() => + loadingLayer.Show(); + + client.ChangeSettings(item: item).ContinueWith(t => { - if (t.IsCompletedSuccessfully) - this.Exit(); - else - Logger.Log($"Could not use current beatmap ({t.Exception?.Message})", level: LogLevel.Important); - })); + return Schedule(() => + { + loadingLayer.Hide(); + + if (t.IsCompletedSuccessfully) + this.Exit(); + else + Logger.Log($"Could not use current beatmap ({t.Exception?.Message})", level: LogLevel.Important); + }); + }); } else { From 59734229ff94bd907fd640374ce081c62581cb61 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 17:21:53 +0900 Subject: [PATCH 223/328] Remove unused using --- .../Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs index d4308d361c..f3dab93089 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using System.Threading; using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; From 3d5783a0eab3e1360dad85f9b6b5183c56467be9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 17:34:51 +0900 Subject: [PATCH 224/328] Improve variable names --- .../Sections/Graphics/LayoutSettings.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 6ec5d1f03a..b722fd4137 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -140,20 +140,20 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics windowModeDropdown.Hide(); }, true); - windowModeDropdown.Current.ValueChanged += v => updateResolutionDropdown(); + windowModeDropdown.Current.ValueChanged += _ => updateResolutionDropdown(); - currentDisplay.BindValueChanged(v => Schedule(() => + currentDisplay.BindValueChanged(display => Schedule(() => { resolutions.RemoveRange(1, resolutions.Count - 1); - if (v.NewValue != null) + if (display.NewValue != null) { - resolutions.AddRange(v.NewValue.DisplayModes - .Where(m => m.Size.Width >= 800 && m.Size.Height >= 600) - .OrderByDescending(m => m.Size.Width) - .ThenByDescending(m => m.Size.Height) - .Select(m => m.Size) - .Distinct()); + resolutions.AddRange(display.NewValue.DisplayModes + .Where(m => m.Size.Width >= 800 && m.Size.Height >= 600) + .OrderByDescending(m => m.Size.Width) + .ThenByDescending(m => m.Size.Height) + .Select(m => m.Size) + .Distinct()); } updateResolutionDropdown(); From 4f02928601b75ed162b6527b728cce8d971182cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 17:36:56 +0900 Subject: [PATCH 225/328] Change sorting to better handle portrait screens --- .../Overlays/Settings/Sections/Graphics/LayoutSettings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index b722fd4137..3d3b543d70 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Drawing; using System.Linq; using osu.Framework.Allocation; @@ -150,8 +151,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics { resolutions.AddRange(display.NewValue.DisplayModes .Where(m => m.Size.Width >= 800 && m.Size.Height >= 600) - .OrderByDescending(m => m.Size.Width) - .ThenByDescending(m => m.Size.Height) + .OrderByDescending(m => Math.Max(m.Size.Height, m.Size.Width)) .Select(m => m.Size) .Distinct()); } From ce806dd880f58b03e18fdf80d76ce9f5c67c86e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 18:25:45 +0900 Subject: [PATCH 226/328] Replace the ready mark display with a state display, showing all participant states --- .../Multiplayer/TestSceneParticipantsList.cs | 1 + .../TestSceneParticipantsList.cs | 11 +- .../Participants/ParticipantPanel.cs | 10 +- .../Participants/ReadyMark.cs | 51 ------- .../Participants/StateDisplay.cs | 128 ++++++++++++++++++ 5 files changed, 138 insertions(+), 63 deletions(-) delete mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ReadyMark.cs create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/StateDisplay.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs index 7bbec7d30e..360aa22af9 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs @@ -20,6 +20,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Room.RecentParticipants.Add(new User { Username = "peppy", + CurrentModeRank = 1234, Id = 2 }); } diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs index 8c997e9e32..35ea0d3813 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Testing; +using osu.Framework.Utils; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Screens.Multi.RealtimeMultiplayer.Participants; using osu.Game.Users; @@ -65,13 +66,13 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer [Test] public void TestToggleReadyState() { - AddAssert("ready mark invisible", () => !this.ChildrenOfType().Single().IsPresent); + AddAssert("ready mark invisible", () => !this.ChildrenOfType().Single().IsPresent); AddStep("make user ready", () => Client.ChangeState(MultiplayerUserState.Ready)); - AddUntilStep("ready mark visible", () => this.ChildrenOfType().Single().IsPresent); + AddUntilStep("ready mark visible", () => this.ChildrenOfType().Single().IsPresent); AddStep("make user idle", () => Client.ChangeState(MultiplayerUserState.Idle)); - AddUntilStep("ready mark invisible", () => !this.ChildrenOfType().Single().IsPresent); + AddUntilStep("ready mark invisible", () => !this.ChildrenOfType().Single().IsPresent); } [Test] @@ -104,11 +105,11 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer { Id = i, Username = $"User {i}", + CurrentModeRank = RNG.Next(1, 100000), CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", }); - if (i % 2 == 0) - Client.ChangeUserState(i, MultiplayerUserState.Ready); + Client.ChangeUserState(i, (MultiplayerUserState)RNG.Next(0, (int)MultiplayerUserState.Results)); } }); } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs index 002849a275..a4ff2ce346 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs @@ -30,7 +30,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants [Resolved] private IAPIProvider api { get; set; } - private ReadyMark readyMark; + private StateDisplay userStateDisplay; private SpriteIcon crown; public ParticipantPanel(MultiplayerRoomUser user) @@ -122,12 +122,11 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants } } }, - readyMark = new ReadyMark + userStateDisplay = new StateDisplay { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Margin = new MarginPadding { Right = 10 }, - Alpha = 0 } } } @@ -144,10 +143,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants const double fade_time = 50; - if (User.State == MultiplayerUserState.Ready) - readyMark.FadeIn(fade_time); - else - readyMark.FadeOut(fade_time); + userStateDisplay.Status = User.State; if (Room.Host?.Equals(User) == true) crown.FadeIn(fade_time); diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ReadyMark.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ReadyMark.cs deleted file mode 100644 index df49d9342e..0000000000 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ReadyMark.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osuTK; - -namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants -{ - public class ReadyMark : CompositeDrawable - { - public ReadyMark() - { - AutoSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader] - private void load() - { - InternalChild = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Spacing = new Vector2(5), - Children = new Drawable[] - { - new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 12), - Text = "ready", - Colour = Color4Extensions.FromHex("#DDFFFF") - }, - new SpriteIcon - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Icon = FontAwesome.Solid.CheckCircle, - Size = new Vector2(12), - Colour = Color4Extensions.FromHex("#AADD00") - } - } - }; - } - } -} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/StateDisplay.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/StateDisplay.cs new file mode 100644 index 0000000000..db93525217 --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/StateDisplay.cs @@ -0,0 +1,128 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.RealtimeMultiplayer; +using osuTK; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants +{ + public class StateDisplay : CompositeDrawable + { + public StateDisplay() + { + AutoSizeAxes = Axes.Both; + } + + private MultiplayerUserState status; + + private OsuSpriteText text; + private SpriteIcon icon; + + private const double fade_time = 50; + + public MultiplayerUserState Status + { + set + { + if (value == status) + return; + + status = value; + + if (IsLoaded) + updateStatus(); + } + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(5), + Children = new Drawable[] + { + text = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 12), + Colour = Color4Extensions.FromHex("#DDFFFF") + }, + icon = new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Icon = FontAwesome.Solid.CheckCircle, + Size = new Vector2(12), + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + updateStatus(); + } + + [Resolved] + private OsuColour colours { get; set; } + + private void updateStatus() + { + switch (status) + { + default: + this.FadeOut(fade_time); + return; + + case MultiplayerUserState.Ready: + text.Text = "ready"; + icon.Icon = FontAwesome.Solid.CheckCircle; + icon.Colour = Color4Extensions.FromHex("#AADD00"); + break; + + case MultiplayerUserState.WaitingForLoad: + text.Text = "loading"; + icon.Icon = FontAwesome.Solid.PauseCircle; + icon.Colour = colours.Yellow; + break; + + case MultiplayerUserState.Loaded: + text.Text = "loaded"; + icon.Icon = FontAwesome.Solid.DotCircle; + icon.Colour = colours.YellowLight; + break; + + case MultiplayerUserState.Playing: + text.Text = "playing"; + icon.Icon = FontAwesome.Solid.PlayCircle; + icon.Colour = colours.BlueLight; + break; + + case MultiplayerUserState.FinishedPlay: + text.Text = "results pending"; + icon.Icon = FontAwesome.Solid.ArrowAltCircleUp; + icon.Colour = colours.BlueLighter; + break; + + case MultiplayerUserState.Results: + text.Text = "results"; + icon.Icon = FontAwesome.Solid.ArrowAltCircleUp; + icon.Colour = colours.BlueLighter; + break; + } + + this.FadeIn(fade_time); + } + } +} From 23bf9c372c71d15049595955c22bda7df3939dfd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 18:26:39 +0900 Subject: [PATCH 227/328] Fix naming conflict with test scenes --- ...articipantsList.cs => TestSceneTimeshiftParticipantsList.cs} | 2 +- ...sList.cs => TestSceneRealtimeMultiplayerParticipantsList.cs} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename osu.Game.Tests/Visual/Multiplayer/{TestSceneParticipantsList.cs => TestSceneTimeshiftParticipantsList.cs} (95%) rename osu.Game.Tests/Visual/RealtimeMultiplayer/{TestSceneParticipantsList.cs => TestSceneRealtimeMultiplayerParticipantsList.cs} (97%) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftParticipantsList.cs similarity index 95% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftParticipantsList.cs index 360aa22af9..efc3be032c 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftParticipantsList.cs @@ -8,7 +8,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneParticipantsList : MultiplayerTestScene + public class TestSceneTimeshiftParticipantsList : MultiplayerTestScene { [SetUp] public new void Setup() => Schedule(() => diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs similarity index 97% rename from osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs rename to osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs index 35ea0d3813..7fd31906f7 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneParticipantsList.cs +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Tests.Visual.RealtimeMultiplayer { - public class TestSceneParticipantsList : RealtimeMultiplayerTestScene + public class TestSceneRealtimeMultiplayerParticipantsList : RealtimeMultiplayerTestScene { [SetUp] public new void Setup() => Schedule(() => From 6517acc510885301d7bc0c3cf82d7638f7fc63cf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Dec 2020 19:09:59 +0900 Subject: [PATCH 228/328] Add leaderboard display to realtime player --- .../RealtimeMultiplayer/RealtimePlayer.cs | 23 +++++++++++++++++++ osu.Game/Screens/Play/HUDOverlay.cs | 7 +++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index c6d44686b5..453e7e6140 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using System.Linq; using System.Threading; using System.Threading.Tasks; using osu.Framework.Allocation; @@ -12,7 +13,9 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Scoring; using osu.Game.Screens.Multi.Play; +using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Ranking; +using osuTK; namespace osu.Game.Screens.Multi.RealtimeMultiplayer { @@ -30,6 +33,8 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer private readonly TaskCompletionSource resultsReady = new TaskCompletionSource(); private readonly ManualResetEventSlim startedEvent = new ManualResetEventSlim(); + private MultiplayerGameplayLeaderboard leaderboard; + public RealtimePlayer(PlaylistItem playlistItem) : base(playlistItem, false) { @@ -55,6 +60,24 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer this.Exit(); }); } + + Debug.Assert(client.Room != null); + + int[] userIds = client.Room.Users.Where(u => u.State >= MultiplayerUserState.WaitingForLoad).Select(u => u.UserID).ToArray(); + + // todo: this should be implemented via a custom HUD implementation, and correctly masked to the main content area. + LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(ScoreProcessor, userIds), HUDOverlay.Add); + } + + protected override void Update() + { + base.Update(); + + const float padding = 44; // enough margin to avoid the hit error display. + + leaderboard.Position = new Vector2( + padding, + padding + HUDOverlay.TopScoringElementsHeight); } private void onMatchStarted() => startedEvent.Set(); diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 50195d571c..3dffab8102 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -28,6 +28,11 @@ namespace osu.Game.Screens.Play public const Easing FADE_EASING = Easing.Out; + /// + /// The total height of all the top of screen scoring elements. + /// + public float TopScoringElementsHeight { get; private set; } + public readonly KeyCounterDisplay KeyCounter; public readonly SkinnableComboCounter ComboCounter; public readonly SkinnableScoreCounter ScoreCounter; @@ -209,7 +214,7 @@ namespace osu.Game.Screens.Play // HACK: for now align with the accuracy counter. // this is done for the sake of hacky legacy skins which extend the health bar to take up the full screen area. // it only works with the default skin due to padding offsetting it *just enough* to coexist. - topRightElements.Y = ToLocalSpace(AccuracyCounter.Drawable.ScreenSpaceDrawQuad.BottomRight).Y; + topRightElements.Y = TopScoringElementsHeight = ToLocalSpace(AccuracyCounter.Drawable.ScreenSpaceDrawQuad.BottomRight).Y; bottomRightElements.Y = -Progress.Height; } From e3483147e2f682000121bd1534f494efbd42e6c8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 22 Dec 2020 13:53:01 +0300 Subject: [PATCH 229/328] Move track looping logic into subscreens --- osu.Game/Screens/Multi/Match/RoomSubScreen.cs | 52 ++++++++++++++++++ osu.Game/Screens/Multi/Multiplayer.cs | 53 ------------------- 2 files changed, 52 insertions(+), 53 deletions(-) diff --git a/osu.Game/Screens/Multi/Match/RoomSubScreen.cs b/osu.Game/Screens/Multi/Match/RoomSubScreen.cs index 0cc9a4354e..21316a98ce 100644 --- a/osu.Game/Screens/Multi/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/Multi/Match/RoomSubScreen.cs @@ -9,6 +9,7 @@ using osu.Framework.Screens; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; +using osu.Game.Overlays; using osu.Game.Rulesets.Mods; namespace osu.Game.Screens.Multi.Match @@ -23,6 +24,9 @@ namespace osu.Game.Screens.Multi.Match [Resolved(typeof(Room), nameof(Room.Playlist))] protected BindableList Playlist { get; private set; } + [Resolved] + private MusicController music { get; set; } + [Resolved] private BeatmapManager beatmapManager { get; set; } @@ -61,6 +65,30 @@ namespace osu.Game.Screens.Multi.Match var localBeatmap = beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineBeatmapID); Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); + if (this.IsCurrentScreen()) + applyTrackLooping(); + } + + public override void OnEntering(IScreen last) + { + base.OnEntering(last); + + music?.EnsurePlayingSomething(); + applyTrackLooping(); + } + + public override void OnSuspending(IScreen next) + { + cancelTrackLooping(); + base.OnSuspending(next); + } + + public override void OnResuming(IScreen last) + { + base.OnResuming(last); + + music?.EnsurePlayingSomething(); + applyTrackLooping(); } public override bool OnExiting(IScreen next) @@ -68,7 +96,31 @@ namespace osu.Game.Screens.Multi.Match RoomManager?.PartRoom(); Mods.Value = Array.Empty(); + cancelTrackLooping(); + return base.OnExiting(next); } + + private void applyTrackLooping() + { + var track = Beatmap.Value?.Track; + + if (track != null) + { + track.RestartPoint = Beatmap.Value.Metadata.PreviewTime; + track.Looping = true; + } + } + + private void cancelTrackLooping() + { + var track = Beatmap?.Value?.Track; + + if (track != null) + { + track.Looping = false; + track.RestartPoint = 0; + } + } } } diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index eae779421d..de2e0d58c9 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Screens; -using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -198,8 +197,6 @@ namespace osu.Game.Screens.Multi { this.FadeIn(); waves.Show(); - - beginHandlingTrack(); } public override void OnResuming(IScreen last) @@ -209,8 +206,6 @@ namespace osu.Game.Screens.Multi base.OnResuming(last); - beginHandlingTrack(); - UpdatePollingRate(isIdle.Value); } @@ -219,8 +214,6 @@ namespace osu.Game.Screens.Multi this.ScaleTo(1.1f, 250, Easing.InSine); this.FadeOut(250); - endHandlingTrack(); - UpdatePollingRate(isIdle.Value); } @@ -235,8 +228,6 @@ namespace osu.Game.Screens.Multi if (screenStack.CurrentScreen != null) loungeSubScreen.MakeCurrent(); - endHandlingTrack(); - base.OnExiting(next); return false; } @@ -275,17 +266,6 @@ namespace osu.Game.Screens.Multi /// The created . protected virtual Room CreateNewRoom() => new Room { Name = { Value = $"{api.LocalUser}'s awesome room" } }; - private void beginHandlingTrack() - { - Beatmap.BindValueChanged(updateTrack, true); - } - - private void endHandlingTrack() - { - cancelLooping(); - Beatmap.ValueChanged -= updateTrack; - } - private void screenPushed(IScreen lastScreen, IScreen newScreen) { subScreenChanged(lastScreen, newScreen); @@ -322,43 +302,10 @@ namespace osu.Game.Screens.Multi UpdatePollingRate(isIdle.Value); createButton.FadeTo(newScreen is LoungeSubScreen ? 1 : 0, 200); - - updateTrack(); } protected IScreen CurrentSubScreen => screenStack.CurrentScreen; - private void updateTrack(ValueChangedEvent _ = null) - { - if (screenStack.CurrentScreen is RoomSubScreen) - { - var track = Beatmap.Value?.Track; - - if (track != null) - { - track.RestartPoint = Beatmap.Value.Metadata.PreviewTime; - track.Looping = true; - - music?.EnsurePlayingSomething(); - } - } - else - { - cancelLooping(); - } - } - - private void cancelLooping() - { - var track = Beatmap?.Value?.Track; - - if (track != null) - { - track.Looping = false; - track.RestartPoint = 0; - } - } - protected abstract RoomManager CreateRoomManager(); protected abstract LoungeSubScreen CreateLounge(); From 91d5c53643a7489066a23b36e6865d67c621ddf2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 22 Dec 2020 16:36:17 +0300 Subject: [PATCH 230/328] Add method for checking room joinability --- osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs | 2 ++ .../Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs | 2 ++ .../Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs | 2 ++ osu.Game/Screens/Multi/Components/RoomManager.cs | 2 ++ osu.Game/Screens/Multi/IRoomManager.cs | 6 ++++++ .../Multi/RealtimeMultiplayer/RealtimeRoomManager.cs | 3 +++ 6 files changed, 17 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs b/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs index 9dd4aea4bd..ea8fb4ef49 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs @@ -24,6 +24,8 @@ namespace osu.Game.Tests.Visual.Multiplayer public void CreateRoom(Room room, Action onSuccess = null, Action onError = null) => Rooms.Add(room); + public bool CanJoinRoom(Room room) => true; + public void JoinRoom(Room room, Action onSuccess = null, Action onError = null) { } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs index 1fcae9c709..55dbd1a7c6 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs @@ -146,6 +146,8 @@ namespace osu.Game.Tests.Visual.Multiplayer onSuccess?.Invoke(room); } + public bool CanJoinRoom(Room room) => true; + public void JoinRoom(Room room, Action onSuccess = null, Action onError = null) => throw new NotImplementedException(); public void PartRoom() => throw new NotImplementedException(); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs index bbd7d84081..8fdb5d4093 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs @@ -161,6 +161,8 @@ namespace osu.Game.Tests.Visual.Multiplayer onSuccess?.Invoke(room); } + public bool CanJoinRoom(Room room) => true; + public void JoinRoom(Room room, Action onSuccess = null, Action onError = null) => onSuccess?.Invoke(room); public void PartRoom() diff --git a/osu.Game/Screens/Multi/Components/RoomManager.cs b/osu.Game/Screens/Multi/Components/RoomManager.cs index f78d0d979e..3fcfe1df25 100644 --- a/osu.Game/Screens/Multi/Components/RoomManager.cs +++ b/osu.Game/Screens/Multi/Components/RoomManager.cs @@ -82,6 +82,8 @@ namespace osu.Game.Screens.Multi.Components api.Queue(req); } + public virtual bool CanJoinRoom(Room room) => true; + private JoinRoomRequest currentJoinRoomRequest; public virtual void JoinRoom(Room room, Action onSuccess = null, Action onError = null) diff --git a/osu.Game/Screens/Multi/IRoomManager.cs b/osu.Game/Screens/Multi/IRoomManager.cs index 630e3af91c..a1cff129a9 100644 --- a/osu.Game/Screens/Multi/IRoomManager.cs +++ b/osu.Game/Screens/Multi/IRoomManager.cs @@ -34,6 +34,12 @@ namespace osu.Game.Screens.Multi /// An action to be invoked if an error occurred. void CreateRoom(Room room, Action onSuccess = null, Action onError = null); + /// + /// Whether the provided can be joined. + /// + /// The to check for. + bool CanJoinRoom(Room room); + /// /// Joins a . /// diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index 7ce031e0e9..d8dc5f127a 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -9,6 +9,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.RoomStatuses; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Screens.Multi.Components; @@ -40,6 +41,8 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer public override void CreateRoom(Room room, Action onSuccess = null, Action onError = null) => base.CreateRoom(room, r => joinMultiplayerRoom(r, onSuccess, onError), onError); + public override bool CanJoinRoom(Room room) => !(room.Status.Value is RoomStatusEnded); + public override void JoinRoom(Room room, Action onSuccess = null, Action onError = null) => base.JoinRoom(room, r => joinMultiplayerRoom(r, onSuccess, onError), onError); From a64ffcd2949ca3f47c0bc3019de9596dc28e79d5 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 22 Dec 2020 16:38:10 +0300 Subject: [PATCH 231/328] Refrain from joining room if not allowed --- osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs index c7c37cbc0d..c1f69b779c 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs @@ -115,7 +115,9 @@ namespace osu.Game.Screens.Multi.Lounge.Components { if (room == selectedRoom.Value) { - joinSelected(); + if (roomManager.CanJoinRoom(room)) + joinSelected(); + return; } From 5efc3b94961cf918fa96b54818382e89b2cd9faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Dec 2020 21:12:28 +0100 Subject: [PATCH 232/328] Start state display as hidden Would otherwise flicker for a few frames when a new user was added to the list of participants. --- .../Multi/RealtimeMultiplayer/Participants/StateDisplay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/StateDisplay.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/StateDisplay.cs index db93525217..844f239363 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/StateDisplay.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/StateDisplay.cs @@ -18,6 +18,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants public StateDisplay() { AutoSizeAxes = Axes.Both; + Alpha = 0; } private MultiplayerUserState status; From 4a677ecc190f0ec7b354db5f2436349353cd9f2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Dec 2020 21:16:45 +0100 Subject: [PATCH 233/328] Make random state choice in test more robust `RNG.Next(int, int)` is max-exclusive, so the random state choice would actually never pick `MultiplayerUserState.Results` on its own. The only reason why that state ever did show up was by a freak accident of sorts (the logic in `TestRealtimeMultiplayerClient` would automatically convert every `FinishedPlay` state to `Results`, up until seeing the first player that was in the `Playing` state). --- .../TestSceneRealtimeMultiplayerParticipantsList.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs index 7fd31906f7..4221821496 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs @@ -109,7 +109,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", }); - Client.ChangeUserState(i, (MultiplayerUserState)RNG.Next(0, (int)MultiplayerUserState.Results)); + Client.ChangeUserState(i, (MultiplayerUserState)RNG.Next(0, (int)MultiplayerUserState.Results + 1)); } }); } From 32728047044a426d2c076cc143d836412d53b7a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Dec 2020 22:31:40 +0100 Subject: [PATCH 234/328] Fix potential crash when no submission token Can happen because `TimeshiftPlayer` will schedule a screen exit on token retrieval failure, and `RealtimePlayer`'s BDL won't even attempt to create a leaderboard in that case. --- .../Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index 453e7e6140..7824b414f2 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Logging; using osu.Framework.Screens; @@ -33,6 +34,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer private readonly TaskCompletionSource resultsReady = new TaskCompletionSource(); private readonly ManualResetEventSlim startedEvent = new ManualResetEventSlim(); + [CanBeNull] private MultiplayerGameplayLeaderboard leaderboard; public RealtimePlayer(PlaylistItem playlistItem) @@ -72,6 +74,13 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer protected override void Update() { base.Update(); + adjustLeaderboardPosition(); + } + + private void adjustLeaderboardPosition() + { + if (leaderboard == null) + return; const float padding = 44; // enough margin to avoid the hit error display. From 7751ef4f3eadf4fa4583e3815bc6f3a95c5c354b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 23 Dec 2020 05:49:18 +0300 Subject: [PATCH 235/328] Revert previous logic of join guarding --- osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs | 2 -- .../Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs | 2 -- .../Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs | 2 -- osu.Game/Screens/Multi/Components/RoomManager.cs | 2 -- osu.Game/Screens/Multi/IRoomManager.cs | 6 ------ osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs | 4 +--- .../Multi/RealtimeMultiplayer/RealtimeRoomManager.cs | 3 --- 7 files changed, 1 insertion(+), 20 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs b/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs index ea8fb4ef49..9dd4aea4bd 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs @@ -24,8 +24,6 @@ namespace osu.Game.Tests.Visual.Multiplayer public void CreateRoom(Room room, Action onSuccess = null, Action onError = null) => Rooms.Add(room); - public bool CanJoinRoom(Room room) => true; - public void JoinRoom(Room room, Action onSuccess = null, Action onError = null) { } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs index 55dbd1a7c6..1fcae9c709 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs @@ -146,8 +146,6 @@ namespace osu.Game.Tests.Visual.Multiplayer onSuccess?.Invoke(room); } - public bool CanJoinRoom(Room room) => true; - public void JoinRoom(Room room, Action onSuccess = null, Action onError = null) => throw new NotImplementedException(); public void PartRoom() => throw new NotImplementedException(); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs index 8fdb5d4093..bbd7d84081 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs @@ -161,8 +161,6 @@ namespace osu.Game.Tests.Visual.Multiplayer onSuccess?.Invoke(room); } - public bool CanJoinRoom(Room room) => true; - public void JoinRoom(Room room, Action onSuccess = null, Action onError = null) => onSuccess?.Invoke(room); public void PartRoom() diff --git a/osu.Game/Screens/Multi/Components/RoomManager.cs b/osu.Game/Screens/Multi/Components/RoomManager.cs index 3fcfe1df25..f78d0d979e 100644 --- a/osu.Game/Screens/Multi/Components/RoomManager.cs +++ b/osu.Game/Screens/Multi/Components/RoomManager.cs @@ -82,8 +82,6 @@ namespace osu.Game.Screens.Multi.Components api.Queue(req); } - public virtual bool CanJoinRoom(Room room) => true; - private JoinRoomRequest currentJoinRoomRequest; public virtual void JoinRoom(Room room, Action onSuccess = null, Action onError = null) diff --git a/osu.Game/Screens/Multi/IRoomManager.cs b/osu.Game/Screens/Multi/IRoomManager.cs index a1cff129a9..630e3af91c 100644 --- a/osu.Game/Screens/Multi/IRoomManager.cs +++ b/osu.Game/Screens/Multi/IRoomManager.cs @@ -34,12 +34,6 @@ namespace osu.Game.Screens.Multi /// An action to be invoked if an error occurred. void CreateRoom(Room room, Action onSuccess = null, Action onError = null); - /// - /// Whether the provided can be joined. - /// - /// The to check for. - bool CanJoinRoom(Room room); - /// /// Joins a . /// diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs index c1f69b779c..c7c37cbc0d 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs @@ -115,9 +115,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components { if (room == selectedRoom.Value) { - if (roomManager.CanJoinRoom(room)) - joinSelected(); - + joinSelected(); return; } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index d8dc5f127a..7ce031e0e9 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -9,7 +9,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.RoomStatuses; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Screens.Multi.Components; @@ -41,8 +40,6 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer public override void CreateRoom(Room room, Action onSuccess = null, Action onError = null) => base.CreateRoom(room, r => joinMultiplayerRoom(r, onSuccess, onError), onError); - public override bool CanJoinRoom(Room room) => !(room.Status.Value is RoomStatusEnded); - public override void JoinRoom(Room room, Action onSuccess = null, Action onError = null) => base.JoinRoom(room, r => joinMultiplayerRoom(r, onSuccess, onError), onError); From 3aa2b228380ccc8a2ce3e9043c5dcd43a80a6b97 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 23 Dec 2020 05:52:10 +0300 Subject: [PATCH 236/328] Add early check for room status before joining --- .../Multi/RealtimeMultiplayer/RealtimeRoomManager.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index 7ce031e0e9..484d5cce0b 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -9,6 +9,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.RoomStatuses; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Screens.Multi.Components; @@ -41,7 +42,15 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer => base.CreateRoom(room, r => joinMultiplayerRoom(r, onSuccess, onError), onError); public override void JoinRoom(Room room, Action onSuccess = null, Action onError = null) - => base.JoinRoom(room, r => joinMultiplayerRoom(r, onSuccess, onError), onError); + { + if (room.Status.Value is RoomStatusEnded) + { + onError?.Invoke("Cannot join an ended room."); + return; + } + + base.JoinRoom(room, r => joinMultiplayerRoom(r, onSuccess, onError), onError); + } public override void PartRoom() { From 45dcd3242db7cc84753577d4de75ba571e75deb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 13:57:48 +0900 Subject: [PATCH 237/328] Add comment explaining why things are done where they are --- .../Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index 484d5cce0b..f982574eb3 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -43,6 +43,8 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer public override void JoinRoom(Room room, Action onSuccess = null, Action onError = null) { + // this is done here as a pre-check to avoid clicking on already closed rooms in the lounge from triggering a server join. + // should probably be done at a higher level, but due to the current structure of things this is the easiest place for now. if (room.Status.Value is RoomStatusEnded) { onError?.Invoke("Cannot join an ended room."); From be427a4ec0fd7f30189f3b37941844483ad95d62 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 14:20:35 +0900 Subject: [PATCH 238/328] Fix realtime leaderboard showing accuracy based on final base score, not rolling --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 23 ++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 10d0cc2865..4b2e2bf715 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -233,7 +233,7 @@ namespace osu.Game.Rulesets.Scoring } /// - /// Given a minimal set of inputs, return the computed score and accuracy for the tracked beatmap / mods combination. + /// Given a minimal set of inputs, return the computed score and accuracy for the tracked beatmap / mods combination, at the current point in time. /// /// The to compute the total score in. /// The maximum combo achievable in the beatmap. @@ -252,15 +252,28 @@ namespace osu.Game.Rulesets.Scoring computedBaseScore += Judgement.ToNumericResult(pair.Key) * pair.Value; } - double accuracy = calculateAccuracyRatio(computedBaseScore); + double pointInTimeAccuracy = calculateAccuracyRatio(computedBaseScore, true); double comboRatio = calculateComboRatio(maxCombo); - double score = GetScore(mode, maxAchievableCombo, accuracy, comboRatio, scoreResultCounts); + double score = GetScore(mode, maxAchievableCombo, calculateAccuracyRatio(computedBaseScore), comboRatio, scoreResultCounts); - return (score, accuracy); + return (score, pointInTimeAccuracy); + } + + /// + /// Get the accuracy fraction for the provided base score. + /// + /// The score to be used for accuracy calculation. + /// Whether the rolling base score should be used (ie. for the current point in time based on Apply/Reverted results). + /// The computed accuracy. + private double calculateAccuracyRatio(double baseScore, bool preferRolling = false) + { + if (preferRolling && rollingMaxBaseScore != 0) + return baseScore / rollingMaxBaseScore; + + return maxBaseScore > 0 ? baseScore / maxBaseScore : 0; } - private double calculateAccuracyRatio(double baseScore) => maxBaseScore > 0 ? baseScore / maxBaseScore : 0; private double calculateComboRatio(int maxCombo) => maxAchievableCombo > 0 ? (double)maxCombo / maxAchievableCombo : 1; private double getBonusScore(Dictionary statistics) From dec997c0f49687800b9c90641299d38b4c9e060d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 14:44:20 +0900 Subject: [PATCH 239/328] Fix flashlight not updating its position during replay rewinding Closes #11260 --- osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index ac20407ed2..3f770cfb5e 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Mods var destination = e.MousePosition; FlashlightPosition = Interpolation.ValueAt( - Math.Clamp(Clock.ElapsedFrameTime, 0, follow_delay), position, destination, 0, follow_delay, Easing.Out); + Math.Clamp(Math.Abs(Clock.ElapsedFrameTime), 0, follow_delay), position, destination, 0, follow_delay, Easing.Out); return base.OnMouseMove(e); } From 286884421d74d8cd565533bdd723448b88416dc3 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 23 Dec 2020 08:47:34 +0300 Subject: [PATCH 240/328] Apply track looping and play on track change --- osu.Game/Screens/Multi/Match/RoomSubScreen.cs | 72 ++++++++++--------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/osu.Game/Screens/Multi/Match/RoomSubScreen.cs b/osu.Game/Screens/Multi/Match/RoomSubScreen.cs index 21316a98ce..4f5d2a5b3e 100644 --- a/osu.Game/Screens/Multi/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/Multi/Match/RoomSubScreen.cs @@ -41,6 +41,37 @@ namespace osu.Game.Screens.Multi.Match managerUpdated = beatmapManager.ItemUpdated.GetBoundCopy(); managerUpdated.BindValueChanged(beatmapUpdated); + + if (music != null) + music.TrackChanged += applyToTrack; + } + + public override void OnEntering(IScreen last) + { + base.OnEntering(last); + applyToTrack(); + } + + public override void OnSuspending(IScreen next) + { + resetTrack(); + base.OnSuspending(next); + } + + public override void OnResuming(IScreen last) + { + base.OnResuming(last); + applyToTrack(); + } + + public override bool OnExiting(IScreen next) + { + RoomManager?.PartRoom(); + Mods.Value = Array.Empty(); + + resetTrack(); + + return base.OnExiting(next); } private void selectedItemChanged() @@ -65,54 +96,25 @@ namespace osu.Game.Screens.Multi.Match var localBeatmap = beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineBeatmapID); Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); - if (this.IsCurrentScreen()) - applyTrackLooping(); } - public override void OnEntering(IScreen last) + private void applyToTrack(WorkingBeatmap _ = default, TrackChangeDirection __ = default) { - base.OnEntering(last); + if (!this.IsCurrentScreen()) + return; - music?.EnsurePlayingSomething(); - applyTrackLooping(); - } - - public override void OnSuspending(IScreen next) - { - cancelTrackLooping(); - base.OnSuspending(next); - } - - public override void OnResuming(IScreen last) - { - base.OnResuming(last); - - music?.EnsurePlayingSomething(); - applyTrackLooping(); - } - - public override bool OnExiting(IScreen next) - { - RoomManager?.PartRoom(); - Mods.Value = Array.Empty(); - - cancelTrackLooping(); - - return base.OnExiting(next); - } - - private void applyTrackLooping() - { var track = Beatmap.Value?.Track; if (track != null) { track.RestartPoint = Beatmap.Value.Metadata.PreviewTime; track.Looping = true; + + music?.EnsurePlayingSomething(); } } - private void cancelTrackLooping() + private void resetTrack() { var track = Beatmap?.Value?.Track; From 00d50150de6e39cbdff44e7f5a98c41a3c57b6a6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 15:49:22 +0900 Subject: [PATCH 241/328] Ensure the current room is left at a mutliplayer client level on client disconnection --- .../RealtimeMultiplayer/RealtimeMultiplayerClient.cs | 4 ++++ .../RealtimeMultiplayer/StatefulMultiplayerClient.cs | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs index 75bb578a29..5cbf3be8ca 100644 --- a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs @@ -130,7 +130,11 @@ namespace osu.Game.Online.RealtimeMultiplayer public override async Task LeaveRoom() { if (!isConnected.Value) + { + // even if not connected, make sure the local room state can be cleaned up. + await base.LeaveRoom(); return; + } if (Room == null) return; diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index 4ebd648689..9680387fcc 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -75,6 +75,16 @@ namespace osu.Game.Online.RealtimeMultiplayer // Todo: This is temporary, until the multiplayer server returns the item id on match start or otherwise. private int playlistItemId; + protected StatefulMultiplayerClient() + { + IsConnected.BindValueChanged(connected => + { + // clean up local room state on server disconnect. + if (!connected.NewValue) + LeaveRoom(); + }); + } + /// /// Joins the for a given API . /// From 12df3056e6d27d2da5d29a172708e849162eaa3c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 15:58:50 +0900 Subject: [PATCH 242/328] Ensure appropriate screens handle exiting when the server gets disconnected I would have liked for this to be handled via the `OnRoomChanged` event flow, but this isn't present in RealtimeMatchSubScreen due to inheritence woes. --- .../RealtimeMultiplayer/RealtimeMatchSubScreen.cs | 14 ++++++++++++++ .../Multi/RealtimeMultiplayer/RealtimePlayer.cs | 12 ++++++++++++ 2 files changed, 26 insertions(+) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs index cdab1435c0..8405fc196b 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs @@ -4,8 +4,10 @@ using System.Collections.Specialized; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; @@ -34,6 +36,8 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer private RealtimeMatchSettingsOverlay settingsOverlay; + private IBindable isConnected; + public RealtimeMatchSubScreen(Room room) { Title = room.RoomID.Value == null ? "New match" : room.Name.Value; @@ -173,6 +177,16 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer Playlist.BindCollectionChanged(onPlaylistChanged, true); client.LoadRequested += onLoadRequested; + + isConnected = client.IsConnected.GetBoundCopy(); + isConnected.BindValueChanged(connected => + { + if (!connected.NewValue) + { + Logger.Log("Connection to multiplayer server was lost.", LoggingTarget.Runtime, LogLevel.Important); + Schedule(this.Exit); + } + }, true); } public override bool OnBackButton() diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index c6d44686b5..d74ccdd32f 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Online.Multiplayer; @@ -30,6 +31,8 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer private readonly TaskCompletionSource resultsReady = new TaskCompletionSource(); private readonly ManualResetEventSlim startedEvent = new ManualResetEventSlim(); + private IBindable isConnected; + public RealtimePlayer(PlaylistItem playlistItem) : base(playlistItem, false) { @@ -43,6 +46,15 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer client.MatchStarted += onMatchStarted; client.ResultsReady += onResultsReady; + + isConnected = client.IsConnected.GetBoundCopy(); + isConnected.BindValueChanged(connected => + { + if (!connected.NewValue) + // messaging to the user about this disconnect will be provided by the RealtimeMatchSubScreen. + Schedule(this.Exit); + }, true); + client.ChangeState(MultiplayerUserState.Loaded); if (!startedEvent.Wait(TimeSpan.FromSeconds(30))) From a1d42dc4a061a8fb2f50064c485cbd3cf07186be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 16:17:55 +0900 Subject: [PATCH 243/328] Don't allow creating or joining a room when not connected to server --- .../Screens/Multi/Lounge/LoungeSubScreen.cs | 2 +- .../RealtimeLoungeSubScreen.cs | 17 +++++++++++++++++ .../RealtimeMultiplayer/RealtimeRoomManager.cs | 6 ++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs index 44c893363b..6b08745dd7 100644 --- a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs @@ -184,7 +184,7 @@ namespace osu.Game.Screens.Multi.Lounge /// /// Push a room as a new subscreen. /// - public void Open(Room room) + public virtual void Open(Room room) { // Handles the case where a room is clicked 3 times in quick succession if (!this.IsCurrentScreen()) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs index 9fbf0c4654..b53ec94519 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs @@ -1,7 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; +using osu.Framework.Logging; using osu.Game.Online.Multiplayer; +using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Lounge.Components; using osu.Game.Screens.Multi.Match; @@ -13,5 +16,19 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer protected override FilterControl CreateFilterControl() => new RealtimeFilterControl(); protected override RoomSubScreen CreateRoomSubScreen(Room room) => new RealtimeMatchSubScreen(room); + + [Resolved] + private StatefulMultiplayerClient client { get; set; } + + public override void Open(Room room) + { + if (!client.IsConnected.Value) + { + Logger.Log("Not currently connected to the multiplayer server.", LoggingTarget.Runtime, LogLevel.Important); + return; + } + + base.Open(room); + } } } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index f982574eb3..2f60f504de 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -43,6 +43,12 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer public override void JoinRoom(Room room, Action onSuccess = null, Action onError = null) { + if (!multiplayerClient.IsConnected.Value) + { + onError?.Invoke("Not currently connected to the multiplayer server."); + return; + } + // this is done here as a pre-check to avoid clicking on already closed rooms in the lounge from triggering a server join. // should probably be done at a higher level, but due to the current structure of things this is the easiest place for now. if (room.Status.Value is RoomStatusEnded) From 569c4092efe42a55caabc5a08c7f7bc227f3b1e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 16:19:03 +0900 Subject: [PATCH 244/328] Move notification to stateful client so it is only shown to the user from one location --- .../RealtimeMultiplayer/StatefulMultiplayerClient.cs | 4 ++++ .../Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs | 7 ++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index 9680387fcc..79d82a8d02 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -11,6 +11,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; +using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Online.API; @@ -81,7 +82,10 @@ namespace osu.Game.Online.RealtimeMultiplayer { // clean up local room state on server disconnect. if (!connected.NewValue) + { + Logger.Log("Connection to multiplayer server was lost.", LoggingTarget.Runtime, LogLevel.Important); LeaveRoom(); + } }); } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs index 8405fc196b..807ea74404 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs @@ -7,7 +7,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; @@ -18,6 +17,7 @@ using osu.Game.Screens.Multi.RealtimeMultiplayer.Match; using osu.Game.Screens.Multi.RealtimeMultiplayer.Participants; using osu.Game.Screens.Play; using osu.Game.Users; +using ParticipantsList = osu.Game.Screens.Multi.RealtimeMultiplayer.Participants.ParticipantsList; namespace osu.Game.Screens.Multi.RealtimeMultiplayer { @@ -106,7 +106,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer new Drawable[] { new ParticipantsListHeader() }, new Drawable[] { - new Participants.ParticipantsList + new ParticipantsList { RelativeSizeAxes = Axes.Both }, @@ -182,10 +182,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer isConnected.BindValueChanged(connected => { if (!connected.NewValue) - { - Logger.Log("Connection to multiplayer server was lost.", LoggingTarget.Runtime, LogLevel.Important); Schedule(this.Exit); - } }, true); } From f5d27b40a8f5c9dd8b3e849360425ed540b79c39 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 16:32:58 +0900 Subject: [PATCH 245/328] Standardise flow for aborting realtime player exit to avoid double-exit call --- .../Multi/RealtimeMultiplayer/RealtimePlayer.cs | 12 ++++++------ osu.Game/Screens/Play/Player.cs | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index d74ccdd32f..edec40890e 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -51,8 +51,12 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer isConnected.BindValueChanged(connected => { if (!connected.NewValue) + { + startedEvent.Set(); + // messaging to the user about this disconnect will be provided by the RealtimeMatchSubScreen. - Schedule(this.Exit); + Schedule(PerformImmediateExit); + } }, true); client.ChangeState(MultiplayerUserState.Loaded); @@ -61,11 +65,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer { Logger.Log("Failed to start the multiplayer match in time.", LoggingTarget.Runtime, LogLevel.Important); - Schedule(() => - { - ValidForResume = false; - this.Exit(); - }); + Schedule(PerformImmediateExit); } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index c539dff5d9..c6265c48d2 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -386,7 +386,7 @@ namespace osu.Game.Screens.Play if (!this.IsCurrentScreen()) return; fadeOut(true); - performImmediateExit(); + PerformImmediateExit(); }, }, failAnimation = new FailAnimation(DrawableRuleset) { OnComplete = onFailComplete, }, @@ -458,7 +458,7 @@ namespace osu.Game.Screens.Play return playable; } - private void performImmediateExit() + protected void PerformImmediateExit() { // if a restart has been requested, cancel any pending completion (user has shown intent to restart). completionProgressDelegate?.Cancel(); @@ -498,7 +498,7 @@ namespace osu.Game.Screens.Play RestartRequested?.Invoke(); if (this.IsCurrentScreen()) - performImmediateExit(); + PerformImmediateExit(); else this.MakeCurrent(); } From 91021eb8c45b0826bf0503cc9d5d4fac822fe005 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 16:49:17 +0900 Subject: [PATCH 246/328] Remove unused using --- osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index edec40890e..9e2ba9b04a 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Logging; -using osu.Framework.Screens; using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Scoring; From d27b83d678bb4c9f0525b685880a5e9dd136ee90 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 16:51:11 +0900 Subject: [PATCH 247/328] More correctly handle fire-and-forget async call --- .../RealtimeMultiplayer/RealtimePlayer.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index 9e2ba9b04a..0f8c0f247c 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -51,21 +51,25 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer { if (!connected.NewValue) { - startedEvent.Set(); - // messaging to the user about this disconnect will be provided by the RealtimeMatchSubScreen. - Schedule(PerformImmediateExit); + failAndBail(); } }, true); - client.ChangeState(MultiplayerUserState.Loaded); + client.ChangeState(MultiplayerUserState.Loaded).ContinueWith(task => + failAndBail(task.Exception?.Message ?? "Server error"), TaskContinuationOptions.NotOnRanToCompletion); if (!startedEvent.Wait(TimeSpan.FromSeconds(30))) - { - Logger.Log("Failed to start the multiplayer match in time.", LoggingTarget.Runtime, LogLevel.Important); + failAndBail("Failed to start the multiplayer match in time."); + } - Schedule(PerformImmediateExit); - } + private void failAndBail(string message = null) + { + if (!string.IsNullOrEmpty(message)) + Logger.Log(message, LoggingTarget.Runtime, LogLevel.Important); + + startedEvent.Set(); + Schedule(PerformImmediateExit); } private void onMatchStarted() => startedEvent.Set(); From c3c3364d399b915f9d0d3044dc3cd045830bd3dd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 16:56:51 +0900 Subject: [PATCH 248/328] Simplify error handling of JoinRoom call --- .../RealtimeRoomManager.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index 2f60f504de..8bdf2bdc1a 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -83,15 +83,19 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer { Debug.Assert(room.RoomID.Value != null); - var joinTask = multiplayerClient.JoinRoom(room); - joinTask.ContinueWith(_ => Schedule(() => onSuccess?.Invoke(room)), TaskContinuationOptions.OnlyOnRanToCompletion); - joinTask.ContinueWith(t => + multiplayerClient.JoinRoom(room).ContinueWith(t => { - PartRoom(); - if (t.Exception != null) - Logger.Error(t.Exception, "Failed to join multiplayer room."); - Schedule(() => onError?.Invoke(t.Exception?.ToString() ?? string.Empty)); - }, TaskContinuationOptions.NotOnRanToCompletion); + if (t.IsCompletedSuccessfully) + Schedule(() => onSuccess?.Invoke(room)); + else + { + if (t.Exception != null) + Logger.Error(t.Exception, "Failed to join multiplayer room."); + + PartRoom(); + Schedule(() => onError?.Invoke(t.Exception?.ToString() ?? string.Empty)); + } + }); } private void updatePolling() From 1864da00e69806eefb389fd0a5742c0477eb419d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 17:10:02 +0900 Subject: [PATCH 249/328] Add extension method to handle cases of fire-and-forget async usage --- osu.Game/Extensions/TaskExtensions.cs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 osu.Game/Extensions/TaskExtensions.cs diff --git a/osu.Game/Extensions/TaskExtensions.cs b/osu.Game/Extensions/TaskExtensions.cs new file mode 100644 index 0000000000..913a622d9b --- /dev/null +++ b/osu.Game/Extensions/TaskExtensions.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading.Tasks; +using osu.Framework.Logging; + +namespace osu.Game.Extensions +{ + public static class TaskExtensions + { + /// + /// Denote a task which is to be run without local error handling logic, where failure is not catastrophic. + /// Avoids unobserved exceptions from being fired. + /// + /// The task. + /// Whether errors should be logged as important, or silently ignored. + public static void FireAndForget(this Task task, bool logOnError = false) + { + task.ContinueWith(t => + { + if (logOnError) + Logger.Log($"Error running task: {t.Exception?.Message ?? "unknown"}", LoggingTarget.Runtime, LogLevel.Important); + }, TaskContinuationOptions.NotOnRanToCompletion); + } + } +} From 7cc38f03d10a44c30c5edb59e28f2bdc46e377dd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 17:10:34 +0900 Subject: [PATCH 250/328] Use extension method in all call sites of fire-and-forget async usage --- .../RealtimeMultiplayer/StatefulMultiplayerClient.cs | 5 +++-- .../Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs | 7 ++++--- .../RealtimeMultiplayer/Participants/ParticipantPanel.cs | 3 ++- .../Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs | 2 +- .../Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs | 3 ++- .../Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs | 4 ++-- .../Multi/RealtimeMultiplayer/RealtimeRoomManager.cs | 4 +++- 7 files changed, 17 insertions(+), 11 deletions(-) diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index 79d82a8d02..3196f10f6f 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. + // See the LICENCE file in the repository root for full licence text. #nullable enable @@ -14,6 +14,7 @@ using osu.Framework.Graphics; using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Database; +using osu.Game.Extensions; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -84,7 +85,7 @@ namespace osu.Game.Online.RealtimeMultiplayer if (!connected.NewValue) { Logger.Log("Connection to multiplayer server was lost.", LoggingTarget.Runtime, LogLevel.Important); - LeaveRoom(); + LeaveRoom().FireAndForget(); } }); } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs index 09487e9831..59f9d5e1ec 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs @@ -7,6 +7,7 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Extensions; using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; using osu.Game.Online.API; @@ -105,13 +106,13 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match return; if (localUser.State == MultiplayerUserState.Idle) - Client.ChangeState(MultiplayerUserState.Ready); + Client.ChangeState(MultiplayerUserState.Ready).FireAndForget(true); else { if (Room?.Host?.Equals(localUser) == true) - Client.StartMatch(); + Client.StartMatch().FireAndForget(true); else - Client.ChangeState(MultiplayerUserState.Idle); + Client.ChangeState(MultiplayerUserState.Idle).FireAndForget(true); } } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs index a4ff2ce346..fd16754045 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; +using osu.Game.Extensions; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -176,7 +177,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants if (Room.Host?.UserID != api.LocalUser.Value.Id) return; - Client.TransferHost(targetUser); + Client.TransferHost(targetUser).FireAndForget(true); }) }; } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs index f3dab93089..4a8e398008 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs @@ -58,7 +58,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer client.ChangeSettings(item: item).ContinueWith(t => { - return Schedule(() => + Schedule(() => { loadingLayer.Hide(); diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs index 6455701d31..d5b891f2cc 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Logging; using osu.Framework.Screens; +using osu.Game.Extensions; using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Screens.Multi.Components; @@ -21,7 +22,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer base.OnResuming(last); if (client.Room != null) - client.ChangeState(MultiplayerUserState.Idle); + client.ChangeState(MultiplayerUserState.Idle).FireAndForget(true); } protected override void UpdatePollingRate(bool isIdle) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index 0f8c0f247c..7c6b33cddd 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -56,8 +56,8 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer } }, true); - client.ChangeState(MultiplayerUserState.Loaded).ContinueWith(task => - failAndBail(task.Exception?.Message ?? "Server error"), TaskContinuationOptions.NotOnRanToCompletion); + client.ChangeState(MultiplayerUserState.Loaded) + .ContinueWith(task => failAndBail(task.Exception?.Message ?? "Server error"), TaskContinuationOptions.NotOnRanToCompletion); if (!startedEvent.Wait(TimeSpan.FromSeconds(30))) failAndBail("Failed to start the multiplayer match in time."); diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index 8bdf2bdc1a..98a0e5b694 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Logging; +using osu.Game.Extensions; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.RoomStatuses; using osu.Game.Online.RealtimeMultiplayer; @@ -68,7 +69,8 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer var joinedRoom = JoinedRoom.Value; base.PartRoom(); - multiplayerClient.LeaveRoom(); + + multiplayerClient.LeaveRoom().FireAndForget(); // Todo: This is not the way to do this. Basically when we're the only participant and the room closes, there's no way to know if this is actually the case. // This is delayed one frame because upon exiting the match subscreen, multiplayer updates the polling rate and messes with polling. From 0ddcab574f05416953361e920a1af22856a16828 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 17:14:58 +0900 Subject: [PATCH 251/328] Rename method to avoid weird code analysis rule --- osu.Game/Extensions/TaskExtensions.cs | 2 +- .../Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs | 2 +- .../Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs | 6 +++--- .../RealtimeMultiplayer/Participants/ParticipantPanel.cs | 2 +- .../Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs | 2 +- .../Multi/RealtimeMultiplayer/RealtimeRoomManager.cs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Extensions/TaskExtensions.cs b/osu.Game/Extensions/TaskExtensions.cs index 913a622d9b..a1215d786b 100644 --- a/osu.Game/Extensions/TaskExtensions.cs +++ b/osu.Game/Extensions/TaskExtensions.cs @@ -14,7 +14,7 @@ namespace osu.Game.Extensions ///
/// The task. /// Whether errors should be logged as important, or silently ignored. - public static void FireAndForget(this Task task, bool logOnError = false) + public static void CatchUnobservedExceptions(this Task task, bool logOnError = false) { task.ContinueWith(t => { diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index 3196f10f6f..7b375ca475 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -85,7 +85,7 @@ namespace osu.Game.Online.RealtimeMultiplayer if (!connected.NewValue) { Logger.Log("Connection to multiplayer server was lost.", LoggingTarget.Runtime, LogLevel.Important); - LeaveRoom().FireAndForget(); + LeaveRoom().CatchUnobservedExceptions(); } }); } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs index 59f9d5e1ec..5bead2b271 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs @@ -106,13 +106,13 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match return; if (localUser.State == MultiplayerUserState.Idle) - Client.ChangeState(MultiplayerUserState.Ready).FireAndForget(true); + Client.ChangeState(MultiplayerUserState.Ready).CatchUnobservedExceptions(true); else { if (Room?.Host?.Equals(localUser) == true) - Client.StartMatch().FireAndForget(true); + Client.StartMatch().CatchUnobservedExceptions(true); else - Client.ChangeState(MultiplayerUserState.Idle).FireAndForget(true); + Client.ChangeState(MultiplayerUserState.Idle).CatchUnobservedExceptions(true); } } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs index fd16754045..85393d1bae 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs @@ -177,7 +177,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants if (Room.Host?.UserID != api.LocalUser.Value.Id) return; - Client.TransferHost(targetUser).FireAndForget(true); + Client.TransferHost(targetUser).CatchUnobservedExceptions(true); }) }; } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs index d5b891f2cc..6685cf52d6 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer base.OnResuming(last); if (client.Room != null) - client.ChangeState(MultiplayerUserState.Idle).FireAndForget(true); + client.ChangeState(MultiplayerUserState.Idle).CatchUnobservedExceptions(true); } protected override void UpdatePollingRate(bool isIdle) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index 98a0e5b694..cd337bbb55 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -70,7 +70,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer base.PartRoom(); - multiplayerClient.LeaveRoom().FireAndForget(); + multiplayerClient.LeaveRoom().CatchUnobservedExceptions(); // Todo: This is not the way to do this. Basically when we're the only participant and the room closes, there's no way to know if this is actually the case. // This is delayed one frame because upon exiting the match subscreen, multiplayer updates the polling rate and messes with polling. From 3c8f871b2815ca8f4618dbf2e51870e31324cae8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 17:39:08 +0900 Subject: [PATCH 252/328] Move player constructor configuration to dedicated class; add AllowRestart parameter --- .../TestSceneHoldNoteInput.cs | 6 +- .../TestSceneOutOfOrderHits.cs | 6 +- .../TestSceneLegacyBeatmapSkin.cs | 6 +- .../TestSceneOutOfOrderHits.cs | 6 +- .../TestSceneSliderInput.cs | 6 +- .../Screens/Multi/Play/TimeshiftPlayer.cs | 4 +- .../RealtimeMultiplayer/RealtimePlayer.cs | 7 +- osu.Game/Screens/Play/Player.cs | 140 +++++++++--------- osu.Game/Screens/Play/PlayerConfiguration.cs | 23 +++ osu.Game/Screens/Play/ReplayPlayer.cs | 4 +- osu.Game/Screens/Ranking/ResultsScreen.cs | 15 +- osu.Game/Tests/Visual/TestPlayer.cs | 6 +- 12 files changed, 146 insertions(+), 83 deletions(-) create mode 100644 osu.Game/Screens/Play/PlayerConfiguration.cs diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs index 5cb1519196..596430f9e5 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs @@ -355,7 +355,11 @@ namespace osu.Game.Rulesets.Mania.Tests protected override bool PauseOnFocusLost => false; public ScoreAccessibleReplayPlayer(Score score) - : base(score, false, false) + : base(score, new PlayerConfiguration + { + AllowPause = false, + ShowResults = false, + }) { } } diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs index cecac38f70..18891f8c58 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs @@ -176,7 +176,11 @@ namespace osu.Game.Rulesets.Mania.Tests protected override bool PauseOnFocusLost => false; public ScoreAccessibleReplayPlayer(Score score) - : base(score, false, false) + : base(score, new PlayerConfiguration + { + AllowPause = false, + ShowResults = false, + }) { } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs index 3ff37c4147..a768626005 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs @@ -74,7 +74,11 @@ namespace osu.Game.Rulesets.Osu.Tests private readonly bool userHasCustomColours; public ExposedPlayer(bool userHasCustomColours) - : base(false, false) + : base(new PlayerConfiguration + { + AllowPause = false, + ShowResults = false, + }) { this.userHasCustomColours = userHasCustomColours; } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOutOfOrderHits.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOutOfOrderHits.cs index 32a36ab317..296b421a11 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneOutOfOrderHits.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOutOfOrderHits.cs @@ -439,7 +439,11 @@ namespace osu.Game.Rulesets.Osu.Tests protected override bool PauseOnFocusLost => false; public ScoreAccessibleReplayPlayer(Score score) - : base(score, false, false) + : base(score, new PlayerConfiguration + { + AllowPause = false, + ShowResults = false, + }) { } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs index 0164fb8bf4..2cc031405e 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs @@ -378,7 +378,11 @@ namespace osu.Game.Rulesets.Osu.Tests protected override bool PauseOnFocusLost => false; public ScoreAccessibleReplayPlayer(Score score) - : base(score, false, false) + : base(score, new PlayerConfiguration + { + AllowPause = false, + ShowResults = false, + }) { } } diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs index e8462088f1..f07f1c2fb0 100644 --- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs +++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs @@ -37,8 +37,8 @@ namespace osu.Game.Screens.Multi.Play [Resolved] private IBindable ruleset { get; set; } - public TimeshiftPlayer(PlaylistItem playlistItem, bool allowPause = true) - : base(allowPause) + public TimeshiftPlayer(PlaylistItem playlistItem, PlayerConfiguration configuration = null) + : base(configuration) { PlaylistItem = playlistItem; } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index c6d44686b5..4b878f43d0 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -12,6 +12,7 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Scoring; using osu.Game.Screens.Multi.Play; +using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; namespace osu.Game.Screens.Multi.RealtimeMultiplayer @@ -31,7 +32,11 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer private readonly ManualResetEventSlim startedEvent = new ManualResetEventSlim(); public RealtimePlayer(PlaylistItem playlistItem) - : base(playlistItem, false) + : base(playlistItem, new PlayerConfiguration + { + AllowPause = false, + AllowRestart = false, + }) { } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index c539dff5d9..a1c91ab26b 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -128,18 +128,14 @@ namespace osu.Game.Screens.Play ///
protected virtual bool CheckModsAllowFailure() => Mods.Value.OfType().All(m => m.PerformFail()); - private readonly bool allowPause; - private readonly bool showResults; + public readonly PlayerConfiguration Configuration; /// /// Create a new player instance. /// - /// Whether pausing should be allowed. If not allowed, attempting to pause will quit. - /// Whether results screen should be pushed on completion. - public Player(bool allowPause = true, bool showResults = true) + public Player(PlayerConfiguration configuration = null) { - this.allowPause = allowPause; - this.showResults = showResults; + this.Configuration = configuration ??= new PlayerConfiguration(); } private GameplayBeatmap gameplayBeatmap; @@ -317,59 +313,77 @@ namespace osu.Game.Screens.Play } }; - private Drawable createOverlayComponents(WorkingBeatmap working) => new Container + private Drawable createOverlayComponents(WorkingBeatmap working) { - RelativeSizeAxes = Axes.Both, - Children = new[] + var container = new Container { - DimmableStoryboard.OverlayLayerContainer.CreateProxy(), - BreakOverlay = new BreakOverlay(working.Beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor) + RelativeSizeAxes = Axes.Both, + Children = new[] { - Clock = DrawableRuleset.FrameStableClock, - ProcessCustomClock = false, - Breaks = working.Beatmap.Breaks - }, - // display the cursor above some HUD elements. - DrawableRuleset.Cursor?.CreateProxy() ?? new Container(), - DrawableRuleset.ResumeOverlay?.CreateProxy() ?? new Container(), - HUDOverlay = new HUDOverlay(ScoreProcessor, HealthProcessor, DrawableRuleset, Mods.Value) - { - HoldToQuit = + DimmableStoryboard.OverlayLayerContainer.CreateProxy(), + BreakOverlay = new BreakOverlay(working.Beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor) { - Action = performUserRequestedExit, - IsPaused = { BindTarget = GameplayClockContainer.IsPaused } + Clock = DrawableRuleset.FrameStableClock, + ProcessCustomClock = false, + Breaks = working.Beatmap.Breaks }, - PlayerSettingsOverlay = { PlaybackSettings = { UserPlaybackRate = { BindTarget = GameplayClockContainer.UserPlaybackRate } } }, - KeyCounter = + // display the cursor above some HUD elements. + DrawableRuleset.Cursor?.CreateProxy() ?? new Container(), + DrawableRuleset.ResumeOverlay?.CreateProxy() ?? new Container(), + HUDOverlay = new HUDOverlay(ScoreProcessor, HealthProcessor, DrawableRuleset, Mods.Value) { - AlwaysVisible = { BindTarget = DrawableRuleset.HasReplayLoaded }, - IsCounting = false + HoldToQuit = + { + Action = performUserRequestedExit, + IsPaused = { BindTarget = GameplayClockContainer.IsPaused } + }, + PlayerSettingsOverlay = { PlaybackSettings = { UserPlaybackRate = { BindTarget = GameplayClockContainer.UserPlaybackRate } } }, + KeyCounter = + { + AlwaysVisible = { BindTarget = DrawableRuleset.HasReplayLoaded }, + IsCounting = false + }, + RequestSeek = time => + { + GameplayClockContainer.Seek(time); + GameplayClockContainer.Start(); + }, + Anchor = Anchor.Centre, + Origin = Anchor.Centre }, - RequestSeek = time => + skipOverlay = new SkipOverlay(DrawableRuleset.GameplayStartTime) { - GameplayClockContainer.Seek(time); - GameplayClockContainer.Start(); + RequestSkip = GameplayClockContainer.Skip }, - Anchor = Anchor.Centre, - Origin = Anchor.Centre - }, - skipOverlay = new SkipOverlay(DrawableRuleset.GameplayStartTime) - { - RequestSkip = GameplayClockContainer.Skip - }, - FailOverlay = new FailOverlay - { - OnRetry = Restart, - OnQuit = performUserRequestedExit, - }, - PauseOverlay = new PauseOverlay - { - OnResume = Resume, - Retries = RestartCount, - OnRetry = Restart, - OnQuit = performUserRequestedExit, - }, - new HotkeyRetryOverlay + FailOverlay = new FailOverlay + { + OnRetry = Restart, + OnQuit = performUserRequestedExit, + }, + PauseOverlay = new PauseOverlay + { + OnResume = Resume, + Retries = RestartCount, + OnRetry = Restart, + OnQuit = performUserRequestedExit, + }, + new HotkeyExitOverlay + { + Action = () => + { + if (!this.IsCurrentScreen()) return; + + fadeOut(true); + performImmediateExit(); + }, + }, + failAnimation = new FailAnimation(DrawableRuleset) { OnComplete = onFailComplete, }, + } + }; + + if (Configuration.AllowRestart) + { + container.Add(new HotkeyRetryOverlay { Action = () => { @@ -378,20 +392,11 @@ namespace osu.Game.Screens.Play fadeOut(true); Restart(); }, - }, - new HotkeyExitOverlay - { - Action = () => - { - if (!this.IsCurrentScreen()) return; - - fadeOut(true); - performImmediateExit(); - }, - }, - failAnimation = new FailAnimation(DrawableRuleset) { OnComplete = onFailComplete, }, + }); } - }; + + return container; + } private void onBreakTimeChanged(ValueChangedEvent isBreakTime) { @@ -490,6 +495,9 @@ namespace osu.Game.Screens.Play ///
public void Restart() { + if (!Configuration.AllowRestart) + return; + // at the point of restarting the track should either already be paused or the volume should be zero. // stopping here is to ensure music doesn't become audible after exiting back to PlayerLoader. musicController.Stop(); @@ -529,7 +537,7 @@ namespace osu.Game.Screens.Play ValidForResume = false; - if (!showResults) return; + if (!Configuration.ShowResults) return; scoreSubmissionTask ??= Task.Run(async () => { @@ -628,7 +636,7 @@ namespace osu.Game.Screens.Play private bool canPause => // must pass basic screen conditions (beatmap loaded, instance allows pause) - LoadedBeatmapSuccessfully && allowPause && ValidForResume + LoadedBeatmapSuccessfully && Configuration.AllowPause && ValidForResume // replays cannot be paused and exit immediately && !DrawableRuleset.HasReplayLoaded.Value // cannot pause if we are already in a fail state diff --git a/osu.Game/Screens/Play/PlayerConfiguration.cs b/osu.Game/Screens/Play/PlayerConfiguration.cs new file mode 100644 index 0000000000..475a234679 --- /dev/null +++ b/osu.Game/Screens/Play/PlayerConfiguration.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Screens.Play +{ + public class PlayerConfiguration + { + /// + /// Whether pausing should be allowed. If not allowed, attempting to pause will quit. + /// + public bool AllowPause { get; set; } = true; + + /// + /// Whether results screen should be pushed on completion. + /// + public bool ShowResults { get; set; } = true; + + /// + /// Whether the player should be allowed to trigger a restart. + /// + public bool AllowRestart { get; set; } = true; + } +} diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index a07213cb33..e23cc22929 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -16,8 +16,8 @@ namespace osu.Game.Screens.Play // Disallow replays from failing. (see https://github.com/ppy/osu/issues/6108) protected override bool CheckModsAllowFailure() => false; - public ReplayPlayer(Score score, bool allowPause = true, bool showResults = true) - : base(allowPause, showResults) + public ReplayPlayer(Score score, PlayerConfiguration configuration = null) + : base(configuration) { Score = score; } diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index 528a1842af..8a12427798 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -164,15 +164,18 @@ namespace osu.Game.Screens.Ranking { buttons.Add(new RetryButton { Width = 300 }); - AddInternal(new HotkeyRetryOverlay + if (player?.Configuration.AllowRestart == true) { - Action = () => + AddInternal(new HotkeyRetryOverlay { - if (!this.IsCurrentScreen()) return; + Action = () => + { + if (!this.IsCurrentScreen()) return; - player?.Restart(); - }, - }); + player?.Restart(); + }, + }); + } } } diff --git a/osu.Game/Tests/Visual/TestPlayer.cs b/osu.Game/Tests/Visual/TestPlayer.cs index f016d29f38..f47391ce6a 100644 --- a/osu.Game/Tests/Visual/TestPlayer.cs +++ b/osu.Game/Tests/Visual/TestPlayer.cs @@ -37,7 +37,11 @@ namespace osu.Game.Tests.Visual public readonly List Results = new List(); public TestPlayer(bool allowPause = true, bool showResults = true, bool pauseOnFocusLost = false) - : base(allowPause, showResults) + : base(new PlayerConfiguration + { + AllowPause = allowPause, + ShowResults = showResults + }) { PauseOnFocusLost = pauseOnFocusLost; } From f9fd909187c3839101e3c52aa476e2460b3e0778 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 18:07:38 +0900 Subject: [PATCH 253/328] Fix missed inspections --- osu.Game/Screens/Play/Player.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index a1c91ab26b..f1fb27e154 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -135,7 +135,7 @@ namespace osu.Game.Screens.Play ///
public Player(PlayerConfiguration configuration = null) { - this.Configuration = configuration ??= new PlayerConfiguration(); + Configuration = configuration ?? new PlayerConfiguration(); } private GameplayBeatmap gameplayBeatmap; From 94e4928c4b5feb2bb404173e27fadedbb5d5468d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Dec 2020 11:27:15 +0100 Subject: [PATCH 254/328] Bring back accidentally-removed license header --- .../Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index 7b375ca475..6331d324a6 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -1,4 +1,4 @@ - +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable enable From ea5da53597e2d1a57b76b6f4d80429645ccc6657 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Wed, 23 Dec 2020 13:31:27 +0100 Subject: [PATCH 255/328] Handle URL links with the osu scheme. --- osu.Android/OsuGameActivity.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs index e801c2ca6e..55484c439a 100644 --- a/osu.Android/OsuGameActivity.cs +++ b/osu.Android/OsuGameActivity.cs @@ -16,8 +16,11 @@ namespace osu.Android { [Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false)] [IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataPathPatterns = new[] { ".*\\.osz", ".*\\.osk" }, DataMimeType = "application/*")] + [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataScheme = osu_url_scheme)] public class OsuGameActivity : AndroidGameActivity { + private const string osu_url_scheme = "osu"; + private OsuGameAndroid game; protected override Framework.Game CreateGame() => game = new OsuGameAndroid(this); @@ -49,6 +52,8 @@ namespace osu.Android case Intent.ActionDefault: if (intent.Scheme == ContentResolver.SchemeContent) handleImportFromUri(intent.Data); + else if (intent.Scheme == osu_url_scheme) + Task.Run(() => game.HandleLink(intent.DataString)); break; case Intent.ActionSend: From 78b8c60f1949aef5c5a63febcf46968038dd9287 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Wed, 23 Dec 2020 13:38:33 +0100 Subject: [PATCH 256/328] Opt for SingleInstance launch mode --- osu.Android/OsuGameActivity.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs index 55484c439a..dfdecdca2e 100644 --- a/osu.Android/OsuGameActivity.cs +++ b/osu.Android/OsuGameActivity.cs @@ -14,7 +14,7 @@ using osu.Framework.Android; namespace osu.Android { - [Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false)] + [Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false, LaunchMode = LaunchMode.SingleInstance)] [IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataPathPatterns = new[] { ".*\\.osz", ".*\\.osk" }, DataMimeType = "application/*")] [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataScheme = osu_url_scheme)] public class OsuGameActivity : AndroidGameActivity From 582b0d2a7467f54f4ae125f79fe6c5611fb88f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Dec 2020 13:47:28 +0100 Subject: [PATCH 257/328] Revert logic to be closer to original Note the reversal of the order of operations in `endHandlingTrack()` (done for extra safety, to ensure no more value changed events can be fired at the point of cancelling looping). --- osu.Game/Screens/Multi/Match/RoomSubScreen.cs | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Multi/Match/RoomSubScreen.cs b/osu.Game/Screens/Multi/Match/RoomSubScreen.cs index 4f5d2a5b3e..b9d7408946 100644 --- a/osu.Game/Screens/Multi/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/Multi/Match/RoomSubScreen.cs @@ -41,27 +41,24 @@ namespace osu.Game.Screens.Multi.Match managerUpdated = beatmapManager.ItemUpdated.GetBoundCopy(); managerUpdated.BindValueChanged(beatmapUpdated); - - if (music != null) - music.TrackChanged += applyToTrack; } public override void OnEntering(IScreen last) { base.OnEntering(last); - applyToTrack(); + beginHandlingTrack(); } public override void OnSuspending(IScreen next) { - resetTrack(); + endHandlingTrack(); base.OnSuspending(next); } public override void OnResuming(IScreen last) { base.OnResuming(last); - applyToTrack(); + beginHandlingTrack(); } public override bool OnExiting(IScreen next) @@ -69,7 +66,7 @@ namespace osu.Game.Screens.Multi.Match RoomManager?.PartRoom(); Mods.Value = Array.Empty(); - resetTrack(); + endHandlingTrack(); return base.OnExiting(next); } @@ -98,7 +95,18 @@ namespace osu.Game.Screens.Multi.Match Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); } - private void applyToTrack(WorkingBeatmap _ = default, TrackChangeDirection __ = default) + private void beginHandlingTrack() + { + Beatmap.BindValueChanged(applyLoopingToTrack, true); + } + + private void endHandlingTrack() + { + Beatmap.ValueChanged -= applyLoopingToTrack; + cancelTrackLooping(); + } + + private void applyLoopingToTrack(ValueChangedEvent _ = null) { if (!this.IsCurrentScreen()) return; @@ -114,7 +122,7 @@ namespace osu.Game.Screens.Multi.Match } } - private void resetTrack() + private void cancelTrackLooping() { var track = Beatmap?.Value?.Track; From c5692a5d6aa51c51513e8a34c5ac023cb9326847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Dec 2020 14:18:24 +0100 Subject: [PATCH 258/328] Re-enable carousel selection after error --- .../Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs index 4a8e398008..8f317800e3 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs @@ -65,7 +65,10 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer if (t.IsCompletedSuccessfully) this.Exit(); else + { Logger.Log($"Could not use current beatmap ({t.Exception?.Message})", level: LogLevel.Important); + Carousel.AllowSelection = true; + } }); }); } From 4296f61d6cbe0a8d25a94a9ae22274139c8b1b1a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Dec 2020 22:39:14 +0900 Subject: [PATCH 259/328] Tidy up event flow of change settings call --- .../RealtimeMultiplayer/StatefulMultiplayerClient.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index 6331d324a6..dc999ee2be 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -369,7 +369,6 @@ namespace osu.Game.Online.RealtimeMultiplayer if (Room == null) return; - // Update a few properties of the room instantaneously. Schedule(() => { if (Room == null) @@ -377,6 +376,7 @@ namespace osu.Game.Online.RealtimeMultiplayer Debug.Assert(apiRoom != null); + // Update a few properties of the room instantaneously. Room.Settings = settings; apiRoom.Name.Value = Room.Settings.Name; @@ -385,12 +385,12 @@ namespace osu.Game.Online.RealtimeMultiplayer apiRoom.Playlist.Clear(); RoomChanged?.Invoke(); + + var req = new GetBeatmapSetRequest(settings.BeatmapID, BeatmapSetLookupType.BeatmapId); + req.Success += res => updatePlaylist(settings, res); + + api.Queue(req); }); - - var req = new GetBeatmapSetRequest(settings.BeatmapID, BeatmapSetLookupType.BeatmapId); - req.Success += res => updatePlaylist(settings, res); - - api.Queue(req); } private void updatePlaylist(MultiplayerRoomSettings settings, APIBeatmapSet onlineSet) From 980e85ce25f087f28306c530e15b3d7916b2b5bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Dec 2020 15:51:26 +0100 Subject: [PATCH 260/328] Refactor player exit logic to convey intention better --- .../RealtimeMultiplayer/RealtimePlayer.cs | 4 ++-- osu.Game/Screens/Play/Player.cs | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index 0d8e636450..e467e5fcf8 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -61,7 +61,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer startedEvent.Set(); // messaging to the user about this disconnect will be provided by the RealtimeMatchSubScreen. - Schedule(PerformImmediateExit); + Schedule(() => PerformExit(false)); } }, true); @@ -71,7 +71,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer { Logger.Log("Failed to start the multiplayer match in time.", LoggingTarget.Runtime, LogLevel.Important); - Schedule(PerformImmediateExit); + Schedule(() => PerformExit(false)); } Debug.Assert(client.Room != null); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index c6265c48d2..2bc84ce5d5 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -386,7 +386,7 @@ namespace osu.Game.Screens.Play if (!this.IsCurrentScreen()) return; fadeOut(true); - PerformImmediateExit(); + PerformExit(true); }, }, failAnimation = new FailAnimation(DrawableRuleset) { OnComplete = onFailComplete, }, @@ -458,20 +458,30 @@ namespace osu.Game.Screens.Play return playable; } - protected void PerformImmediateExit() + /// + /// Exits the . + /// + /// + /// Whether the exit is requested by the user, or a higher-level game component. + /// Pausing is allowed only in the former case. + /// + protected void PerformExit(bool userRequested) { // if a restart has been requested, cancel any pending completion (user has shown intent to restart). completionProgressDelegate?.Cancel(); ValidForResume = false; - performUserRequestedExit(); + if (!this.IsCurrentScreen()) return; + + if (userRequested) + performUserRequestedExit(); + else + this.Exit(); } private void performUserRequestedExit() { - if (!this.IsCurrentScreen()) return; - if (ValidForResume && HasFailed && !FailOverlay.IsPresent) { failAnimation.FinishTransforms(true); @@ -498,7 +508,7 @@ namespace osu.Game.Screens.Play RestartRequested?.Invoke(); if (this.IsCurrentScreen()) - PerformImmediateExit(); + PerformExit(true); else this.MakeCurrent(); } From 3b0bf1136642c40fd189cbbd1940d3121f286e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Dec 2020 17:01:01 +0100 Subject: [PATCH 261/328] Fix JoinRoom failing to return canceled token As it turns out, `Task.FromCanceled` expects to receive an already cancelled `CancellationToken`, which `CancellationToken.None` is not. --- .../Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs index 5cbf3be8ca..026b7176d1 100644 --- a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs @@ -122,7 +122,7 @@ namespace osu.Game.Online.RealtimeMultiplayer protected override Task JoinRoom(long roomId) { if (!isConnected.Value) - return Task.FromCanceled(CancellationToken.None); + return Task.FromCanceled(new CancellationToken(true)); return connection.InvokeAsync(nameof(IMultiplayerServer.JoinRoom), roomId); } From e4959489b70d61f76c6f25e0c7125fd24d96becc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Dec 2020 17:08:28 +0100 Subject: [PATCH 262/328] Improve user-facing error messages in room settings --- .../Match/RealtimeMatchSettingsOverlay.cs | 3 ++- .../Multi/RealtimeMultiplayer/RealtimeRoomManager.cs | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs index 3e495b490f..a93b1b09d1 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.ExceptionExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -299,7 +300,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match if (t.IsCompletedSuccessfully) onSuccess(currentRoom.Value); else - onError(t.Exception?.Message ?? "Error changing settings."); + onError(t.Exception?.AsSingular().Message ?? "Error changing settings."); })); } else diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs index cd337bbb55..eb6e5fad07 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ExceptionExtensions; using osu.Framework.Logging; using osu.Game.Extensions; using osu.Game.Online.Multiplayer; @@ -91,11 +92,13 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer Schedule(() => onSuccess?.Invoke(room)); else { + const string message = "Failed to join multiplayer room."; + if (t.Exception != null) - Logger.Error(t.Exception, "Failed to join multiplayer room."); + Logger.Error(t.Exception, message); PartRoom(); - Schedule(() => onError?.Invoke(t.Exception?.ToString() ?? string.Empty)); + Schedule(() => onError?.Invoke(t.Exception?.AsSingular().Message ?? message)); } }); } From e89583d732e5c9996534bdb89a8ee42470cbe530 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 01:33:19 +0900 Subject: [PATCH 263/328] Prefer connecting to dev server when running in DEBUG --- osu.Game/Online/API/APIAccess.cs | 8 +++++++- .../RealtimeMultiplayer/RealtimeMultiplayerClient.cs | 4 ++++ osu.Game/Online/Spectator/SpectatorStreamingClient.cs | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index fe500b9548..ca457ccf71 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -26,9 +26,15 @@ namespace osu.Game.Online.API private readonly OAuth authentication; +#if DEBUG + public string Endpoint => @"https://dev.ppy.sh"; + private const string client_secret = @"3LP2mhUrV89xxzD1YKNndXHEhWWCRLPNKioZ9ymT"; +#else public string Endpoint => @"https://osu.ppy.sh"; - private const string client_id = @"5"; private const string client_secret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"; +#endif + + private const string client_id = @"5"; private readonly Queue queue = new Queue(); diff --git a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs index 75bb578a29..4ec5b9af40 100644 --- a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs @@ -19,7 +19,11 @@ namespace osu.Game.Online.RealtimeMultiplayer { public class RealtimeMultiplayerClient : StatefulMultiplayerClient { +#if DEBUG + private const string endpoint = "https://dev.ppy.sh/multiplayer"; +#else private const string endpoint = "https://spectator.ppy.sh/multiplayer"; +#endif public override IBindable IsConnected => isConnected; diff --git a/osu.Game/Online/Spectator/SpectatorStreamingClient.cs b/osu.Game/Online/Spectator/SpectatorStreamingClient.cs index 0167a5d025..c9203b595e 100644 --- a/osu.Game/Online/Spectator/SpectatorStreamingClient.cs +++ b/osu.Game/Online/Spectator/SpectatorStreamingClient.cs @@ -104,7 +104,11 @@ namespace osu.Game.Online.Spectator } } +#if DEBUG + private const string endpoint = "https://dev.ppy.sh/spectator"; +#else private const string endpoint = "https://spectator.ppy.sh/spectator"; +#endif protected virtual async Task Connect() { From 9843da59f4866918391902de30125577b60c1464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Dec 2020 20:29:17 +0100 Subject: [PATCH 264/328] Fix intermittent test fail due to duplicate user `TestSceneRealtimeReadyButton` was manually adding `API.LocalUser`, which wasn't actually needed. The base `RealtimeMultiplayerTestScene` by default creates a new room as `API.LocalUser`, therefore automatically adding that user to the room - and as such there is no need to add them manually unless the `joinRoom` ctor param is specified as `false`. --- .../Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs index b7cd81fb32..e9d3ddb32d 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs @@ -55,8 +55,6 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer } } }; - - Client.AddUser(API.LocalUser.Value); }); [Test] From 47020c888731c2370d6f81fbfe9f11d6e7fcfdc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Dec 2020 21:00:47 +0100 Subject: [PATCH 265/328] Add failing test cases --- .../TestSceneRealtimeMultiplayer.cs | 24 +++++++++++++++++++ .../TestRealtimeMultiplayerClient.cs | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs index 80955ca380..5cf80df6aa 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs @@ -1,7 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using NUnit.Framework; using osu.Game.Screens.Multi.Components; +using osu.Game.Users; namespace osu.Game.Tests.Visual.RealtimeMultiplayer { @@ -15,6 +17,28 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer AddUntilStep("wait for loaded", () => multi.IsLoaded); } + [Test] + public void TestOneUserJoinedMultipleTimes() + { + var user = new User { Id = 33 }; + + AddRepeatStep("add user multiple times", () => Client.AddUser(user), 3); + + AddAssert("room has 2 users", () => Client.Room?.Users.Count == 2); + } + + [Test] + public void TestOneUserLeftMultipleTimes() + { + var user = new User { Id = 44 }; + + AddStep("add user", () => Client.AddUser(user)); + AddAssert("room has 2 users", () => Client.Room?.Users.Count == 2); + + AddRepeatStep("remove user multiple times", () => Client.RemoveUser(user), 3); + AddAssert("room has 1 user", () => Client.Room?.Users.Count == 1); + } + private class TestRealtimeMultiplayer : Screens.Multi.RealtimeMultiplayer.RealtimeMultiplayer { protected override RoomManager CreateRoomManager() => new TestRealtimeRoomManager(); diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs index de52633c88..52047016e2 100644 --- a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs @@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer public void RemoveUser(User user) { Debug.Assert(Room != null); - ((IMultiplayerClient)this).UserLeft(Room.Users.Single(u => u.User == user)); + ((IMultiplayerClient)this).UserLeft(new MultiplayerRoomUser(user.Id)); Schedule(() => { From a71496bc4e9f0386d13b295eb92496f33144e5b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Dec 2020 20:34:19 +0100 Subject: [PATCH 266/328] Sanity check received user joined messages While test failures fixed in 9843da5 were a shortcoming of the test, they exposed a potential vulnerable point of the multiplayer client logic. In case of unreliable message delivery it is not unreasonable that duplicate messages might arrive, in which case the same scenario that failed in the tests could crash the game. To ensure that is not the case, explicitly screen each new joined user against the room user list, to ensure that duplicates do not show up. `UserLeft` is already tolerant in that respect (if a user is requested to be removed twice by the server, the second removal just won't do anything). --- .../Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs index 6331d324a6..e8dbeda9cb 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs @@ -226,6 +226,10 @@ namespace osu.Game.Online.RealtimeMultiplayer if (Room == null) return; + // for sanity, ensure that there can be no duplicate users in the room user list. + if (Room.Users.Any(existing => existing.UserID == user.UserID)) + return; + Room.Users.Add(user); RoomChanged?.Invoke(); From 05d9f2376224b42d9ee56f8ee094374a15dc2801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Dec 2020 16:38:18 +0100 Subject: [PATCH 267/328] Move out create room button to separate class --- osu.Game/Screens/Multi/CreateRoomButton.cs | 31 ++++++++++++++++++++++ osu.Game/Screens/Multi/Multiplayer.cs | 23 ---------------- 2 files changed, 31 insertions(+), 23 deletions(-) create mode 100644 osu.Game/Screens/Multi/CreateRoomButton.cs diff --git a/osu.Game/Screens/Multi/CreateRoomButton.cs b/osu.Game/Screens/Multi/CreateRoomButton.cs new file mode 100644 index 0000000000..b501de46ef --- /dev/null +++ b/osu.Game/Screens/Multi/CreateRoomButton.cs @@ -0,0 +1,31 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Screens.Multi.Match.Components; +using osuTK; + +namespace osu.Game.Screens.Multi +{ + public class CreateRoomButton : PurpleTriangleButton + { + public CreateRoomButton() + { + Size = new Vector2(150, Header.HEIGHT - 20); + Margin = new MarginPadding + { + Top = 10, + Right = 10 + OsuScreen.HORIZONTAL_OVERFLOW_PADDING, + }; + } + + [BackgroundDependencyLoader] + private void load() + { + Triangles.TriangleScale = 1.5f; + + Text = "Create room"; + } + } +} diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index de2e0d58c9..a957eb6824 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -21,9 +21,7 @@ using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Lounge.Components; using osu.Game.Screens.Multi.Match; -using osu.Game.Screens.Multi.Match.Components; using osu.Game.Users; -using osuTK; namespace osu.Game.Screens.Multi { @@ -332,26 +330,5 @@ namespace osu.Game.Screens.Multi protected override double TransformDuration => 200; } } - - public class CreateRoomButton : PurpleTriangleButton - { - public CreateRoomButton() - { - Size = new Vector2(150, Header.HEIGHT - 20); - Margin = new MarginPadding - { - Top = 10, - Right = 10 + HORIZONTAL_OVERFLOW_PADDING, - }; - } - - [BackgroundDependencyLoader] - private void load() - { - Triangles.TriangleScale = 1.5f; - - Text = "Create room"; - } - } } } From c13acb609aed79df56e883586697be71b72e74c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Dec 2020 21:50:29 +0100 Subject: [PATCH 268/328] Move out sizing logic to multiplayer screen --- osu.Game/Screens/Multi/CreateRoomButton.cs | 12 ------------ osu.Game/Screens/Multi/Multiplayer.cs | 7 +++++++ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Multi/CreateRoomButton.cs b/osu.Game/Screens/Multi/CreateRoomButton.cs index b501de46ef..9e53904510 100644 --- a/osu.Game/Screens/Multi/CreateRoomButton.cs +++ b/osu.Game/Screens/Multi/CreateRoomButton.cs @@ -2,24 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Graphics; using osu.Game.Screens.Multi.Match.Components; -using osuTK; namespace osu.Game.Screens.Multi { public class CreateRoomButton : PurpleTriangleButton { - public CreateRoomButton() - { - Size = new Vector2(150, Header.HEIGHT - 20); - Margin = new MarginPadding - { - Top = 10, - Right = 10 + OsuScreen.HORIZONTAL_OVERFLOW_PADDING, - }; - } - [BackgroundDependencyLoader] private void load() { diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index a957eb6824..c820eae51f 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -22,6 +22,7 @@ using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Lounge.Components; using osu.Game.Screens.Multi.Match; using osu.Game.Users; +using osuTK; namespace osu.Game.Screens.Multi { @@ -131,6 +132,12 @@ namespace osu.Game.Screens.Multi { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, + Size = new Vector2(150, Header.HEIGHT - 20), + Margin = new MarginPadding + { + Top = 10, + Right = 10 + HORIZONTAL_OVERFLOW_PADDING, + }, Action = () => OpenNewRoom() }, RoomManager = CreateRoomManager() From 414f886b02d21c24ddaddc273ac747dc1d347b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Dec 2020 22:02:37 +0100 Subject: [PATCH 269/328] Split timeshift & multiplayer "create" buttons Multiplayer button gets new, different "Create match" text, and disable logic in case of a dropped connection to the multiplayer server. --- osu.Game/Screens/Multi/Multiplayer.cs | 18 ++++++++------- .../CreateRealtimeMatchButton.cs | 23 +++++++++++++++++++ .../RealtimeMultiplayer.cs | 3 +++ .../CreateTimeshiftRoomButton.cs} | 4 ++-- .../Multi/Timeshift/TimeshiftMultiplayer.cs | 3 +++ 5 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 osu.Game/Screens/Multi/RealtimeMultiplayer/CreateRealtimeMatchButton.cs rename osu.Game/Screens/Multi/{CreateRoomButton.cs => Timeshift/CreateTimeshiftRoomButton.cs} (78%) diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index c820eae51f..a7d40a89d3 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -128,18 +128,18 @@ namespace osu.Game.Screens.Multi } }, new Header(screenStack), - createButton = new CreateRoomButton + createButton = CreateNewMultiplayerGameButton().With(button => { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Size = new Vector2(150, Header.HEIGHT - 20), - Margin = new MarginPadding + button.Anchor = Anchor.TopRight; + button.Origin = Anchor.TopRight; + button.Size = new Vector2(150, Header.HEIGHT - 20); + button.Margin = new MarginPadding { Top = 10, Right = 10 + HORIZONTAL_OVERFLOW_PADDING, - }, - Action = () => OpenNewRoom() - }, + }; + button.Action = () => OpenNewRoom(); + }), RoomManager = CreateRoomManager() } }; @@ -315,6 +315,8 @@ namespace osu.Game.Screens.Multi protected abstract LoungeSubScreen CreateLounge(); + protected abstract OsuButton CreateNewMultiplayerGameButton(); + private class MultiplayerWaveContainer : WaveContainer { protected override bool StartHidden => true; diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/CreateRealtimeMatchButton.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/CreateRealtimeMatchButton.cs new file mode 100644 index 0000000000..eda907f8cb --- /dev/null +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/CreateRealtimeMatchButton.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Screens.Multi.Match.Components; + +namespace osu.Game.Screens.Multi.RealtimeMultiplayer +{ + public class CreateRealtimeMatchButton : PurpleTriangleButton + { + [BackgroundDependencyLoader] + private void load(StatefulMultiplayerClient multiplayerClient) + { + Triangles.TriangleScale = 1.5f; + + Text = "Create match"; + + ((IBindable)Enabled).BindTo(multiplayerClient.IsConnected); + } + } +} diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs index 6685cf52d6..6739a51fe8 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Extensions; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Screens.Multi.Components; @@ -64,5 +65,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer protected override RoomManager CreateRoomManager() => new RealtimeRoomManager(); protected override LoungeSubScreen CreateLounge() => new RealtimeLoungeSubScreen(); + + protected override OsuButton CreateNewMultiplayerGameButton() => new CreateRealtimeMatchButton(); } } diff --git a/osu.Game/Screens/Multi/CreateRoomButton.cs b/osu.Game/Screens/Multi/Timeshift/CreateTimeshiftRoomButton.cs similarity index 78% rename from osu.Game/Screens/Multi/CreateRoomButton.cs rename to osu.Game/Screens/Multi/Timeshift/CreateTimeshiftRoomButton.cs index 9e53904510..bd9d667630 100644 --- a/osu.Game/Screens/Multi/CreateRoomButton.cs +++ b/osu.Game/Screens/Multi/Timeshift/CreateTimeshiftRoomButton.cs @@ -4,9 +4,9 @@ using osu.Framework.Allocation; using osu.Game.Screens.Multi.Match.Components; -namespace osu.Game.Screens.Multi +namespace osu.Game.Screens.Multi.Timeshift { - public class CreateRoomButton : PurpleTriangleButton + public class CreateTimeshiftRoomButton : PurpleTriangleButton { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs index 2ea4857799..d525a3800d 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs @@ -3,6 +3,7 @@ using osu.Framework.Logging; using osu.Framework.Screens; +using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Match; @@ -47,5 +48,7 @@ namespace osu.Game.Screens.Multi.Timeshift protected override RoomManager CreateRoomManager() => new TimeshiftRoomManager(); protected override LoungeSubScreen CreateLounge() => new TimeshiftLoungeSubScreen(); + + protected override OsuButton CreateNewMultiplayerGameButton() => new CreateTimeshiftRoomButton(); } } From 06bc3cd54d448d5597a193d7024c036f25b9e081 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Thu, 24 Dec 2020 00:17:26 +0100 Subject: [PATCH 270/328] Apply review suggestions. --- osu.Android/OsuGameActivity.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs index dfdecdca2e..953c06f4e2 100644 --- a/osu.Android/OsuGameActivity.cs +++ b/osu.Android/OsuGameActivity.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.IO; +using System.Linq; using System.Threading.Tasks; using Android.App; using Android.Content; @@ -16,10 +17,10 @@ namespace osu.Android { [Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false, LaunchMode = LaunchMode.SingleInstance)] [IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataPathPatterns = new[] { ".*\\.osz", ".*\\.osk" }, DataMimeType = "application/*")] - [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataScheme = osu_url_scheme)] + [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataSchemes = new[] { "osu", "osump" })] public class OsuGameActivity : AndroidGameActivity { - private const string osu_url_scheme = "osu"; + private static readonly string[] osu_url_schemes = { "osu", "osump" }; private OsuGameAndroid game; @@ -52,8 +53,8 @@ namespace osu.Android case Intent.ActionDefault: if (intent.Scheme == ContentResolver.SchemeContent) handleImportFromUri(intent.Data); - else if (intent.Scheme == osu_url_scheme) - Task.Run(() => game.HandleLink(intent.DataString)); + else if (osu_url_schemes.Contains(intent.Scheme)) + game.HandleLink(intent.DataString); break; case Intent.ActionSend: From d6dadd12faa7c277befcdcefd0eecdc25196cf0c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 10:38:53 +0900 Subject: [PATCH 271/328] Send multiplayer user IDs via ctor for better thread safety --- .../RealtimeMultiplayer/RealtimeMatchSubScreen.cs | 10 +++++++++- .../Multi/RealtimeMultiplayer/RealtimePlayer.cs | 13 +++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs index cdab1435c0..468908f83d 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Specialized; +using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -188,7 +189,14 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) => SelectedItem.Value = Playlist.FirstOrDefault(); - private void onLoadRequested() => multiplayer?.Push(new PlayerLoader(() => new RealtimePlayer(SelectedItem.Value))); + private void onLoadRequested() + { + Debug.Assert(client.Room != null); + + int[] userIds = client.Room.Users.Where(u => u.State >= MultiplayerUserState.WaitingForLoad).Select(u => u.UserID).ToArray(); + + multiplayer?.Push(new PlayerLoader(() => new RealtimePlayer(SelectedItem.Value, userIds))); + } protected override void Dispose(bool isDisposing) { diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index 7824b414f2..25543d3d6d 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -3,7 +3,6 @@ using System; using System.Diagnostics; -using System.Linq; using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; @@ -37,9 +36,17 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer [CanBeNull] private MultiplayerGameplayLeaderboard leaderboard; - public RealtimePlayer(PlaylistItem playlistItem) + private readonly int[] userIds; + + /// + /// Construct a multiplayer player. + /// + /// The playlist item to be played. + /// The users which are participating in this game. + public RealtimePlayer(PlaylistItem playlistItem, int[] userIds) : base(playlistItem, false) { + this.userIds = userIds; } [BackgroundDependencyLoader] @@ -65,8 +72,6 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer Debug.Assert(client.Room != null); - int[] userIds = client.Room.Users.Where(u => u.State >= MultiplayerUserState.WaitingForLoad).Select(u => u.UserID).ToArray(); - // todo: this should be implemented via a custom HUD implementation, and correctly masked to the main content area. LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(ScoreProcessor, userIds), HUDOverlay.Add); } From a411b26a09530bed75c404afe49d5b447bd5a863 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 10:51:24 +0900 Subject: [PATCH 272/328] Remove unnecessary clamp Co-authored-by: Joseph Madamba --- osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index 3f770cfb5e..20c0818d03 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Mods var destination = e.MousePosition; FlashlightPosition = Interpolation.ValueAt( - Math.Clamp(Math.Abs(Clock.ElapsedFrameTime), 0, follow_delay), position, destination, 0, follow_delay, Easing.Out); + Math.Min(Math.Abs(Clock.ElapsedFrameTime), follow_delay), position, destination, 0, follow_delay, Easing.Out); return base.OnMouseMove(e); } From 61a5d3ef4ae8d7724eb02686a01a33e85cbc4e0c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 13:32:35 +0900 Subject: [PATCH 273/328] Remove double handling of restart allowance on results screen (already handled locally) --- osu.Game/Screens/Ranking/ResultsScreen.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index 8a12427798..528a1842af 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -164,18 +164,15 @@ namespace osu.Game.Screens.Ranking { buttons.Add(new RetryButton { Width = 300 }); - if (player?.Configuration.AllowRestart == true) + AddInternal(new HotkeyRetryOverlay { - AddInternal(new HotkeyRetryOverlay + Action = () => { - Action = () => - { - if (!this.IsCurrentScreen()) return; + if (!this.IsCurrentScreen()) return; - player?.Restart(); - }, - }); - } + player?.Restart(); + }, + }); } } From 1f80f01b53f4861a26ee8564bb7b81684cfad488 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 14:46:52 +0900 Subject: [PATCH 274/328] Add accuracy to frame bundle header --- osu.Game/Online/Spectator/FrameHeader.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Spectator/FrameHeader.cs b/osu.Game/Online/Spectator/FrameHeader.cs index b4988fecf9..135b356eda 100644 --- a/osu.Game/Online/Spectator/FrameHeader.cs +++ b/osu.Game/Online/Spectator/FrameHeader.cs @@ -14,6 +14,11 @@ namespace osu.Game.Online.Spectator [Serializable] public class FrameHeader { + /// + /// The current accuracy of the score. + /// + public double Accuracy { get; set; } + /// /// The current combo of the score. /// @@ -42,16 +47,18 @@ namespace osu.Game.Online.Spectator { Combo = score.Combo; MaxCombo = score.MaxCombo; + Accuracy = score.Accuracy; // copy for safety Statistics = new Dictionary(score.Statistics); } [JsonConstructor] - public FrameHeader(int combo, int maxCombo, Dictionary statistics, DateTimeOffset receivedTime) + public FrameHeader(int combo, int maxCombo, double accuracy, Dictionary statistics, DateTimeOffset receivedTime) { Combo = combo; MaxCombo = maxCombo; + Accuracy = accuracy; Statistics = statistics; ReceivedTime = receivedTime; } From d66e2183185bbedc26b2d7350499e71d3aebc0fb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 14:57:23 +0900 Subject: [PATCH 275/328] Source display accuracy from header and remove from ScoreProcessor function --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 15 +++++---------- .../Play/HUD/MultiplayerGameplayLeaderboard.cs | 4 ++-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 4b2e2bf715..2024290460 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -193,7 +193,7 @@ namespace osu.Game.Rulesets.Scoring private void updateScore() { if (rollingMaxBaseScore != 0) - Accuracy.Value = baseScore / rollingMaxBaseScore; + Accuracy.Value = calculateAccuracyRatio(baseScore, true); TotalScore.Value = getScore(Mode.Value); } @@ -233,13 +233,13 @@ namespace osu.Game.Rulesets.Scoring } /// - /// Given a minimal set of inputs, return the computed score and accuracy for the tracked beatmap / mods combination, at the current point in time. + /// Given a minimal set of inputs, return the computed score for the tracked beatmap / mods combination, at the current point in time. /// /// The to compute the total score in. /// The maximum combo achievable in the beatmap. /// Statistics to be used for calculating accuracy, bonus score, etc. - /// The computed score and accuracy for provided inputs. - public (double score, double accuracy) GetScoreAndAccuracy(ScoringMode mode, int maxCombo, Dictionary statistics) + /// The computed score for provided inputs. + public double GetImmediateScore(ScoringMode mode, int maxCombo, Dictionary statistics) { // calculate base score from statistics pairs int computedBaseScore = 0; @@ -252,12 +252,7 @@ namespace osu.Game.Rulesets.Scoring computedBaseScore += Judgement.ToNumericResult(pair.Key) * pair.Value; } - double pointInTimeAccuracy = calculateAccuracyRatio(computedBaseScore, true); - double comboRatio = calculateComboRatio(maxCombo); - - double score = GetScore(mode, maxAchievableCombo, calculateAccuracyRatio(computedBaseScore), comboRatio, scoreResultCounts); - - return (score, pointInTimeAccuracy); + return GetScore(mode, maxAchievableCombo, calculateAccuracyRatio(computedBaseScore), calculateComboRatio(maxCombo), scoreResultCounts); } /// diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 12321de442..c10ec9e004 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -122,8 +122,8 @@ namespace osu.Game.Screens.Play.HUD if (LastHeader == null) return; - (score.Value, accuracy.Value) = processor.GetScoreAndAccuracy(mode, LastHeader.MaxCombo, LastHeader.Statistics); - + score.Value = processor.GetImmediateScore(mode, LastHeader.MaxCombo, LastHeader.Statistics); + accuracy.Value = LastHeader.Accuracy; currentCombo.Value = LastHeader.Combo; } } From e86e9bfae625351e5323c9393e011190dd58c7b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 15:32:55 +0900 Subject: [PATCH 276/328] Don't begin gameplay until all users are in a completely prepared state --- .../RealtimeMultiplayer/RealtimePlayer.cs | 39 ++++++++++++------- osu.Game/Screens/Play/Player.cs | 18 +++++++-- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index 085c52cb85..20b184bed3 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -3,12 +3,12 @@ using System; using System.Diagnostics; -using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Logging; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Scoring; @@ -33,13 +33,14 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer private IBindable isConnected; private readonly TaskCompletionSource resultsReady = new TaskCompletionSource(); - private readonly ManualResetEventSlim startedEvent = new ManualResetEventSlim(); [CanBeNull] private MultiplayerGameplayLeaderboard leaderboard; private readonly int[] userIds; + private LoadingLayer loadingDisplay; + /// /// Construct a multiplayer player. /// @@ -60,6 +61,12 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer client.MatchStarted += onMatchStarted; client.ResultsReady += onResultsReady; + ScoreProcessor.HasCompleted.BindValueChanged(completed => + { + // wait for server to tell us that results are ready (see SubmitScore implementation) + loadingDisplay.Show(); + }); + isConnected = client.IsConnected.GetBoundCopy(); isConnected.BindValueChanged(connected => { @@ -70,19 +77,20 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer } }, true); - client.ChangeState(MultiplayerUserState.Loaded) - .ContinueWith(task => failAndBail(task.Exception?.Message ?? "Server error"), TaskContinuationOptions.NotOnRanToCompletion); - - if (!startedEvent.Wait(TimeSpan.FromSeconds(30))) - { - failAndBail("Failed to start the multiplayer match in time."); - return; - } - Debug.Assert(client.Room != null); // todo: this should be implemented via a custom HUD implementation, and correctly masked to the main content area. LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(ScoreProcessor, userIds), HUDOverlay.Add); + + HUDOverlay.Add(loadingDisplay = new LoadingLayer(DrawableRuleset) { Depth = float.MaxValue }); + } + + protected override void StartGameplay() + { + // block base call, but let the server know we are ready to start. + loadingDisplay.Show(); + + client.ChangeState(MultiplayerUserState.Loaded).ContinueWith(task => failAndBail(task.Exception?.Message ?? "Server error"), TaskContinuationOptions.NotOnRanToCompletion); } private void failAndBail(string message = null) @@ -90,7 +98,6 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer if (!string.IsNullOrEmpty(message)) Logger.Log(message, LoggingTarget.Runtime, LogLevel.Important); - startedEvent.Set(); Schedule(() => PerformExit(false)); } @@ -112,7 +119,11 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer padding + HUDOverlay.TopScoringElementsHeight); } - private void onMatchStarted() => startedEvent.Set(); + private void onMatchStarted() => Scheduler.Add(() => + { + loadingDisplay.Hide(); + base.StartGameplay(); + }); private void onResultsReady() => resultsReady.SetResult(true); @@ -124,7 +135,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer // Await up to 30 seconds for results to become available (3 api request timeouts). // This is arbitrary just to not leave the player in an essentially deadlocked state if any connection issues occur. - await Task.WhenAny(resultsReady.Task, Task.Delay(TimeSpan.FromSeconds(30))); + await Task.WhenAny(resultsReady.Task, Task.Delay(TimeSpan.FromSeconds(60))); } protected override ResultsScreen CreateResults(ScoreInfo score) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 2bc84ce5d5..3f761d9e11 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -723,9 +723,6 @@ namespace osu.Game.Screens.Play storyboardReplacesBackground.Value = Beatmap.Value.Storyboard.ReplacesBackground && Beatmap.Value.Storyboard.HasDrawable; - GameplayClockContainer.Restart(); - GameplayClockContainer.FadeInFromZero(750, Easing.OutQuint); - foreach (var mod in Mods.Value.OfType()) mod.ApplyToPlayer(this); @@ -740,6 +737,21 @@ namespace osu.Game.Screens.Play mod.ApplyToTrack(musicController.CurrentTrack); updateGameplayState(); + + GameplayClockContainer.FadeInFromZero(750, Easing.OutQuint); + StartGameplay(); + } + + /// + /// Called to trigger the starting of the gameplay clock and underlying gameplay. + /// This will be called on entering the player screen once. A derived class may block the first call to this to delay the start of gameplay. + /// + protected virtual void StartGameplay() + { + if (GameplayClockContainer.GameplayClock.IsRunning) + throw new InvalidOperationException($"{nameof(StartGameplay)} should not be called when the gameplay clock is already running"); + + GameplayClockContainer.Restart(); } public override void OnSuspending(IScreen next) From 5457e4598b1a21405a183790cdd299218f789849 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 16:20:38 +0900 Subject: [PATCH 277/328] Schedule UpdateFilter calls to avoid operations occuring while at a sub screen --- osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs b/osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs index 896c215c42..3712cbe33e 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs @@ -98,7 +98,9 @@ namespace osu.Game.Screens.Multi.Lounge.Components scheduledFilterUpdate = Scheduler.AddDelayed(UpdateFilter, 200); } - protected void UpdateFilter() + protected void UpdateFilter() => Scheduler.AddOnce(updateFilter); + + private void updateFilter() { scheduledFilterUpdate?.Cancel(); From 6bd6888a938667f2050ef55c24ff4f9872a418ec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 16:29:51 +0900 Subject: [PATCH 278/328] Disallow skipping in multiplayer for now --- osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs | 1 + osu.Game/Screens/Play/Player.cs | 3 +++ osu.Game/Screens/Play/PlayerConfiguration.cs | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index b1615cc7f6..5da712bfcc 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -51,6 +51,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer { AllowPause = false, AllowRestart = false, + AllowSkippingIntro = false, }) { this.userIds = userIds; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 4bd6340751..90600b0cf1 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -381,6 +381,9 @@ namespace osu.Game.Screens.Play } }; + if (!Configuration.AllowSkippingIntro) + skipOverlay.Expire(); + if (Configuration.AllowRestart) { container.Add(new HotkeyRetryOverlay diff --git a/osu.Game/Screens/Play/PlayerConfiguration.cs b/osu.Game/Screens/Play/PlayerConfiguration.cs index 475a234679..cd30ead638 100644 --- a/osu.Game/Screens/Play/PlayerConfiguration.cs +++ b/osu.Game/Screens/Play/PlayerConfiguration.cs @@ -19,5 +19,10 @@ namespace osu.Game.Screens.Play /// Whether the player should be allowed to trigger a restart. /// public bool AllowRestart { get; set; } = true; + + /// + /// Whether the player should be allowed to skip the intro, advancing to the start of gameplay. + /// + public bool AllowSkippingIntro { get; set; } = true; } } From 3148c04fb89493c65159d177e208fc2f03b6187e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 16:53:25 +0900 Subject: [PATCH 279/328] Play a sound when starting a timeshift or multiplayer room --- osu.Game/Screens/Multi/Match/RoomSubScreen.cs | 20 +++++++++++++++++++ .../RealtimeMatchSubScreen.cs | 6 +----- .../Multi/Timeshift/TimeshiftRoomSubScreen.cs | 10 +++------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Multi/Match/RoomSubScreen.cs b/osu.Game/Screens/Multi/Match/RoomSubScreen.cs index b9d7408946..0598524e81 100644 --- a/osu.Game/Screens/Multi/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/Multi/Match/RoomSubScreen.cs @@ -4,6 +4,8 @@ using System; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Screens; using osu.Game.Audio; @@ -11,6 +13,7 @@ using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Overlays; using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Play; namespace osu.Game.Screens.Multi.Match { @@ -21,6 +24,8 @@ namespace osu.Game.Screens.Multi.Match public override bool DisallowExternalBeatmapRulesetChanges => true; + private SampleChannel sampleStart; + [Resolved(typeof(Room), nameof(Room.Playlist))] protected BindableList Playlist { get; private set; } @@ -30,8 +35,17 @@ namespace osu.Game.Screens.Multi.Match [Resolved] private BeatmapManager beatmapManager { get; set; } + [Resolved(canBeNull: true)] + protected Multiplayer Multiplayer { get; private set; } + private IBindable> managerUpdated; + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sampleStart = audio.Samples.Get(@"SongSelect/confirm-selection"); + } + protected override void LoadComplete() { base.LoadComplete(); @@ -71,6 +85,12 @@ namespace osu.Game.Screens.Multi.Match return base.OnExiting(next); } + protected void StartPlay(Func player) + { + sampleStart?.Play(); + Multiplayer?.Push(new PlayerLoader(player)); + } + private void selectedItemChanged() { updateWorkingBeatmap(); diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs index 45ac7e25d3..15d997605c 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs @@ -16,7 +16,6 @@ using osu.Game.Screens.Multi.Match; using osu.Game.Screens.Multi.Match.Components; using osu.Game.Screens.Multi.RealtimeMultiplayer.Match; using osu.Game.Screens.Multi.RealtimeMultiplayer.Participants; -using osu.Game.Screens.Play; using osu.Game.Users; using ParticipantsList = osu.Game.Screens.Multi.RealtimeMultiplayer.Participants.ParticipantsList; @@ -29,9 +28,6 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer public override string ShortTitle => "match"; - [Resolved(canBeNull: true)] - private Multiplayer multiplayer { get; set; } - [Resolved] private StatefulMultiplayerClient client { get; set; } @@ -206,7 +202,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer int[] userIds = client.Room.Users.Where(u => u.State >= MultiplayerUserState.WaitingForLoad).Select(u => u.UserID).ToArray(); - multiplayer?.Push(new PlayerLoader(() => new RealtimePlayer(SelectedItem.Value, userIds))); + StartPlay(() => new RealtimePlayer(SelectedItem.Value, userIds)); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs index fa901179e9..730ad795b2 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs @@ -15,7 +15,6 @@ using osu.Game.Screens.Multi.Match; using osu.Game.Screens.Multi.Match.Components; using osu.Game.Screens.Multi.Play; using osu.Game.Screens.Multi.Ranking; -using osu.Game.Screens.Play; using osu.Game.Screens.Select; using osu.Game.Users; using Footer = osu.Game.Screens.Multi.Match.Components.Footer; @@ -220,12 +219,9 @@ namespace osu.Game.Screens.Multi.Timeshift }, true); } - private void onStart() + private void onStart() => StartPlay(() => new TimeshiftPlayer(SelectedItem.Value) { - multiplayer?.Push(new PlayerLoader(() => new TimeshiftPlayer(SelectedItem.Value) - { - Exited = () => leaderboard.RefreshScores() - })); - } + Exited = () => leaderboard.RefreshScores() + }); } } From c35454081c931b2d1e836698d4f11186d1c7f56e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 17:17:45 +0900 Subject: [PATCH 280/328] Add sound when players change ready state --- .../TestSceneRealtimeReadyButton.cs | 31 ++++++++++++++++ .../Match/RealtimeReadyButton.cs | 36 +++++++++++++++++-- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs index e9d3ddb32d..825470846c 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs +++ b/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Framework.Platform; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Online.RealtimeMultiplayer; @@ -124,6 +125,36 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer AddAssert("match not started", () => Client.Room?.Users[0].State == MultiplayerUserState.Idle); } + [TestCase(true)] + [TestCase(false)] + public void TestManyUsersChangingState(bool isHost) + { + const int users = 10; + AddStep("setup", () => + { + Client.TransferHost(Client.Room?.Users[0].UserID ?? 0); + for (int i = 0; i < users; i++) + Client.AddUser(new User { Id = i, Username = "Another user" }); + }); + + if (!isHost) + AddStep("transfer host", () => Client.TransferHost(2)); + + addClickButtonStep(); + + AddRepeatStep("change user ready state", () => + { + Client.ChangeUserState(RNG.Next(0, users), RNG.NextBool() ? MultiplayerUserState.Ready : MultiplayerUserState.Idle); + }, 20); + + AddRepeatStep("ready all users", () => + { + var nextUnready = Client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle); + if (nextUnready != null) + Client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready); + }, users); + } + private void addClickButtonStep() => AddStep("click button", () => { InputManager.MoveMouseTo(button); diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs index 5bead2b271..962c6bbead 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs @@ -5,6 +5,8 @@ using System.Diagnostics; using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Extensions; @@ -31,8 +33,12 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match [Resolved] private OsuColour colours { get; set; } + private SampleChannel sampleReadyCount; + private readonly ButtonWithTrianglesExposed button; + private int countReady; + public RealtimeReadyButton() { InternalChild = button = new ButtonWithTrianglesExposed @@ -44,6 +50,12 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match }; } + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sampleReadyCount = audio.Samples.Get(@"SongSelect/select-difficulty"); + } + protected override void OnRoomChanged() { base.OnRoomChanged(); @@ -60,6 +72,10 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match Debug.Assert(Room != null); + int newCountReady = Room.Users.Count(u => u.State == MultiplayerUserState.Ready); + + string countText = $"({newCountReady} / {Room.Users.Count} ready)"; + switch (localUser.State) { case MultiplayerUserState.Idle: @@ -70,18 +86,32 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match case MultiplayerUserState.Ready: if (Room?.Host?.Equals(localUser) == true) { - int countReady = Room.Users.Count(u => u.State == MultiplayerUserState.Ready); - button.Text = $"Start match ({countReady} / {Room.Users.Count} ready)"; + button.Text = $"Start match {countText}"; updateButtonColour(true); } else { - button.Text = "Waiting for host..."; + button.Text = $"Waiting for host... {countText}"; updateButtonColour(false); } break; } + + if (newCountReady != countReady) + { + countReady = newCountReady; + Scheduler.AddOnce(playSound); + } + } + + private void playSound() + { + if (sampleReadyCount != null) + { + sampleReadyCount.Frequency.Value = 0.77f + countReady * 0.06f; + sampleReadyCount.Play(); + } } private void updateButtonColour(bool green) From eb795a212730b87f947f35eb25586a802563b543 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 17:58:38 +0900 Subject: [PATCH 281/328] Move all endpoint information to a configuration class --- ...TestSceneMultiplayerGameplayLeaderboard.cs | 2 ++ .../Visual/Gameplay/TestSceneSpectator.cs | 6 ++++ .../DevelopmentOsuConfigManager.cs | 19 ++++++++++++ osu.Game/Online/API/APIAccess.cs | 18 ++++------- .../DevelopmentEndpointConfiguration.cs | 17 +++++++++++ osu.Game/Online/EndpointConfiguration.cs | 30 +++++++++++++++++++ .../Online/ProductionEndpointConfiguration.cs | 17 +++++++++++ .../RealtimeMultiplayerClient.cs | 13 ++++---- .../Spectator/SpectatorStreamingClient.cs | 13 ++++---- osu.Game/OsuGameBase.cs | 18 +++++++---- 10 files changed, 124 insertions(+), 29 deletions(-) create mode 100644 osu.Game/Configuration/DevelopmentOsuConfigManager.cs create mode 100644 osu.Game/Online/DevelopmentEndpointConfiguration.cs create mode 100644 osu.Game/Online/EndpointConfiguration.cs create mode 100644 osu.Game/Online/ProductionEndpointConfiguration.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs index e42ddeb35e..8078c7b994 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneMultiplayerGameplayLeaderboard.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Database; +using osu.Game.Online; using osu.Game.Online.Spectator; using osu.Game.Replays.Legacy; using osu.Game.Rulesets.Osu.Scoring; @@ -87,6 +88,7 @@ namespace osu.Game.Tests.Visual.Gameplay private readonly int totalUsers; public TestMultiplayerStreaming(int totalUsers) + : base(new DevelopmentEndpointConfiguration()) { this.totalUsers = totalUsers; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs index 1fdff99da6..26524f07da 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs @@ -12,6 +12,7 @@ using osu.Framework.Screens; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Online; using osu.Game.Online.Spectator; using osu.Game.Replays.Legacy; using osu.Game.Rulesets.Osu; @@ -238,6 +239,11 @@ namespace osu.Game.Tests.Visual.Gameplay private int beatmapId; + public TestSpectatorStreamingClient() + : base(new DevelopmentEndpointConfiguration()) + { + } + protected override Task Connect() { return Task.CompletedTask; diff --git a/osu.Game/Configuration/DevelopmentOsuConfigManager.cs b/osu.Game/Configuration/DevelopmentOsuConfigManager.cs new file mode 100644 index 0000000000..ff19dd874c --- /dev/null +++ b/osu.Game/Configuration/DevelopmentOsuConfigManager.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Platform; +using osu.Framework.Testing; + +namespace osu.Game.Configuration +{ + [ExcludeFromDynamicCompile] + public class DevelopmentOsuConfigManager : OsuConfigManager + { + protected override string Filename => base.Filename.Replace(".ini", ".dev.ini"); + + public DevelopmentOsuConfigManager(Storage storage) + : base(storage) + { + } + } +} diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index ca457ccf71..49c815b2d3 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -26,18 +26,10 @@ namespace osu.Game.Online.API private readonly OAuth authentication; -#if DEBUG - public string Endpoint => @"https://dev.ppy.sh"; - private const string client_secret = @"3LP2mhUrV89xxzD1YKNndXHEhWWCRLPNKioZ9ymT"; -#else - public string Endpoint => @"https://osu.ppy.sh"; - private const string client_secret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"; -#endif - - private const string client_id = @"5"; - private readonly Queue queue = new Queue(); + public string Endpoint { get; } + /// /// The username/email provided by the user when initiating a login. /// @@ -61,11 +53,13 @@ namespace osu.Game.Online.API private readonly Logger log; - public APIAccess(OsuConfigManager config) + public APIAccess(OsuConfigManager config, EndpointConfiguration endpointConfiguration) { this.config = config; - authentication = new OAuth(client_id, client_secret, Endpoint); + Endpoint = endpointConfiguration.APIEndpoint; + + authentication = new OAuth(endpointConfiguration.APIClientID, endpointConfiguration.APIClientSecret, Endpoint); log = Logger.GetLogger(LoggingTarget.Network); ProvidedUsername = config.Get(OsuSetting.Username); diff --git a/osu.Game/Online/DevelopmentEndpointConfiguration.cs b/osu.Game/Online/DevelopmentEndpointConfiguration.cs new file mode 100644 index 0000000000..5e4105f5fd --- /dev/null +++ b/osu.Game/Online/DevelopmentEndpointConfiguration.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Online +{ + public class DevelopmentEndpointConfiguration : EndpointConfiguration + { + public DevelopmentEndpointConfiguration() + { + APIEndpoint = @"https://dev.ppy.sh"; + APIClientSecret = @"3LP2mhUrV89xxzD1YKNndXHEhWWCRLPNKioZ9ymT"; + APIClientID = "5"; + SpectatorEndpoint = $"{APIEndpoint}/spectator"; + MultiplayerEndpoint = $"{APIEndpoint}/multiplayer"; + } + } +} diff --git a/osu.Game/Online/EndpointConfiguration.cs b/osu.Game/Online/EndpointConfiguration.cs new file mode 100644 index 0000000000..a8b1a84e62 --- /dev/null +++ b/osu.Game/Online/EndpointConfiguration.cs @@ -0,0 +1,30 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Online +{ + /// + /// Holds configuration for API endpoints. + /// + public class EndpointConfiguration + { + /// + /// The endpoint for the main (osu-web) API. + /// + public string APIEndpoint { get; set; } + + /// + /// The OAuth client secret. + /// + public string APIClientSecret { get; set; } + + /// + /// The OAuth client ID. + /// + public string APIClientID { get; set; } + + public string SpectatorEndpoint { get; set; } + + public string MultiplayerEndpoint { get; set; } + } +} diff --git a/osu.Game/Online/ProductionEndpointConfiguration.cs b/osu.Game/Online/ProductionEndpointConfiguration.cs new file mode 100644 index 0000000000..f5c71ef737 --- /dev/null +++ b/osu.Game/Online/ProductionEndpointConfiguration.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Online +{ + public class ProductionEndpointConfiguration : EndpointConfiguration + { + public ProductionEndpointConfiguration() + { + APIEndpoint = @"https://osu.ppy.sh"; + APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"; + APIClientID = "5"; + SpectatorEndpoint = "https://spectator.ppy.sh/spectator"; + MultiplayerEndpoint = "https://spectator.ppy.sh/multiplayer"; + } + } +} diff --git a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs index 4ec5b9af40..0e2b4855da 100644 --- a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs @@ -19,12 +19,6 @@ namespace osu.Game.Online.RealtimeMultiplayer { public class RealtimeMultiplayerClient : StatefulMultiplayerClient { -#if DEBUG - private const string endpoint = "https://dev.ppy.sh/multiplayer"; -#else - private const string endpoint = "https://spectator.ppy.sh/multiplayer"; -#endif - public override IBindable IsConnected => isConnected; private readonly Bindable isConnected = new Bindable(); @@ -35,6 +29,13 @@ namespace osu.Game.Online.RealtimeMultiplayer private HubConnection? connection; + private readonly string endpoint; + + public RealtimeMultiplayerClient(EndpointConfiguration endpoints) + { + endpoint = endpoints.MultiplayerEndpoint; + } + [BackgroundDependencyLoader] private void load() { diff --git a/osu.Game/Online/Spectator/SpectatorStreamingClient.cs b/osu.Game/Online/Spectator/SpectatorStreamingClient.cs index c9203b595e..1432fd1c98 100644 --- a/osu.Game/Online/Spectator/SpectatorStreamingClient.cs +++ b/osu.Game/Online/Spectator/SpectatorStreamingClient.cs @@ -81,6 +81,13 @@ namespace osu.Game.Online.Spectator /// public event Action OnUserFinishedPlaying; + private readonly string endpoint; + + public SpectatorStreamingClient(EndpointConfiguration endpoints) + { + endpoint = endpoints.SpectatorEndpoint; + } + [BackgroundDependencyLoader] private void load() { @@ -104,12 +111,6 @@ namespace osu.Game.Online.Spectator } } -#if DEBUG - private const string endpoint = "https://dev.ppy.sh/spectator"; -#else - private const string endpoint = "https://spectator.ppy.sh/spectator"; -#endif - protected virtual async Task Connect() { if (connection != null) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index eb27821d82..bdc9e5eb7b 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -30,6 +30,7 @@ using osu.Game.Database; using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.IO; +using osu.Game.Online; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Online.Spectator; using osu.Game.Overlays; @@ -54,6 +55,8 @@ namespace osu.Game public const int SAMPLE_CONCURRENCY = 6; + public bool UseDevelopmentServer { get; } + protected OsuConfigManager LocalConfig; protected BeatmapManager BeatmapManager; @@ -132,6 +135,7 @@ namespace osu.Game public OsuGameBase() { + UseDevelopmentServer = DebugUtils.IsDebugBuild; Name = @"osu!lazer"; } @@ -170,7 +174,7 @@ namespace osu.Game dependencies.Cache(largeStore); dependencies.CacheAs(this); - dependencies.Cache(LocalConfig); + dependencies.CacheAs(LocalConfig); AddFont(Resources, @"Fonts/osuFont"); @@ -210,10 +214,12 @@ namespace osu.Game } }); - dependencies.CacheAs(API ??= new APIAccess(LocalConfig)); + EndpointConfiguration endpoints = UseDevelopmentServer ? (EndpointConfiguration)new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration(); - dependencies.CacheAs(spectatorStreaming = new SpectatorStreamingClient()); - dependencies.CacheAs(multiplayerClient = new RealtimeMultiplayerClient()); + dependencies.CacheAs(API ??= new APIAccess(LocalConfig, endpoints)); + + dependencies.CacheAs(spectatorStreaming = new SpectatorStreamingClient(endpoints)); + dependencies.CacheAs(multiplayerClient = new RealtimeMultiplayerClient(endpoints)); var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures); @@ -369,7 +375,9 @@ namespace osu.Game // may be non-null for certain tests Storage ??= host.Storage; - LocalConfig ??= new OsuConfigManager(Storage); + LocalConfig ??= UseDevelopmentServer + ? new DevelopmentOsuConfigManager(Storage) + : new OsuConfigManager(Storage); } protected override Storage CreateStorage(GameHost host, Storage defaultStorage) => new OsuStorage(host, defaultStorage); From 323da82477304456af0c9a4bd04e089061c6ea3e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 18:11:40 +0900 Subject: [PATCH 282/328] Add website root URL and update most links to use it For what it's worth, I intentionally didn't include news / changelog / supporter, because these should never change. --- osu.Game/Online/API/APIAccess.cs | 11 +++++++---- osu.Game/Online/API/APIRequest.cs | 2 +- osu.Game/Online/API/DummyAPIAccess.cs | 4 +++- osu.Game/Online/API/IAPIProvider.cs | 7 ++++++- osu.Game/Online/Chat/NowPlayingCommand.cs | 2 +- .../Online/DevelopmentEndpointConfiguration.cs | 6 +++--- osu.Game/Online/EndpointConfiguration.cs | 17 ++++++++++++++--- .../Online/ProductionEndpointConfiguration.cs | 6 +++--- .../RealtimeMultiplayerClient.cs | 2 +- .../Spectator/SpectatorStreamingClient.cs | 2 +- osu.Game/OsuGame.cs | 2 +- osu.Game/Overlays/BeatmapSet/Header.cs | 6 +++++- .../Profile/Header/BottomHeaderContainer.cs | 6 +++++- .../Profile/Header/TopHeaderContainer.cs | 6 +++++- .../Sections/Recent/DrawableRecentActivity.cs | 2 +- 15 files changed, 57 insertions(+), 24 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 49c815b2d3..133ba22406 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -28,7 +28,9 @@ namespace osu.Game.Online.API private readonly Queue queue = new Queue(); - public string Endpoint { get; } + public string APIEndpointUrl { get; } + + public string WebsiteRootUrl { get; } /// /// The username/email provided by the user when initiating a login. @@ -57,9 +59,10 @@ namespace osu.Game.Online.API { this.config = config; - Endpoint = endpointConfiguration.APIEndpoint; + APIEndpointUrl = endpointConfiguration.APIEndpointUrl; + WebsiteRootUrl = endpointConfiguration.WebsiteRootUrl; - authentication = new OAuth(endpointConfiguration.APIClientID, endpointConfiguration.APIClientSecret, Endpoint); + authentication = new OAuth(endpointConfiguration.APIClientID, endpointConfiguration.APIClientSecret, APIEndpointUrl); log = Logger.GetLogger(LoggingTarget.Network); ProvidedUsername = config.Get(OsuSetting.Username); @@ -245,7 +248,7 @@ namespace osu.Game.Online.API var req = new RegistrationRequest { - Url = $@"{Endpoint}/users", + Url = $@"{APIEndpointUrl}/users", Method = HttpMethod.Post, Username = username, Email = email, diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index 6912d9b629..a7174324d8 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -57,7 +57,7 @@ namespace osu.Game.Online.API protected virtual WebRequest CreateWebRequest() => new OsuWebRequest(Uri); - protected virtual string Uri => $@"{API.Endpoint}/api/v2/{Target}"; + protected virtual string Uri => $@"{API.APIEndpointUrl}/api/v2/{Target}"; protected APIAccess API; protected WebRequest WebRequest; diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index 265298270c..3e996ac97f 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -28,7 +28,9 @@ namespace osu.Game.Online.API public string ProvidedUsername => LocalUser.Value.Username; - public string Endpoint => "http://localhost"; + public string APIEndpointUrl => "http://localhost"; + + public string WebsiteRootUrl => "http://localhost"; /// /// Provide handling logic for an arbitrary API request. diff --git a/osu.Game/Online/API/IAPIProvider.cs b/osu.Game/Online/API/IAPIProvider.cs index 3a444460f2..4407f1f55e 100644 --- a/osu.Game/Online/API/IAPIProvider.cs +++ b/osu.Game/Online/API/IAPIProvider.cs @@ -46,7 +46,12 @@ namespace osu.Game.Online.API /// /// The URL endpoint for this API. Does not include a trailing slash. /// - string Endpoint { get; } + string APIEndpointUrl { get; } + + /// + /// The root URL of of the website, excluding the trailing slash. + /// + public string WebsiteRootUrl { get; } /// /// The current connection state of the API. diff --git a/osu.Game/Online/Chat/NowPlayingCommand.cs b/osu.Game/Online/Chat/NowPlayingCommand.cs index c0b54812b6..926709694b 100644 --- a/osu.Game/Online/Chat/NowPlayingCommand.cs +++ b/osu.Game/Online/Chat/NowPlayingCommand.cs @@ -46,7 +46,7 @@ namespace osu.Game.Online.Chat break; } - var beatmapString = beatmap.OnlineBeatmapID.HasValue ? $"[https://osu.ppy.sh/b/{beatmap.OnlineBeatmapID} {beatmap}]" : beatmap.ToString(); + var beatmapString = beatmap.OnlineBeatmapID.HasValue ? $"[{api.WebsiteRootUrl}/b/{beatmap.OnlineBeatmapID} {beatmap}]" : beatmap.ToString(); channelManager.PostMessage($"is {verb} {beatmapString}", true); Expire(); diff --git a/osu.Game/Online/DevelopmentEndpointConfiguration.cs b/osu.Game/Online/DevelopmentEndpointConfiguration.cs index 5e4105f5fd..69531dbe1b 100644 --- a/osu.Game/Online/DevelopmentEndpointConfiguration.cs +++ b/osu.Game/Online/DevelopmentEndpointConfiguration.cs @@ -7,11 +7,11 @@ namespace osu.Game.Online { public DevelopmentEndpointConfiguration() { - APIEndpoint = @"https://dev.ppy.sh"; + WebsiteRootUrl = APIEndpointUrl = @"https://dev.ppy.sh"; APIClientSecret = @"3LP2mhUrV89xxzD1YKNndXHEhWWCRLPNKioZ9ymT"; APIClientID = "5"; - SpectatorEndpoint = $"{APIEndpoint}/spectator"; - MultiplayerEndpoint = $"{APIEndpoint}/multiplayer"; + SpectatorEndpointUrl = $"{APIEndpointUrl}/spectator"; + MultiplayerEndpointUrl = $"{APIEndpointUrl}/multiplayer"; } } } diff --git a/osu.Game/Online/EndpointConfiguration.cs b/osu.Game/Online/EndpointConfiguration.cs index a8b1a84e62..e347d3c653 100644 --- a/osu.Game/Online/EndpointConfiguration.cs +++ b/osu.Game/Online/EndpointConfiguration.cs @@ -8,10 +8,15 @@ namespace osu.Game.Online /// public class EndpointConfiguration { + /// + /// The base URL for the website. + /// + public string WebsiteRootUrl { get; set; } + /// /// The endpoint for the main (osu-web) API. /// - public string APIEndpoint { get; set; } + public string APIEndpointUrl { get; set; } /// /// The OAuth client secret. @@ -23,8 +28,14 @@ namespace osu.Game.Online /// public string APIClientID { get; set; } - public string SpectatorEndpoint { get; set; } + /// + /// The endpoint for the SignalR spectator server. + /// + public string SpectatorEndpointUrl { get; set; } - public string MultiplayerEndpoint { get; set; } + /// + /// The endpoint for the SignalR multiplayer server. + /// + public string MultiplayerEndpointUrl { get; set; } } } diff --git a/osu.Game/Online/ProductionEndpointConfiguration.cs b/osu.Game/Online/ProductionEndpointConfiguration.cs index f5c71ef737..c6ddc03564 100644 --- a/osu.Game/Online/ProductionEndpointConfiguration.cs +++ b/osu.Game/Online/ProductionEndpointConfiguration.cs @@ -7,11 +7,11 @@ namespace osu.Game.Online { public ProductionEndpointConfiguration() { - APIEndpoint = @"https://osu.ppy.sh"; + WebsiteRootUrl = APIEndpointUrl = @"https://osu.ppy.sh"; APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"; APIClientID = "5"; - SpectatorEndpoint = "https://spectator.ppy.sh/spectator"; - MultiplayerEndpoint = "https://spectator.ppy.sh/multiplayer"; + SpectatorEndpointUrl = "https://spectator.ppy.sh/spectator"; + MultiplayerEndpointUrl = "https://spectator.ppy.sh/multiplayer"; } } } diff --git a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs index 0e2b4855da..bfc89df483 100644 --- a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs +++ b/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs @@ -33,7 +33,7 @@ namespace osu.Game.Online.RealtimeMultiplayer public RealtimeMultiplayerClient(EndpointConfiguration endpoints) { - endpoint = endpoints.MultiplayerEndpoint; + endpoint = endpoints.MultiplayerEndpointUrl; } [BackgroundDependencyLoader] diff --git a/osu.Game/Online/Spectator/SpectatorStreamingClient.cs b/osu.Game/Online/Spectator/SpectatorStreamingClient.cs index 1432fd1c98..344b73f3d9 100644 --- a/osu.Game/Online/Spectator/SpectatorStreamingClient.cs +++ b/osu.Game/Online/Spectator/SpectatorStreamingClient.cs @@ -85,7 +85,7 @@ namespace osu.Game.Online.Spectator public SpectatorStreamingClient(EndpointConfiguration endpoints) { - endpoint = endpoints.SpectatorEndpoint; + endpoint = endpoints.SpectatorEndpointUrl; } [BackgroundDependencyLoader] diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index bb51c55551..17831ed26b 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -294,7 +294,7 @@ namespace osu.Game public void OpenUrlExternally(string url) => waitForReady(() => externalLinkOpener, _ => { if (url.StartsWith('/')) - url = $"{API.Endpoint}{url}"; + url = $"{API.APIEndpointUrl}{url}"; externalLinkOpener.OpenUrlExternally(url); }); diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs index 06e31277dd..321e496511 100644 --- a/osu.Game/Overlays/BeatmapSet/Header.cs +++ b/osu.Game/Overlays/BeatmapSet/Header.cs @@ -15,6 +15,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online; +using osu.Game.Online.API; using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Overlays.BeatmapSet.Buttons; using osu.Game.Rulesets; @@ -40,6 +41,9 @@ namespace osu.Game.Overlays.BeatmapSet public bool DownloadButtonsVisible => downloadButtonsContainer.Any(); + [Resolved] + private IAPIProvider api { get; set; } + public BeatmapRulesetSelector RulesetSelector => beatmapSetHeader.RulesetSelector; public readonly BeatmapPicker Picker; @@ -213,7 +217,7 @@ namespace osu.Game.Overlays.BeatmapSet Picker.Beatmap.ValueChanged += b => { Details.Beatmap = b.NewValue; - externalLink.Link = $@"https://osu.ppy.sh/beatmapsets/{BeatmapSet.Value?.OnlineBeatmapSetID}#{b.NewValue?.Ruleset.ShortName}/{b.NewValue?.OnlineBeatmapID}"; + externalLink.Link = $@"{api.WebsiteRootUrl}/beatmapsets/{BeatmapSet.Value?.OnlineBeatmapSetID}#{b.NewValue?.Ruleset.ShortName}/{b.NewValue?.OnlineBeatmapID}"; }; } diff --git a/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs index ebee377a51..2925107766 100644 --- a/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Online.API; using osu.Game.Users; using osuTK; using osuTK.Graphics; @@ -27,6 +28,9 @@ namespace osu.Game.Overlays.Profile.Header private Color4 iconColour; + [Resolved] + private IAPIProvider api { get; set; } + public BottomHeaderContainer() { AutoSizeAxes = Axes.Y; @@ -109,7 +113,7 @@ namespace osu.Game.Overlays.Profile.Header } topLinkContainer.AddText("Contributed "); - topLinkContainer.AddLink($@"{user.PostCount:#,##0} forum posts", $"https://osu.ppy.sh/users/{user.Id}/posts", creationParameters: embolden); + topLinkContainer.AddLink($@"{user.PostCount:#,##0} forum posts", $"{api.WebsiteRootUrl}/users/{user.Id}/posts", creationParameters: embolden); string websiteWithoutProtocol = user.Website; diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index 2cc1f6533f..e0642d650c 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; using osu.Game.Overlays.Profile.Header.Components; using osu.Game.Users; using osu.Game.Users.Drawables; @@ -23,6 +24,9 @@ namespace osu.Game.Overlays.Profile.Header public readonly Bindable User = new Bindable(); + [Resolved] + private IAPIProvider api { get; set; } + private SupporterIcon supporterTag; private UpdateableAvatar avatar; private OsuSpriteText usernameText; @@ -166,7 +170,7 @@ namespace osu.Game.Overlays.Profile.Header { avatar.User = user; usernameText.Text = user?.Username ?? string.Empty; - openUserExternally.Link = $@"https://osu.ppy.sh/users/{user?.Id ?? 0}"; + openUserExternally.Link = $@"{api.WebsiteRootUrl}/users/{user?.Id ?? 0}"; userFlag.Country = user?.Country; userCountryText.Text = user?.Country?.FullName ?? "Alien"; supporterTag.SupportLevel = user?.SupportLevel ?? 0; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 8782e82642..49b46f7e7a 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -216,7 +216,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent private void addBeatmapsetLink() => content.AddLink(activity.Beatmapset?.Title, LinkAction.OpenBeatmapSet, getLinkArgument(activity.Beatmapset?.Url), creationParameters: t => t.Font = getLinkFont()); - private string getLinkArgument(string url) => MessageFormatter.GetLinkDetails($"{api.Endpoint}{url}").Argument; + private string getLinkArgument(string url) => MessageFormatter.GetLinkDetails($"{api.APIEndpointUrl}{url}").Argument; private FontUsage getLinkFont(FontWeight fontWeight = FontWeight.Regular) => OsuFont.GetFont(size: font_size, weight: fontWeight, italics: true); From 261c250b46dae0db37151601a2d789c0e789b5f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 24 Dec 2020 11:33:49 +0100 Subject: [PATCH 283/328] Update outdated comment --- osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index 20b184bed3..b1179ea7cd 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -133,7 +133,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer await client.ChangeState(MultiplayerUserState.FinishedPlay); - // Await up to 30 seconds for results to become available (3 api request timeouts). + // Await up to 60 seconds for results to become available (6 api request timeouts). // This is arbitrary just to not leave the player in an essentially deadlocked state if any connection issues occur. await Task.WhenAny(resultsReady.Task, Task.Delay(TimeSpan.FromSeconds(60))); } From 40b9d1bc5ef7b3f0c63766a7478f278aaa565cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 24 Dec 2020 12:45:01 +0100 Subject: [PATCH 284/328] Invert if & early-return to reduce nesting --- .../RealtimeMultiplayer/Match/RealtimeReadyButton.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs index 962c6bbead..be405feef1 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs @@ -107,11 +107,11 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match private void playSound() { - if (sampleReadyCount != null) - { - sampleReadyCount.Frequency.Value = 0.77f + countReady * 0.06f; - sampleReadyCount.Play(); - } + if (sampleReadyCount == null) + return; + + sampleReadyCount.Frequency.Value = 0.77f + countReady * 0.06f; + sampleReadyCount.Play(); } private void updateButtonColour(bool green) From 66a23c22e5580f6866db87aebfe503d195a2a8dd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 21:28:21 +0900 Subject: [PATCH 285/328] Fix various tests failing due to dependence on specific online data --- .../Online/TestSceneChangelogOverlay.cs | 5 +- .../Online/TestSceneNowPlayingCommand.cs | 2 +- .../Requests/Responses/APIChangelogEntry.cs | 3 +- osu.Game/Overlays/Changelog/ChangelogBuild.cs | 49 ++++++++++--------- osu.Game/Overlays/ChangelogOverlay.cs | 1 + 5 files changed, 33 insertions(+), 27 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs index 02f6de2269..998e42b478 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs @@ -41,6 +41,7 @@ namespace osu.Game.Tests.Visual.Online } [Test] + [Ignore("needs to be updated to not be so server dependent")] public void ShowWithBuild() { AddStep(@"Show with Lazer 2018.712.0", () => @@ -49,7 +50,7 @@ namespace osu.Game.Tests.Visual.Online { Version = "2018.712.0", DisplayVersion = "2018.712.0", - UpdateStream = new APIUpdateStream { Id = 7, Name = OsuGameBase.CLIENT_STREAM_NAME }, + UpdateStream = new APIUpdateStream { Id = 5, Name = OsuGameBase.CLIENT_STREAM_NAME }, ChangelogEntries = new List { new APIChangelogEntry @@ -64,7 +65,7 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep(@"wait for streams", () => changelog.Streams?.Count > 0); AddAssert(@"correct build displayed", () => changelog.Current.Value.Version == "2018.712.0"); - AddAssert(@"correct stream selected", () => changelog.Header.Streams.Current.Value.Id == 7); + AddAssert(@"correct stream selected", () => changelog.Header.Streams.Current.Value.Id == 5); } [Test] diff --git a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs index 0324da6cf5..64e80e9f02 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs @@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Run command", () => Add(new NowPlayingCommand())); if (hasOnlineId) - AddAssert("Check link presence", () => postTarget.LastMessage.Contains("https://osu.ppy.sh/b/1234")); + AddAssert("Check link presence", () => postTarget.LastMessage.Contains("/b/1234")); else AddAssert("Check link not present", () => !postTarget.LastMessage.Contains("https://")); } diff --git a/osu.Game/Online/API/Requests/Responses/APIChangelogEntry.cs b/osu.Game/Online/API/Requests/Responses/APIChangelogEntry.cs index f949ab5da5..1ff7523ba6 100644 --- a/osu.Game/Online/API/Requests/Responses/APIChangelogEntry.cs +++ b/osu.Game/Online/API/Requests/Responses/APIChangelogEntry.cs @@ -48,6 +48,7 @@ namespace osu.Game.Online.API.Requests.Responses public enum ChangelogEntryType { Add, - Fix + Fix, + Misc } } diff --git a/osu.Game/Overlays/Changelog/ChangelogBuild.cs b/osu.Game/Overlays/Changelog/ChangelogBuild.cs index 48bf6c2ddd..65ff0fef92 100644 --- a/osu.Game/Overlays/Changelog/ChangelogBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogBuild.cs @@ -131,33 +131,36 @@ namespace osu.Game.Overlays.Changelog t.Padding = new MarginPadding { Left = 10 }; }); - if (entry.GithubUser.UserId != null) + if (entry.GithubUser != null) { - title.AddUserLink(new User + if (entry.GithubUser.UserId != null) { - Username = entry.GithubUser.OsuUsername, - Id = entry.GithubUser.UserId.Value - }, t => + title.AddUserLink(new User + { + Username = entry.GithubUser.OsuUsername, + Id = entry.GithubUser.UserId.Value + }, t => + { + t.Font = fontMedium; + t.Colour = entryColour; + }); + } + else if (entry.GithubUser.GithubUrl != null) { - t.Font = fontMedium; - t.Colour = entryColour; - }); - } - else if (entry.GithubUser.GithubUrl != null) - { - title.AddLink(entry.GithubUser.DisplayName, entry.GithubUser.GithubUrl, t => + title.AddLink(entry.GithubUser.DisplayName, entry.GithubUser.GithubUrl, t => + { + t.Font = fontMedium; + t.Colour = entryColour; + }); + } + else { - t.Font = fontMedium; - t.Colour = entryColour; - }); - } - else - { - title.AddText(entry.GithubUser.DisplayName, t => - { - t.Font = fontMedium; - t.Colour = entryColour; - }); + title.AddText(entry.GithubUser.DisplayName, t => + { + t.Font = fontMedium; + t.Colour = entryColour; + }); + } } ChangelogEntries.Add(titleContainer); diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs index c7e9a86fa4..f591b1d427 100644 --- a/osu.Game/Overlays/ChangelogOverlay.cs +++ b/osu.Game/Overlays/ChangelogOverlay.cs @@ -86,6 +86,7 @@ namespace osu.Game.Overlays } public void ShowListing() + { Current.Value = null; Show(); From 4270c29f6083cea4abc28f9d82aef3bc6c5c222a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 24 Dec 2020 13:42:08 +0100 Subject: [PATCH 286/328] Trim stray newline --- osu.Game/Overlays/ChangelogOverlay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs index f591b1d427..c7e9a86fa4 100644 --- a/osu.Game/Overlays/ChangelogOverlay.cs +++ b/osu.Game/Overlays/ChangelogOverlay.cs @@ -86,7 +86,6 @@ namespace osu.Game.Overlays } public void ShowListing() - { Current.Value = null; Show(); From d5c348b568096b1a10fc2d2a04a0b2dd922c20e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 24 Dec 2020 13:44:46 +0100 Subject: [PATCH 287/328] Remove explicit public access modifier from interface --- osu.Game/Online/API/IAPIProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/IAPIProvider.cs b/osu.Game/Online/API/IAPIProvider.cs index 4407f1f55e..1951dfaf40 100644 --- a/osu.Game/Online/API/IAPIProvider.cs +++ b/osu.Game/Online/API/IAPIProvider.cs @@ -51,7 +51,7 @@ namespace osu.Game.Online.API /// /// The root URL of of the website, excluding the trailing slash. /// - public string WebsiteRootUrl { get; } + string WebsiteRootUrl { get; } /// /// The current connection state of the API. From f991448a3e6f359efa277f4491c472421c311ca9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 21:49:38 +0900 Subject: [PATCH 288/328] Re-sort the leaderboard order a maximum of once a second --- .../Screens/Play/HUD/GameplayLeaderboard.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index cab1cbd3f1..e33cc05e64 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using osu.Framework.Caching; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Users; @@ -12,6 +13,8 @@ namespace osu.Game.Screens.Play.HUD { public class GameplayLeaderboard : FillFlowContainer { + private readonly Cached sorting = new Cached(); + public GameplayLeaderboard() { Width = GameplayLeaderboardScore.EXTENDED_WIDTH + GameplayLeaderboardScore.SHEAR_WIDTH; @@ -24,6 +27,13 @@ namespace osu.Game.Screens.Play.HUD LayoutEasing = Easing.OutQuint; } + protected override void LoadComplete() + { + base.LoadComplete(); + + Scheduler.AddDelayed(sort, 1000, true); + } + /// /// Adds a player to the leaderboard. /// @@ -41,7 +51,7 @@ namespace osu.Game.Screens.Play.HUD }; base.Add(drawable); - drawable.TotalScore.BindValueChanged(_ => Scheduler.AddOnce(sort), true); + drawable.TotalScore.BindValueChanged(_ => sorting.Invalidate(), true); Height = Count * (GameplayLeaderboardScore.PANEL_HEIGHT + Spacing.Y); @@ -55,6 +65,9 @@ namespace osu.Game.Screens.Play.HUD private void sort() { + if (sorting.IsValid) + return; + var orderedByScore = this.OrderByDescending(i => i.TotalScore.Value).ToList(); for (int i = 0; i < Count; i++) @@ -62,6 +75,8 @@ namespace osu.Game.Screens.Play.HUD SetLayoutPosition(orderedByScore[i], i); orderedByScore[i].ScorePosition = i + 1; } + + sorting.Validate(); } } } From aec25e2d73079043d810fbc97da19441c1b1c581 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 21:53:18 +0900 Subject: [PATCH 289/328] Rename "timeshift" to "playlists" This only covers the user-facing instances. Code and class name changes will happen once things have calmed down. --- osu.Game/Screens/Menu/ButtonSystem.cs | 2 +- osu.Game/Screens/Menu/Disclaimer.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index badfa3f693..5af6517f49 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -125,7 +125,7 @@ namespace osu.Game.Screens.Menu { buttonsPlay.Add(new Button(@"solo", @"button-solo-select", FontAwesome.Solid.User, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P)); buttonsPlay.Add(new Button(@"multi", @"button-generic-select", FontAwesome.Solid.Users, new Color4(94, 63, 186, 255), onMultiplayer, 0, Key.M)); - buttonsPlay.Add(new Button(@"timeshift", @"button-generic-select", OsuIcon.Charts, new Color4(94, 63, 186, 255), onTimeshift, 0, Key.L)); + buttonsPlay.Add(new Button(@"playlists", @"button-generic-select", OsuIcon.Charts, new Color4(94, 63, 186, 255), onTimeshift, 0, Key.L)); buttonsPlay.ForEach(b => b.VisibleState = ButtonSystemState.Play); buttonsTopLevel.Add(new Button(@"play", @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P)); diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index ceec12c967..9c7206d259 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -208,7 +208,7 @@ namespace osu.Game.Screens.Menu "Most of the web content (profiles, rankings, etc.) are available natively in-game from the icons on the toolbar!", "Get more details, hide or delete a beatmap by right-clicking on its panel at song select!", "All delete operations are temporary until exiting. Restore accidentally deleted content from the maintenance settings!", - "Check out the \"timeshift\" multiplayer system, which has local permanent leaderboards and playlist support!", + "Check out the \"playlist\" system, which lets users create their own custom and permanent leaderboards!", "Toggle advanced frame / thread statistics with Ctrl-F11!", "Take a look under the hood at performance counters and enable verbose performance logging with Ctrl-F2!", }; From 3a46e210d48d903bc631021979518f1fcab59293 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 21:59:10 +0900 Subject: [PATCH 290/328] Change low-hanging references of "room" to "playlist" --- osu.Game/Screens/Multi/Multiplayer.cs | 6 +++--- .../Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs | 2 +- .../Screens/Multi/Timeshift/CreateTimeshiftRoomButton.cs | 2 +- osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs | 6 ++++++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index a7d40a89d3..585ac71189 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -59,7 +59,7 @@ namespace osu.Game.Screens.Multi private OsuGameBase game { get; set; } [Resolved] - private IAPIProvider api { get; set; } + protected IAPIProvider API { get; private set; } [Resolved(CanBeNull = true)] private OsuLogo logo { get; set; } @@ -155,7 +155,7 @@ namespace osu.Game.Screens.Multi [BackgroundDependencyLoader(true)] private void load(IdleTracker idleTracker) { - apiState.BindTo(api.State); + apiState.BindTo(API.State); apiState.BindValueChanged(onlineStateChanged, true); if (idleTracker != null) @@ -269,7 +269,7 @@ namespace osu.Game.Screens.Multi /// Creates a new room. /// /// The created . - protected virtual Room CreateNewRoom() => new Room { Name = { Value = $"{api.LocalUser}'s awesome room" } }; + protected abstract Room CreateNewRoom(); private void screenPushed(IScreen lastScreen, IScreen newScreen) { diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs index 6739a51fe8..e15a6bd408 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs @@ -57,7 +57,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer protected override Room CreateNewRoom() { - var room = base.CreateNewRoom(); + var room = new Room { Name = { Value = $"{API.LocalUser}'s awesome room" } }; room.Category.Value = RoomCategory.Realtime; return room; } diff --git a/osu.Game/Screens/Multi/Timeshift/CreateTimeshiftRoomButton.cs b/osu.Game/Screens/Multi/Timeshift/CreateTimeshiftRoomButton.cs index bd9d667630..0424493472 100644 --- a/osu.Game/Screens/Multi/Timeshift/CreateTimeshiftRoomButton.cs +++ b/osu.Game/Screens/Multi/Timeshift/CreateTimeshiftRoomButton.cs @@ -13,7 +13,7 @@ namespace osu.Game.Screens.Multi.Timeshift { Triangles.TriangleScale = 1.5f; - Text = "Create room"; + Text = "Create playlist"; } } } diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs index d525a3800d..e1b94f8455 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs @@ -4,6 +4,7 @@ using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Match; @@ -45,6 +46,11 @@ namespace osu.Game.Screens.Multi.Timeshift Logger.Log($"Polling adjusted (listing: {timeshiftManager.TimeBetweenListingPolls.Value}, selection: {timeshiftManager.TimeBetweenSelectionPolls.Value})"); } + protected override Room CreateNewRoom() + { + return new Room { Name = { Value = $"{API.LocalUser}'s awesome playlist" } }; + } + protected override RoomManager CreateRoomManager() => new TimeshiftRoomManager(); protected override LoungeSubScreen CreateLounge() => new TimeshiftLoungeSubScreen(); From d0e834796818beedbfbb9ecb3ab70dfd8bb18b5a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Dec 2020 22:28:25 +0900 Subject: [PATCH 291/328] Change asserts into until steps --- .../Gameplay/TestSceneGameplayLeaderboard.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index ca61672ef9..c0a021436e 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -52,19 +52,19 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("add player 2", () => createLeaderboardScore(player2Score, new User { Username = "Player 2" })); AddStep("add player 3", () => createLeaderboardScore(player3Score, new User { Username = "Player 3" })); - AddAssert("is player 2 position #1", () => leaderboard.CheckPositionByUsername("Player 2", 1)); - AddAssert("is player position #2", () => leaderboard.CheckPositionByUsername("You", 2)); - AddAssert("is player 3 position #3", () => leaderboard.CheckPositionByUsername("Player 3", 3)); + AddUntilStep("is player 2 position #1", () => leaderboard.CheckPositionByUsername("Player 2", 1)); + AddUntilStep("is player position #2", () => leaderboard.CheckPositionByUsername("You", 2)); + AddUntilStep("is player 3 position #3", () => leaderboard.CheckPositionByUsername("Player 3", 3)); AddStep("set score above player 3", () => player2Score.Value = playerScore.Value - 500); - AddAssert("is player position #1", () => leaderboard.CheckPositionByUsername("You", 1)); - AddAssert("is player 2 position #2", () => leaderboard.CheckPositionByUsername("Player 2", 2)); - AddAssert("is player 3 position #3", () => leaderboard.CheckPositionByUsername("Player 3", 3)); + AddUntilStep("is player position #1", () => leaderboard.CheckPositionByUsername("You", 1)); + AddUntilStep("is player 2 position #2", () => leaderboard.CheckPositionByUsername("Player 2", 2)); + AddUntilStep("is player 3 position #3", () => leaderboard.CheckPositionByUsername("Player 3", 3)); AddStep("set score below players", () => player2Score.Value = playerScore.Value - 123456); - AddAssert("is player position #1", () => leaderboard.CheckPositionByUsername("You", 1)); - AddAssert("is player 3 position #2", () => leaderboard.CheckPositionByUsername("Player 3", 2)); - AddAssert("is player 2 position #3", () => leaderboard.CheckPositionByUsername("Player 2", 3)); + AddUntilStep("is player position #1", () => leaderboard.CheckPositionByUsername("You", 1)); + AddUntilStep("is player 3 position #2", () => leaderboard.CheckPositionByUsername("Player 3", 2)); + AddUntilStep("is player 2 position #3", () => leaderboard.CheckPositionByUsername("Player 2", 3)); } [Test] From 76a7aabfe86b73d5619ff4b3e0d6d23e74907f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 24 Dec 2020 14:32:30 +0100 Subject: [PATCH 292/328] Always create realtime-specific player elements regardless of token --- .../Multi/RealtimeMultiplayer/RealtimePlayer.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index 07d21995ce..8eb6a11228 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -4,7 +4,6 @@ using System; using System.Diagnostics; using System.Threading.Tasks; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Logging; @@ -35,7 +34,6 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer private readonly TaskCompletionSource resultsReady = new TaskCompletionSource(); - [CanBeNull] private MultiplayerGameplayLeaderboard leaderboard; private readonly int[] userIds; @@ -61,6 +59,11 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer [BackgroundDependencyLoader] private void load() { + // todo: this should be implemented via a custom HUD implementation, and correctly masked to the main content area. + LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(ScoreProcessor, userIds), HUDOverlay.Add); + + HUDOverlay.Add(loadingDisplay = new LoadingLayer(DrawableRuleset) { Depth = float.MaxValue }); + if (Token == null) return; // Todo: Somehow handle token retrieval failure. @@ -84,11 +87,6 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer }, true); Debug.Assert(client.Room != null); - - // todo: this should be implemented via a custom HUD implementation, and correctly masked to the main content area. - LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(ScoreProcessor, userIds), HUDOverlay.Add); - - HUDOverlay.Add(loadingDisplay = new LoadingLayer(DrawableRuleset) { Depth = float.MaxValue }); } protected override void StartGameplay() @@ -115,9 +113,6 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer private void adjustLeaderboardPosition() { - if (leaderboard == null) - return; - const float padding = 44; // enough margin to avoid the hit error display. leaderboard.Position = new Vector2( From a97681a5daa18b6e4374a901b65e836a1bef82eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 24 Dec 2020 15:07:03 +0100 Subject: [PATCH 293/328] Proxy screen transition events to subscreens in multiplayer --- osu.Game/Screens/Multi/Multiplayer.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index a7d40a89d3..c4259400fa 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -202,6 +202,11 @@ namespace osu.Game.Screens.Multi { this.FadeIn(); waves.Show(); + + if (loungeSubScreen.IsCurrentScreen()) + loungeSubScreen.OnEntering(last); + else + loungeSubScreen.MakeCurrent(); } public override void OnResuming(IScreen last) @@ -209,6 +214,7 @@ namespace osu.Game.Screens.Multi this.FadeIn(250); this.ScaleTo(1, 250, Easing.OutSine); + screenStack.CurrentScreen?.OnResuming(last); base.OnResuming(last); UpdatePollingRate(isIdle.Value); @@ -219,6 +225,8 @@ namespace osu.Game.Screens.Multi this.ScaleTo(1.1f, 250, Easing.InSine); this.FadeOut(250); + screenStack.CurrentScreen?.OnSuspending(next); + UpdatePollingRate(isIdle.Value); } @@ -230,9 +238,7 @@ namespace osu.Game.Screens.Multi this.Delay(WaveContainer.DISAPPEAR_DURATION).FadeOut(); - if (screenStack.CurrentScreen != null) - loungeSubScreen.MakeCurrent(); - + screenStack.CurrentScreen?.OnExiting(next); base.OnExiting(next); return false; } From 7f0f6d86b0f931401e4fb8b347485ff6656ee354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 24 Dec 2020 16:08:45 +0100 Subject: [PATCH 294/328] Rename {room -> playlist} on playlist room screen --- osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs index 730ad795b2..4a66f09a22 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Multi.Timeshift { public override string Title { get; } - public override string ShortTitle => "room"; + public override string ShortTitle => "playlist"; [Resolved(typeof(Room), nameof(Room.RoomID))] private Bindable roomId { get; set; } @@ -40,7 +40,7 @@ namespace osu.Game.Screens.Multi.Timeshift public TimeshiftRoomSubScreen(Room room) { - Title = room.RoomID.Value == null ? "New room" : room.Name.Value; + Title = room.RoomID.Value == null ? "New playlist" : room.Name.Value; Activity.Value = new UserActivity.InLobby(room); } From db1c11073f430edd13aa8a480b0e30233de4697e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 24 Dec 2020 16:10:29 +0100 Subject: [PATCH 295/328] Rename back to "room" for "realtime" multiplayer --- .../Multi/RealtimeMultiplayer/CreateRealtimeMatchButton.cs | 2 +- .../Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/CreateRealtimeMatchButton.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/CreateRealtimeMatchButton.cs index eda907f8cb..cdaeb6faec 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/CreateRealtimeMatchButton.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/CreateRealtimeMatchButton.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer { Triangles.TriangleScale = 1.5f; - Text = "Create match"; + Text = "Create room"; ((IBindable)Enabled).BindTo(multiplayerClient.IsConnected); } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs index 15d997605c..1778bc272c 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer { public override string Title { get; } - public override string ShortTitle => "match"; + public override string ShortTitle => "room"; [Resolved] private StatefulMultiplayerClient client { get; set; } @@ -37,7 +37,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer public RealtimeMatchSubScreen(Room room) { - Title = room.RoomID.Value == null ? "New match" : room.Name.Value; + Title = room.RoomID.Value == null ? "New room" : room.Name.Value; Activity.Value = new UserActivity.InLobby(room); } From 6ec045f2353e80534efc1961990ac3d04adf58f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 24 Dec 2020 16:18:35 +0100 Subject: [PATCH 296/328] Distinguish primary multi screen titles in header --- osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs | 2 +- osu.Game/Screens/Multi/Header.cs | 8 ++++---- osu.Game/Screens/Multi/Multiplayer.cs | 4 +++- .../Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs | 2 ++ osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs | 2 ++ 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs index 76ab402b72..0ccd882d95 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Children = new Drawable[] { screenStack, - new Header(screenStack) + new Header("Multiplayer", screenStack) }; AddStep("push multi screen", () => screenStack.CurrentScreen.Push(new TestMultiplayerSubScreen(++index))); diff --git a/osu.Game/Screens/Multi/Header.cs b/osu.Game/Screens/Multi/Header.cs index cd8695286b..637d8bb52b 100644 --- a/osu.Game/Screens/Multi/Header.cs +++ b/osu.Game/Screens/Multi/Header.cs @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Multi { public const float HEIGHT = 80; - public Header(ScreenStack stack) + public Header(string mainTitle, ScreenStack stack) { RelativeSizeAxes = Axes.X; Height = HEIGHT; @@ -45,7 +45,7 @@ namespace osu.Game.Screens.Multi Padding = new MarginPadding { Left = WaveOverlayContainer.WIDTH_PADDING + OsuScreen.HORIZONTAL_OVERFLOW_PADDING }, Children = new Drawable[] { - title = new MultiHeaderTitle + title = new MultiHeaderTitle(mainTitle) { Anchor = Anchor.CentreLeft, Origin = Anchor.BottomLeft, @@ -80,7 +80,7 @@ namespace osu.Game.Screens.Multi set => pageTitle.Text = value.ShortTitle.Titleize(); } - public MultiHeaderTitle() + public MultiHeaderTitle(string mainTitle) { AutoSizeAxes = Axes.Both; @@ -98,7 +98,7 @@ namespace osu.Game.Screens.Multi Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Font = OsuFont.GetFont(size: 24), - Text = "Multiplayer" + Text = mainTitle }, dot = new OsuSpriteText { diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs index 585ac71189..56c1c6cb37 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer.cs @@ -127,7 +127,7 @@ namespace osu.Game.Screens.Multi screenStack = new MultiplayerSubScreenStack { RelativeSizeAxes = Axes.Both } } }, - new Header(screenStack), + new Header(ScreenTitle, screenStack), createButton = CreateNewMultiplayerGameButton().With(button => { button.Anchor = Anchor.TopRight; @@ -311,6 +311,8 @@ namespace osu.Game.Screens.Multi protected IScreen CurrentSubScreen => screenStack.CurrentScreen; + protected abstract string ScreenTitle { get; } + protected abstract RoomManager CreateRoomManager(); protected abstract LoungeSubScreen CreateLounge(); diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs index e15a6bd408..70308844b0 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs @@ -62,6 +62,8 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer return room; } + protected override string ScreenTitle => "Multiplayer"; + protected override RoomManager CreateRoomManager() => new RealtimeRoomManager(); protected override LoungeSubScreen CreateLounge() => new RealtimeLoungeSubScreen(); diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs b/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs index e1b94f8455..60b01ee431 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs +++ b/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs @@ -51,6 +51,8 @@ namespace osu.Game.Screens.Multi.Timeshift return new Room { Name = { Value = $"{API.LocalUser}'s awesome playlist" } }; } + protected override string ScreenTitle => "Playlists"; + protected override RoomManager CreateRoomManager() => new TimeshiftRoomManager(); protected override LoungeSubScreen CreateLounge() => new TimeshiftLoungeSubScreen(); From 60c7c8b63badedf7c0bef7ec7b5c365d1877e486 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Dec 2020 00:44:42 +0900 Subject: [PATCH 297/328] Pluralise playlists in tip --- osu.Game/Screens/Menu/Disclaimer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 9c7206d259..46fddabb26 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -208,7 +208,7 @@ namespace osu.Game.Screens.Menu "Most of the web content (profiles, rankings, etc.) are available natively in-game from the icons on the toolbar!", "Get more details, hide or delete a beatmap by right-clicking on its panel at song select!", "All delete operations are temporary until exiting. Restore accidentally deleted content from the maintenance settings!", - "Check out the \"playlist\" system, which lets users create their own custom and permanent leaderboards!", + "Check out the \"playlists\" system, which lets users create their own custom and permanent leaderboards!", "Toggle advanced frame / thread statistics with Ctrl-F11!", "Take a look under the hood at performance counters and enable verbose performance logging with Ctrl-F2!", }; From a1384942b1e6b2720988cb4618f9eab7bf8058cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Dec 2020 13:11:21 +0900 Subject: [PATCH 298/328] Timeshift -> Playlists at a code level --- .../TestSceneMatchSettingsOverlay.cs | 4 +-- .../Multiplayer/TestSceneMultiScreen.cs | 4 +-- ....cs => TestScenePlaylistsFilterControl.cs} | 6 ++-- ...s => TestScenePlaylistsLoungeSubScreen.cs} | 6 ++-- ... => TestScenePlaylistsParticipantsList.cs} | 2 +- ....cs => TestScenePlaylistsResultsScreen.cs} | 4 +-- ....cs => TestScenePlaylistsRoomSubScreen.cs} | 14 ++++----- .../Navigation/TestSceneScreenNavigation.cs | 6 ++-- .../GameTypes/GameTypeTimeshift.cs | 4 +-- osu.Game/Online/Multiplayer/Room.cs | 2 +- osu.Game/Screens/Menu/ButtonSystem.cs | 8 ++--- osu.Game/Screens/Menu/MainMenu.cs | 4 +-- .../Components/TimeshiftFilterControl.cs | 14 ++++----- .../Screens/Multi/Match/Components/Footer.cs | 4 +-- .../Multi/Match/Components/GameTypePicker.cs | 2 +- .../Screens/Multi/Play/TimeshiftPlayer.cs | 8 ++--- .../CreatePlaylistsRoomButton.cs} | 4 +-- .../PlaylistsLoungeSubScreen.cs} | 8 ++--- .../PlaylistsMatchSettingsOverlay.cs} | 4 +-- .../PlaylistsMultiplayer.cs} | 30 +++++++++---------- .../PlaylistsReadyButton.cs} | 6 ++-- .../PlaylistsRoomManager.cs} | 4 +-- .../PlaylistsRoomSubScreen.cs} | 12 ++++---- .../Multi/Ranking/TimeshiftResultsScreen.cs | 4 +-- .../RealtimeMultiplayer.cs | 16 +++++----- .../RealtimeMultiplayer/RealtimePlayer.cs | 4 +-- .../RealtimeResultsScreen.cs | 2 +- 27 files changed, 93 insertions(+), 93 deletions(-) rename osu.Game.Tests/Visual/Multiplayer/{TestSceneTimeshiftFilterControl.cs => TestScenePlaylistsFilterControl.cs} (76%) rename osu.Game.Tests/Visual/Multiplayer/{TestSceneTimeshiftLoungeSubScreen.cs => TestScenePlaylistsLoungeSubScreen.cs} (93%) rename osu.Game.Tests/Visual/Multiplayer/{TestSceneTimeshiftParticipantsList.cs => TestScenePlaylistsParticipantsList.cs} (95%) rename osu.Game.Tests/Visual/Multiplayer/{TestSceneTimeshiftResultsScreen.cs => TestScenePlaylistsResultsScreen.cs} (99%) rename osu.Game.Tests/Visual/Multiplayer/{TestSceneTimeshiftRoomSubScreen.cs => TestScenePlaylistsRoomSubScreen.cs} (93%) rename osu.Game/Screens/Multi/{Timeshift/CreateTimeshiftRoomButton.cs => Playlists/CreatePlaylistsRoomButton.cs} (79%) rename osu.Game/Screens/Multi/{Timeshift/TimeshiftLoungeSubScreen.cs => Playlists/PlaylistsLoungeSubScreen.cs} (71%) rename osu.Game/Screens/Multi/{Timeshift/TimeshiftMatchSettingsOverlay.cs => Playlists/PlaylistsMatchSettingsOverlay.cs} (99%) rename osu.Game/Screens/Multi/{Timeshift/TimeshiftMultiplayer.cs => Playlists/PlaylistsMultiplayer.cs} (62%) rename osu.Game/Screens/Multi/{Timeshift/TimeshiftReadyButton.cs => Playlists/PlaylistsReadyButton.cs} (88%) rename osu.Game/Screens/Multi/{Timeshift/TimeshiftRoomManager.cs => Playlists/PlaylistsRoomManager.cs} (89%) rename osu.Game/Screens/Multi/{Timeshift/TimeshiftRoomSubScreen.cs => Playlists/PlaylistsRoomSubScreen.cs} (97%) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs index 1fcae9c709..90abecd26d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi; -using osu.Game.Screens.Multi.Timeshift; +using osu.Game.Screens.Multi.Playlists; namespace osu.Game.Tests.Visual.Multiplayer { @@ -109,7 +109,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("error not displayed", () => !settings.ErrorText.IsPresent); } - private class TestRoomSettings : TimeshiftMatchSettingsOverlay + private class TestRoomSettings : PlaylistsMatchSettingsOverlay { public TriangleButton ApplyButton => ((MatchSettings)Settings).ApplyButton; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiScreen.cs index 0390b995e1..9ac1eb8013 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiScreen.cs @@ -4,7 +4,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Game.Overlays; -using osu.Game.Screens.Multi.Timeshift; +using osu.Game.Screens.Multi.Playlists; namespace osu.Game.Tests.Visual.Multiplayer { @@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Multiplayer public TestSceneMultiScreen() { - var multi = new TimeshiftMultiplayer(); + var multi = new PlaylistsMultiplayer(); AddStep("show", () => LoadScreen(multi)); AddUntilStep("wait for loaded", () => multi.IsLoaded); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftFilterControl.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsFilterControl.cs similarity index 76% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftFilterControl.cs rename to osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsFilterControl.cs index f635a28b5c..427a69552d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftFilterControl.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsFilterControl.cs @@ -6,11 +6,11 @@ using osu.Game.Screens.Multi.Lounge.Components; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneTimeshiftFilterControl : OsuTestScene + public class TestScenePlaylistsFilterControl : OsuTestScene { - public TestSceneTimeshiftFilterControl() + public TestScenePlaylistsFilterControl() { - Child = new TimeshiftFilterControl + Child = new PlaylistsFilterControl { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftLoungeSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsLoungeSubScreen.cs similarity index 93% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftLoungeSubScreen.cs rename to osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsLoungeSubScreen.cs index 73afd65d6d..f8788f0c36 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsLoungeSubScreen.cs @@ -10,11 +10,11 @@ using osu.Framework.Testing; using osu.Game.Graphics.Containers; using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Lounge.Components; -using osu.Game.Screens.Multi.Timeshift; +using osu.Game.Screens.Multi.Playlists; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneTimeshiftLoungeSubScreen : RoomManagerTestScene + public class TestScenePlaylistsLoungeSubScreen : RoomManagerTestScene { private LoungeSubScreen loungeScreen; @@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { base.SetUpSteps(); - AddStep("push screen", () => LoadScreen(loungeScreen = new TimeshiftLoungeSubScreen + AddStep("push screen", () => LoadScreen(loungeScreen = new PlaylistsLoungeSubScreen { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsParticipantsList.cs similarity index 95% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftParticipantsList.cs rename to osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsParticipantsList.cs index efc3be032c..d71fdc42e3 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsParticipantsList.cs @@ -8,7 +8,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneTimeshiftParticipantsList : MultiplayerTestScene + public class TestScenePlaylistsParticipantsList : MultiplayerTestScene { [SetUp] public new void Setup() => Schedule(() => diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftResultsScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsResultsScreen.cs similarity index 99% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftResultsScreen.cs rename to osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsResultsScreen.cs index 03fd2b968c..99fc6597ee 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftResultsScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsResultsScreen.cs @@ -26,7 +26,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneTimeshiftResultsScreen : ScreenTestScene + public class TestScenePlaylistsResultsScreen : ScreenTestScene { private const int scores_per_result = 10; @@ -360,7 +360,7 @@ namespace osu.Game.Tests.Visual.Multiplayer }; } - private class TestResultsScreen : TimeshiftResultsScreen + private class TestResultsScreen : PlaylistsResultsScreen { public new LoadingSpinner LeftSpinner => base.LeftSpinner; public new LoadingSpinner CentreSpinner => base.CentreSpinner; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSubScreen.cs similarity index 93% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs rename to osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSubScreen.cs index bbd7d84081..02cc03eca4 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSubScreen.cs @@ -17,14 +17,14 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Multi; using osu.Game.Screens.Multi.Match.Components; -using osu.Game.Screens.Multi.Timeshift; +using osu.Game.Screens.Multi.Playlists; using osu.Game.Tests.Beatmaps; using osu.Game.Users; using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneTimeshiftRoomSubScreen : MultiplayerTestScene + public class TestScenePlaylistsRoomSubScreen : MultiplayerTestScene { protected override bool UseOnlineAPI => true; @@ -34,7 +34,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private BeatmapManager manager; private RulesetStore rulesets; - private TestTimeshiftRoomSubScreen match; + private TestPlaylistsRoomSubScreen match; [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Multiplayer [SetUpSteps] public void SetupSteps() { - AddStep("load match", () => LoadScreen(match = new TestTimeshiftRoomSubScreen(Room))); + AddStep("load match", () => LoadScreen(match = new TestPlaylistsRoomSubScreen(Room))); AddUntilStep("wait for load", () => match.IsCurrentScreen()); } @@ -120,7 +120,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("create room", () => { - InputManager.MoveMouseTo(match.ChildrenOfType().Single()); + InputManager.MoveMouseTo(match.ChildrenOfType().Single()); InputManager.Click(MouseButton.Left); }); @@ -131,13 +131,13 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("match has original beatmap", () => match.Beatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty.CircleSize != 1); } - private class TestTimeshiftRoomSubScreen : TimeshiftRoomSubScreen + private class TestPlaylistsRoomSubScreen : PlaylistsRoomSubScreen { public new Bindable SelectedItem => base.SelectedItem; public new Bindable Beatmap => base.Beatmap; - public TestTimeshiftRoomSubScreen(Room room) + public TestPlaylistsRoomSubScreen(Room room) : base(room) { } diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 43f97d8ace..381bbca74f 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -11,7 +11,7 @@ using osu.Game.Beatmaps; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Overlays.Toolbar; -using osu.Game.Screens.Multi.Timeshift; +using osu.Game.Screens.Multi.Playlists; using osu.Game.Screens.Play; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Options; @@ -108,14 +108,14 @@ namespace osu.Game.Tests.Visual.Navigation [Test] public void TestExitMultiWithEscape() { - PushAndConfirm(() => new TimeshiftMultiplayer()); + PushAndConfirm(() => new PlaylistsMultiplayer()); exitViaEscapeAndConfirm(); } [Test] public void TestExitMultiWithBackButton() { - PushAndConfirm(() => new TimeshiftMultiplayer()); + PushAndConfirm(() => new PlaylistsMultiplayer()); exitViaBackButtonAndConfirm(); } diff --git a/osu.Game/Online/Multiplayer/GameTypes/GameTypeTimeshift.cs b/osu.Game/Online/Multiplayer/GameTypes/GameTypeTimeshift.cs index 1a3d2837ce..5840ccb803 100644 --- a/osu.Game/Online/Multiplayer/GameTypes/GameTypeTimeshift.cs +++ b/osu.Game/Online/Multiplayer/GameTypes/GameTypeTimeshift.cs @@ -8,9 +8,9 @@ using osuTK; namespace osu.Game.Online.Multiplayer.GameTypes { - public class GameTypeTimeshift : GameType + public class GameTypePlaylists : GameType { - public override string Name => "Timeshift"; + public override string Name => "Playlists"; public override Drawable GetIcon(OsuColour colours, float size) => new SpriteIcon { diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs index 11efe281d1..d13d7dc774 100644 --- a/osu.Game/Online/Multiplayer/Room.cs +++ b/osu.Game/Online/Multiplayer/Room.cs @@ -66,7 +66,7 @@ namespace osu.Game.Online.Multiplayer [Cached] [JsonIgnore] - public readonly Bindable Type = new Bindable(new GameTypeTimeshift()); + public readonly Bindable Type = new Bindable(new GameTypePlaylists()); [Cached] [JsonIgnore] diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 5af6517f49..474cbde192 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -43,7 +43,7 @@ namespace osu.Game.Screens.Menu public Action OnSolo; public Action OnSettings; public Action OnMultiplayer; - public Action OnTimeshift; + public Action OnPlaylists; public const float BUTTON_WIDTH = 140f; public const float WEDGE_WIDTH = 20; @@ -125,7 +125,7 @@ namespace osu.Game.Screens.Menu { buttonsPlay.Add(new Button(@"solo", @"button-solo-select", FontAwesome.Solid.User, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P)); buttonsPlay.Add(new Button(@"multi", @"button-generic-select", FontAwesome.Solid.Users, new Color4(94, 63, 186, 255), onMultiplayer, 0, Key.M)); - buttonsPlay.Add(new Button(@"playlists", @"button-generic-select", OsuIcon.Charts, new Color4(94, 63, 186, 255), onTimeshift, 0, Key.L)); + buttonsPlay.Add(new Button(@"playlists", @"button-generic-select", OsuIcon.Charts, new Color4(94, 63, 186, 255), onPlaylists, 0, Key.L)); buttonsPlay.ForEach(b => b.VisibleState = ButtonSystemState.Play); buttonsTopLevel.Add(new Button(@"play", @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P)); @@ -175,7 +175,7 @@ namespace osu.Game.Screens.Menu OnMultiplayer?.Invoke(); } - private void onTimeshift() + private void onPlaylists() { if (!api.IsLoggedIn) { @@ -193,7 +193,7 @@ namespace osu.Game.Screens.Menu return; } - OnTimeshift?.Invoke(); + OnPlaylists?.Invoke(); } private void updateIdleState(bool isIdle) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index fa96ac9c51..5650b22f25 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -18,7 +18,7 @@ using osu.Game.Overlays; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; using osu.Game.Screens.Multi.RealtimeMultiplayer; -using osu.Game.Screens.Multi.Timeshift; +using osu.Game.Screens.Multi.Playlists; using osu.Game.Screens.Select; namespace osu.Game.Screens.Menu @@ -106,7 +106,7 @@ namespace osu.Game.Screens.Menu }, OnSolo = onSolo, OnMultiplayer = () => this.Push(new RealtimeMultiplayer()), - OnTimeshift = () => this.Push(new TimeshiftMultiplayer()), + OnPlaylists = () => this.Push(new PlaylistsMultiplayer()), OnExit = confirmAndExit, } } diff --git a/osu.Game/Screens/Multi/Lounge/Components/TimeshiftFilterControl.cs b/osu.Game/Screens/Multi/Lounge/Components/TimeshiftFilterControl.cs index 68cab283a0..3c55c3c43f 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/TimeshiftFilterControl.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/TimeshiftFilterControl.cs @@ -7,13 +7,13 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Screens.Multi.Lounge.Components { - public class TimeshiftFilterControl : FilterControl + public class PlaylistsFilterControl : FilterControl { - private readonly Dropdown dropdown; + private readonly Dropdown dropdown; - public TimeshiftFilterControl() + public PlaylistsFilterControl() { - AddInternal(dropdown = new SlimEnumDropdown + AddInternal(dropdown = new SlimEnumDropdown { Anchor = Anchor.BottomRight, Origin = Anchor.TopRight, @@ -37,11 +37,11 @@ namespace osu.Game.Screens.Multi.Lounge.Components switch (dropdown.Current.Value) { - case TimeshiftCategory.Normal: + case PlaylistsCategory.Normal: criteria.Category = "normal"; break; - case TimeshiftCategory.Spotlight: + case PlaylistsCategory.Spotlight: criteria.Category = "spotlight"; break; } @@ -49,7 +49,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components return criteria; } - private enum TimeshiftCategory + private enum PlaylistsCategory { Any, Normal, diff --git a/osu.Game/Screens/Multi/Match/Components/Footer.cs b/osu.Game/Screens/Multi/Match/Components/Footer.cs index d6a7e380bf..fdf1d0dbeb 100644 --- a/osu.Game/Screens/Multi/Match/Components/Footer.cs +++ b/osu.Game/Screens/Multi/Match/Components/Footer.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Online.Multiplayer; -using osu.Game.Screens.Multi.Timeshift; +using osu.Game.Screens.Multi.Playlists; using osuTK; namespace osu.Game.Screens.Multi.Match.Components @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Multi.Match.Components InternalChildren = new[] { background = new Box { RelativeSizeAxes = Axes.Both }, - new TimeshiftReadyButton + new PlaylistsReadyButton { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Multi/Match/Components/GameTypePicker.cs b/osu.Game/Screens/Multi/Match/Components/GameTypePicker.cs index b69cb9705d..c7fc329a1a 100644 --- a/osu.Game/Screens/Multi/Match/Components/GameTypePicker.cs +++ b/osu.Game/Screens/Multi/Match/Components/GameTypePicker.cs @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Multi.Match.Components AddItem(new GameTypeVersus()); AddItem(new GameTypeTagTeam()); AddItem(new GameTypeTeamVersus()); - AddItem(new GameTypeTimeshift()); + AddItem(new GameTypePlaylists()); } private class GameTypePickerItem : DisableableTabItem diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs index f07f1c2fb0..65b0091505 100644 --- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs +++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs @@ -20,7 +20,7 @@ using osu.Game.Screens.Ranking; namespace osu.Game.Screens.Multi.Play { - public class TimeshiftPlayer : Player + public class PlaylistsPlayer : Player { public Action Exited; @@ -37,7 +37,7 @@ namespace osu.Game.Screens.Multi.Play [Resolved] private IBindable ruleset { get; set; } - public TimeshiftPlayer(PlaylistItem playlistItem, PlayerConfiguration configuration = null) + public PlaylistsPlayer(PlaylistItem playlistItem, PlayerConfiguration configuration = null) : base(configuration) { PlaylistItem = playlistItem; @@ -50,7 +50,7 @@ namespace osu.Game.Screens.Multi.Play bool failed = false; - // Sanity checks to ensure that TimeshiftPlayer matches the settings for the current PlaylistItem + // Sanity checks to ensure that PlaylistsPlayer matches the settings for the current PlaylistItem if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != PlaylistItem.Beatmap.Value.OnlineBeatmapID) throw new InvalidOperationException("Current Beatmap does not match PlaylistItem's Beatmap"); @@ -94,7 +94,7 @@ namespace osu.Game.Screens.Multi.Play protected override ResultsScreen CreateResults(ScoreInfo score) { Debug.Assert(RoomId.Value != null); - return new TimeshiftResultsScreen(score, RoomId.Value.Value, PlaylistItem, true); + return new PlaylistsResultsScreen(score, RoomId.Value.Value, PlaylistItem, true); } protected override Score CreateScore() diff --git a/osu.Game/Screens/Multi/Timeshift/CreateTimeshiftRoomButton.cs b/osu.Game/Screens/Multi/Playlists/CreatePlaylistsRoomButton.cs similarity index 79% rename from osu.Game/Screens/Multi/Timeshift/CreateTimeshiftRoomButton.cs rename to osu.Game/Screens/Multi/Playlists/CreatePlaylistsRoomButton.cs index 0424493472..acee063115 100644 --- a/osu.Game/Screens/Multi/Timeshift/CreateTimeshiftRoomButton.cs +++ b/osu.Game/Screens/Multi/Playlists/CreatePlaylistsRoomButton.cs @@ -4,9 +4,9 @@ using osu.Framework.Allocation; using osu.Game.Screens.Multi.Match.Components; -namespace osu.Game.Screens.Multi.Timeshift +namespace osu.Game.Screens.Multi.Playlists { - public class CreateTimeshiftRoomButton : PurpleTriangleButton + public class CreatePlaylistsRoomButton : PurpleTriangleButton { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftLoungeSubScreen.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsLoungeSubScreen.cs similarity index 71% rename from osu.Game/Screens/Multi/Timeshift/TimeshiftLoungeSubScreen.cs rename to osu.Game/Screens/Multi/Playlists/PlaylistsLoungeSubScreen.cs index 8e426ffbcc..b40c543b68 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftLoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsLoungeSubScreen.cs @@ -6,12 +6,12 @@ using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Lounge.Components; using osu.Game.Screens.Multi.Match; -namespace osu.Game.Screens.Multi.Timeshift +namespace osu.Game.Screens.Multi.Playlists { - public class TimeshiftLoungeSubScreen : LoungeSubScreen + public class PlaylistsLoungeSubScreen : LoungeSubScreen { - protected override FilterControl CreateFilterControl() => new TimeshiftFilterControl(); + protected override FilterControl CreateFilterControl() => new PlaylistsFilterControl(); - protected override RoomSubScreen CreateRoomSubScreen(Room room) => new TimeshiftRoomSubScreen(room); + protected override RoomSubScreen CreateRoomSubScreen(Room room) => new PlaylistsRoomSubScreen(room); } } diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftMatchSettingsOverlay.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsMatchSettingsOverlay.cs similarity index 99% rename from osu.Game/Screens/Multi/Timeshift/TimeshiftMatchSettingsOverlay.cs rename to osu.Game/Screens/Multi/Playlists/PlaylistsMatchSettingsOverlay.cs index 7e1e9894d8..af29e8d34d 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftMatchSettingsOverlay.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsMatchSettingsOverlay.cs @@ -19,9 +19,9 @@ using osu.Game.Overlays; using osu.Game.Screens.Multi.Match.Components; using osuTK; -namespace osu.Game.Screens.Multi.Timeshift +namespace osu.Game.Screens.Multi.Playlists { - public class TimeshiftMatchSettingsOverlay : MatchSettingsOverlay + public class PlaylistsMatchSettingsOverlay : MatchSettingsOverlay { public Action EditPlaylist; diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsMultiplayer.cs similarity index 62% rename from osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs rename to osu.Game/Screens/Multi/Playlists/PlaylistsMultiplayer.cs index 60b01ee431..fce24da966 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftMultiplayer.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsMultiplayer.cs @@ -9,41 +9,41 @@ using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Match; -namespace osu.Game.Screens.Multi.Timeshift +namespace osu.Game.Screens.Multi.Playlists { - public class TimeshiftMultiplayer : Multiplayer + public class PlaylistsMultiplayer : Multiplayer { protected override void UpdatePollingRate(bool isIdle) { - var timeshiftManager = (TimeshiftRoomManager)RoomManager; + var playlistsManager = (PlaylistsRoomManager)RoomManager; if (!this.IsCurrentScreen()) { - timeshiftManager.TimeBetweenListingPolls.Value = 0; - timeshiftManager.TimeBetweenSelectionPolls.Value = 0; + playlistsManager.TimeBetweenListingPolls.Value = 0; + playlistsManager.TimeBetweenSelectionPolls.Value = 0; } else { switch (CurrentSubScreen) { case LoungeSubScreen _: - timeshiftManager.TimeBetweenListingPolls.Value = isIdle ? 120000 : 15000; - timeshiftManager.TimeBetweenSelectionPolls.Value = isIdle ? 120000 : 15000; + playlistsManager.TimeBetweenListingPolls.Value = isIdle ? 120000 : 15000; + playlistsManager.TimeBetweenSelectionPolls.Value = isIdle ? 120000 : 15000; break; case RoomSubScreen _: - timeshiftManager.TimeBetweenListingPolls.Value = 0; - timeshiftManager.TimeBetweenSelectionPolls.Value = isIdle ? 30000 : 5000; + playlistsManager.TimeBetweenListingPolls.Value = 0; + playlistsManager.TimeBetweenSelectionPolls.Value = isIdle ? 30000 : 5000; break; default: - timeshiftManager.TimeBetweenListingPolls.Value = 0; - timeshiftManager.TimeBetweenSelectionPolls.Value = 0; + playlistsManager.TimeBetweenListingPolls.Value = 0; + playlistsManager.TimeBetweenSelectionPolls.Value = 0; break; } } - Logger.Log($"Polling adjusted (listing: {timeshiftManager.TimeBetweenListingPolls.Value}, selection: {timeshiftManager.TimeBetweenSelectionPolls.Value})"); + Logger.Log($"Polling adjusted (listing: {playlistsManager.TimeBetweenListingPolls.Value}, selection: {playlistsManager.TimeBetweenSelectionPolls.Value})"); } protected override Room CreateNewRoom() @@ -53,10 +53,10 @@ namespace osu.Game.Screens.Multi.Timeshift protected override string ScreenTitle => "Playlists"; - protected override RoomManager CreateRoomManager() => new TimeshiftRoomManager(); + protected override RoomManager CreateRoomManager() => new PlaylistsRoomManager(); - protected override LoungeSubScreen CreateLounge() => new TimeshiftLoungeSubScreen(); + protected override LoungeSubScreen CreateLounge() => new PlaylistsLoungeSubScreen(); - protected override OsuButton CreateNewMultiplayerGameButton() => new CreateTimeshiftRoomButton(); + protected override OsuButton CreateNewMultiplayerGameButton() => new CreatePlaylistsRoomButton(); } } diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsReadyButton.cs similarity index 88% rename from osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs rename to osu.Game/Screens/Multi/Playlists/PlaylistsReadyButton.cs index c878451eee..f5adf899e3 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftReadyButton.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsReadyButton.cs @@ -8,14 +8,14 @@ using osu.Game.Graphics; using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi.Components; -namespace osu.Game.Screens.Multi.Timeshift +namespace osu.Game.Screens.Multi.Playlists { - public class TimeshiftReadyButton : ReadyButton + public class PlaylistsReadyButton : ReadyButton { [Resolved(typeof(Room), nameof(Room.EndDate))] private Bindable endDate { get; set; } - public TimeshiftReadyButton() + public PlaylistsReadyButton() { Text = "Start"; } diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomManager.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsRoomManager.cs similarity index 89% rename from osu.Game/Screens/Multi/Timeshift/TimeshiftRoomManager.cs rename to osu.Game/Screens/Multi/Playlists/PlaylistsRoomManager.cs index d21f844e04..ae57eeddcc 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomManager.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsRoomManager.cs @@ -5,9 +5,9 @@ using System.Collections.Generic; using osu.Framework.Bindables; using osu.Game.Screens.Multi.Components; -namespace osu.Game.Screens.Multi.Timeshift +namespace osu.Game.Screens.Multi.Playlists { - public class TimeshiftRoomManager : RoomManager + public class PlaylistsRoomManager : RoomManager { public readonly Bindable TimeBetweenListingPolls = new Bindable(); public readonly Bindable TimeBetweenSelectionPolls = new Bindable(); diff --git a/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs similarity index 97% rename from osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs rename to osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs index 4a66f09a22..b2bcba1724 100644 --- a/osu.Game/Screens/Multi/Timeshift/TimeshiftRoomSubScreen.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs @@ -19,9 +19,9 @@ using osu.Game.Screens.Select; using osu.Game.Users; using Footer = osu.Game.Screens.Multi.Match.Components.Footer; -namespace osu.Game.Screens.Multi.Timeshift +namespace osu.Game.Screens.Multi.Playlists { - public class TimeshiftRoomSubScreen : RoomSubScreen + public class PlaylistsRoomSubScreen : RoomSubScreen { public override string Title { get; } @@ -38,7 +38,7 @@ namespace osu.Game.Screens.Multi.Timeshift private OverlinedHeader participantsHeader; - public TimeshiftRoomSubScreen(Room room) + public PlaylistsRoomSubScreen(Room room) { Title = room.RoomID.Value == null ? "New playlist" : room.Name.Value; Activity.Value = new UserActivity.InLobby(room); @@ -126,7 +126,7 @@ namespace osu.Game.Screens.Multi.Timeshift RequestShowResults = item => { Debug.Assert(roomId.Value != null); - multiplayer?.Push(new TimeshiftResultsScreen(null, roomId.Value.Value, item, false)); + multiplayer?.Push(new PlaylistsResultsScreen(null, roomId.Value.Value, item, false)); } } }, @@ -188,7 +188,7 @@ namespace osu.Game.Screens.Multi.Timeshift new Dimension(GridSizeMode.AutoSize), } }, - settingsOverlay = new TimeshiftMatchSettingsOverlay + settingsOverlay = new PlaylistsMatchSettingsOverlay { RelativeSizeAxes = Axes.Both, EditPlaylist = () => this.Push(new MatchSongSelect()), @@ -219,7 +219,7 @@ namespace osu.Game.Screens.Multi.Timeshift }, true); } - private void onStart() => StartPlay(() => new TimeshiftPlayer(SelectedItem.Value) + private void onStart() => StartPlay(() => new PlaylistsPlayer(SelectedItem.Value) { Exited = () => leaderboard.RefreshScores() }); diff --git a/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs b/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs index d3f1c19c7c..c757433e2f 100644 --- a/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs +++ b/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs @@ -17,7 +17,7 @@ using osu.Game.Screens.Ranking; namespace osu.Game.Screens.Multi.Ranking { - public class TimeshiftResultsScreen : ResultsScreen + public class PlaylistsResultsScreen : ResultsScreen { private readonly int roomId; private readonly PlaylistItem playlistItem; @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Multi.Ranking [Resolved] private IAPIProvider api { get; set; } - public TimeshiftResultsScreen(ScoreInfo score, int roomId, PlaylistItem playlistItem, bool allowRetry, bool allowWatchingReplay = true) + public PlaylistsResultsScreen(ScoreInfo score, int roomId, PlaylistItem playlistItem, bool allowRetry, bool allowWatchingReplay = true) : base(score, allowRetry, allowWatchingReplay) { this.roomId = roomId; diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs index 70308844b0..87c838f29f 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs @@ -28,31 +28,31 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer protected override void UpdatePollingRate(bool isIdle) { - var timeshiftManager = (RealtimeRoomManager)RoomManager; + var playlistsManager = (RealtimeRoomManager)RoomManager; if (!this.IsCurrentScreen()) { - timeshiftManager.TimeBetweenListingPolls.Value = 0; - timeshiftManager.TimeBetweenSelectionPolls.Value = 0; + playlistsManager.TimeBetweenListingPolls.Value = 0; + playlistsManager.TimeBetweenSelectionPolls.Value = 0; } else { switch (CurrentSubScreen) { case LoungeSubScreen _: - timeshiftManager.TimeBetweenListingPolls.Value = isIdle ? 120000 : 15000; - timeshiftManager.TimeBetweenSelectionPolls.Value = isIdle ? 120000 : 15000; + playlistsManager.TimeBetweenListingPolls.Value = isIdle ? 120000 : 15000; + playlistsManager.TimeBetweenSelectionPolls.Value = isIdle ? 120000 : 15000; break; // Don't poll inside the match or anywhere else. default: - timeshiftManager.TimeBetweenListingPolls.Value = 0; - timeshiftManager.TimeBetweenSelectionPolls.Value = 0; + playlistsManager.TimeBetweenListingPolls.Value = 0; + playlistsManager.TimeBetweenSelectionPolls.Value = 0; break; } } - Logger.Log($"Polling adjusted (listing: {timeshiftManager.TimeBetweenListingPolls.Value}, selection: {timeshiftManager.TimeBetweenSelectionPolls.Value})"); + Logger.Log($"Polling adjusted (listing: {playlistsManager.TimeBetweenListingPolls.Value}, selection: {playlistsManager.TimeBetweenSelectionPolls.Value})"); } protected override Room CreateNewRoom() diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs index 8eb6a11228..033e4756eb 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs @@ -19,8 +19,8 @@ using osuTK; namespace osu.Game.Screens.Multi.RealtimeMultiplayer { - // Todo: The "room" part of TimeshiftPlayer should be split out into an abstract player class to be inherited instead. - public class RealtimePlayer : TimeshiftPlayer + // Todo: The "room" part of PlaylistsPlayer should be split out into an abstract player class to be inherited instead. + public class RealtimePlayer : PlaylistsPlayer { protected override bool PauseOnFocusLost => false; diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs index 3964a87eb6..6bec06cbba 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs +++ b/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs @@ -7,7 +7,7 @@ using osu.Game.Screens.Multi.Ranking; namespace osu.Game.Screens.Multi.RealtimeMultiplayer { - public class RealtimeResultsScreen : TimeshiftResultsScreen + public class RealtimeResultsScreen : PlaylistsResultsScreen { public RealtimeResultsScreen(ScoreInfo score, int roomId, PlaylistItem playlistItem) : base(score, roomId, playlistItem, false, false) From 12e4bbdc5b00de3a1c81da809fad4c69787269a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Dec 2020 13:20:37 +0900 Subject: [PATCH 299/328] Reorganise test scenes into playlists specific namespace --- .../TestSceneRealtimeMatchSubScreen.cs | 3 ++- .../TestSceneRealtimeMultiplayer.cs | 3 ++- .../TestSceneRealtimeMultiplayerParticipantsList.cs | 3 ++- .../TestSceneRealtimeReadyButton.cs | 3 ++- .../TestSceneRealtimeRoomManager.cs | 3 ++- .../TestScenePlaylistsFilterControl.cs | 2 +- .../TestScenePlaylistsLoungeSubScreen.cs | 3 ++- .../TestScenePlaylistsMatchSettingsOverlay.cs} | 4 ++-- .../TestScenePlaylistsParticipantsList.cs | 2 +- .../TestScenePlaylistsResultsScreen.cs | 2 +- .../TestScenePlaylistsRoomSubScreen.cs | 2 +- .../TestScenePlaylistsScreen.cs} | 6 +++--- 12 files changed, 21 insertions(+), 15 deletions(-) rename osu.Game.Tests/Visual/{RealtimeMultiplayer => Multiplayer}/TestSceneRealtimeMatchSubScreen.cs (96%) rename osu.Game.Tests/Visual/{RealtimeMultiplayer => Multiplayer}/TestSceneRealtimeMultiplayer.cs (94%) rename osu.Game.Tests/Visual/{RealtimeMultiplayer => Multiplayer}/TestSceneRealtimeMultiplayerParticipantsList.cs (97%) rename osu.Game.Tests/Visual/{RealtimeMultiplayer => Multiplayer}/TestSceneRealtimeReadyButton.cs (98%) rename osu.Game.Tests/Visual/{RealtimeMultiplayer => Multiplayer}/TestSceneRealtimeRoomManager.cs (98%) rename osu.Game.Tests/Visual/{Multiplayer => Playlists}/TestScenePlaylistsFilterControl.cs (93%) rename osu.Game.Tests/Visual/{Multiplayer => Playlists}/TestScenePlaylistsLoungeSubScreen.cs (95%) rename osu.Game.Tests/Visual/{Multiplayer/TestSceneMatchSettingsOverlay.cs => Playlists/TestScenePlaylistsMatchSettingsOverlay.cs} (97%) rename osu.Game.Tests/Visual/{Multiplayer => Playlists}/TestScenePlaylistsParticipantsList.cs (97%) rename osu.Game.Tests/Visual/{Multiplayer => Playlists}/TestScenePlaylistsResultsScreen.cs (99%) rename osu.Game.Tests/Visual/{Multiplayer => Playlists}/TestScenePlaylistsRoomSubScreen.cs (99%) rename osu.Game.Tests/Visual/{Multiplayer/TestSceneMultiScreen.cs => Playlists/TestScenePlaylistsScreen.cs} (82%) diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMatchSubScreen.cs similarity index 96% rename from osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMatchSubScreen.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMatchSubScreen.cs index a059bb1cc0..dff375d1bb 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMatchSubScreen.cs @@ -10,9 +10,10 @@ using osu.Game.Rulesets.Osu; using osu.Game.Screens.Multi.RealtimeMultiplayer; using osu.Game.Screens.Multi.RealtimeMultiplayer.Match; using osu.Game.Tests.Beatmaps; +using osu.Game.Tests.Visual.RealtimeMultiplayer; using osuTK.Input; -namespace osu.Game.Tests.Visual.RealtimeMultiplayer +namespace osu.Game.Tests.Visual.Multiplayer { public class TestSceneRealtimeMatchSubScreen : RealtimeMultiplayerTestScene { diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMultiplayer.cs similarity index 94% rename from osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMultiplayer.cs index 5cf80df6aa..cc07bb8e79 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMultiplayer.cs @@ -3,9 +3,10 @@ using NUnit.Framework; using osu.Game.Screens.Multi.Components; +using osu.Game.Tests.Visual.RealtimeMultiplayer; using osu.Game.Users; -namespace osu.Game.Tests.Visual.RealtimeMultiplayer +namespace osu.Game.Tests.Visual.Multiplayer { public class TestSceneRealtimeMultiplayer : RealtimeMultiplayerTestScene { diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs similarity index 97% rename from osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs index 4221821496..7c26918927 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs @@ -9,10 +9,11 @@ using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Screens.Multi.RealtimeMultiplayer.Participants; +using osu.Game.Tests.Visual.RealtimeMultiplayer; using osu.Game.Users; using osuTK; -namespace osu.Game.Tests.Visual.RealtimeMultiplayer +namespace osu.Game.Tests.Visual.Multiplayer { public class TestSceneRealtimeMultiplayerParticipantsList : RealtimeMultiplayerTestScene { diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeReadyButton.cs similarity index 98% rename from osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeReadyButton.cs index 825470846c..3c92276629 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeReadyButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeReadyButton.cs @@ -14,11 +14,12 @@ using osu.Game.Online.RealtimeMultiplayer; using osu.Game.Rulesets; using osu.Game.Screens.Multi.RealtimeMultiplayer.Match; using osu.Game.Tests.Resources; +using osu.Game.Tests.Visual.RealtimeMultiplayer; using osu.Game.Users; using osuTK; using osuTK.Input; -namespace osu.Game.Tests.Visual.RealtimeMultiplayer +namespace osu.Game.Tests.Visual.Multiplayer { public class TestSceneRealtimeReadyButton : RealtimeMultiplayerTestScene { diff --git a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeRoomManager.cs similarity index 98% rename from osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeRoomManager.cs index 925a83a863..ba90e0840b 100644 --- a/osu.Game.Tests/Visual/RealtimeMultiplayer/TestSceneRealtimeRoomManager.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeRoomManager.cs @@ -5,8 +5,9 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Online.Multiplayer; +using osu.Game.Tests.Visual.RealtimeMultiplayer; -namespace osu.Game.Tests.Visual.RealtimeMultiplayer +namespace osu.Game.Tests.Visual.Multiplayer { [HeadlessTest] public class TestSceneRealtimeRoomManager : MultiplayerTestScene diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsFilterControl.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsFilterControl.cs similarity index 93% rename from osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsFilterControl.cs rename to osu.Game.Tests/Visual/Playlists/TestScenePlaylistsFilterControl.cs index 427a69552d..66992b27a2 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsFilterControl.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsFilterControl.cs @@ -4,7 +4,7 @@ using osu.Framework.Graphics; using osu.Game.Screens.Multi.Lounge.Components; -namespace osu.Game.Tests.Visual.Multiplayer +namespace osu.Game.Tests.Visual.Playlists { public class TestScenePlaylistsFilterControl : OsuTestScene { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsLoungeSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs similarity index 95% rename from osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsLoungeSubScreen.cs rename to osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs index f8788f0c36..04555857f5 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs @@ -11,8 +11,9 @@ using osu.Game.Graphics.Containers; using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Lounge.Components; using osu.Game.Screens.Multi.Playlists; +using osu.Game.Tests.Visual.Multiplayer; -namespace osu.Game.Tests.Visual.Multiplayer +namespace osu.Game.Tests.Visual.Playlists { public class TestScenePlaylistsLoungeSubScreen : RoomManagerTestScene { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs similarity index 97% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs rename to osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs index 90abecd26d..2a110c0386 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs @@ -13,9 +13,9 @@ using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi; using osu.Game.Screens.Multi.Playlists; -namespace osu.Game.Tests.Visual.Multiplayer +namespace osu.Game.Tests.Visual.Playlists { - public class TestSceneMatchSettingsOverlay : MultiplayerTestScene + public class TestScenePlaylistsMatchSettingsOverlay : MultiplayerTestScene { [Cached(Type = typeof(IRoomManager))] private TestRoomManager roomManager = new TestRoomManager(); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsParticipantsList.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs similarity index 97% rename from osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsParticipantsList.cs rename to osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs index d71fdc42e3..d5553e4527 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsParticipantsList.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics; using osu.Game.Screens.Multi.Components; using osu.Game.Users; -namespace osu.Game.Tests.Visual.Multiplayer +namespace osu.Game.Tests.Visual.Playlists { public class TestScenePlaylistsParticipantsList : MultiplayerTestScene { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsResultsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs similarity index 99% rename from osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsResultsScreen.cs rename to osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs index 99fc6597ee..10ae44351b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsResultsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs @@ -24,7 +24,7 @@ using osu.Game.Screens.Ranking; using osu.Game.Tests.Beatmaps; using osu.Game.Users; -namespace osu.Game.Tests.Visual.Multiplayer +namespace osu.Game.Tests.Visual.Playlists { public class TestScenePlaylistsResultsScreen : ScreenTestScene { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs similarity index 99% rename from osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSubScreen.cs rename to osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs index 02cc03eca4..aebff14c80 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs @@ -22,7 +22,7 @@ using osu.Game.Tests.Beatmaps; using osu.Game.Users; using osuTK.Input; -namespace osu.Game.Tests.Visual.Multiplayer +namespace osu.Game.Tests.Visual.Playlists { public class TestScenePlaylistsRoomSubScreen : MultiplayerTestScene { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs similarity index 82% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneMultiScreen.cs rename to osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs index 9ac1eb8013..8203ca4845 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs @@ -6,17 +6,17 @@ using osu.Framework.Allocation; using osu.Game.Overlays; using osu.Game.Screens.Multi.Playlists; -namespace osu.Game.Tests.Visual.Multiplayer +namespace osu.Game.Tests.Visual.Playlists { [TestFixture] - public class TestSceneMultiScreen : ScreenTestScene + public class TestScenePlaylistsScreen : ScreenTestScene { protected override bool UseOnlineAPI => true; [Cached] private MusicController musicController { get; set; } = new MusicController(); - public TestSceneMultiScreen() + public TestScenePlaylistsScreen() { var multi = new PlaylistsMultiplayer(); From 5d4b73baa5f655c1c7f77a69228c06e895c40b6d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Dec 2020 13:38:11 +0900 Subject: [PATCH 300/328] RealtimeMultiplayer -> Multiplayer --- .../Multiplayer/RoomManagerTestScene.cs | 4 ++-- .../Visual/Multiplayer/TestRoomManager.cs | 2 +- .../TestSceneDrawableRoomPlaylist.cs | 2 +- .../Multiplayer/TestSceneLoungeRoomInfo.cs | 2 +- .../TestSceneLoungeRoomsContainer.cs | 2 +- .../TestSceneMatchBeatmapDetailArea.cs | 2 +- .../Multiplayer/TestSceneMatchHeader.cs | 2 +- ...Multiplayer.cs => TestSceneMultiplayer.cs} | 11 ++++----- ... => TestSceneMultiplayerMatchSubScreen.cs} | 21 ++++++++-------- ...> TestSceneMultiplayerParticipantsList.cs} | 7 +++--- ....cs => TestSceneMultiplayerReadyButton.cs} | 11 ++++----- ....cs => TestSceneMultiplayerRoomManager.cs} | 13 +++++----- .../Visual/Multiplayer/TestSceneRoomStatus.cs | 8 +++---- .../TestScenePlaylistsMatchSettingsOverlay.cs | 4 ++-- .../TestScenePlaylistsParticipantsList.cs | 2 +- .../TestScenePlaylistsResultsScreen.cs | 2 +- .../TestScenePlaylistsRoomSubScreen.cs | 4 ++-- .../IMultiplayerClient.cs | 2 +- .../IMultiplayerLoungeServer.cs | 2 +- .../IMultiplayerRoomServer.cs | 2 +- .../IMultiplayerServer.cs | 2 +- .../InvalidStateChangeException.cs | 2 +- .../InvalidStateException.cs | 2 +- .../MultiplayerClient.cs} | 6 ++--- .../MultiplayerRoom.cs | 2 +- .../MultiplayerRoomSettings.cs | 2 +- .../MultiplayerRoomState.cs | 4 ++-- .../MultiplayerRoomUser.cs | 2 +- .../MultiplayerUserState.cs | 2 +- .../NotHostException.cs | 2 +- .../NotJoinedRoomException.cs | 2 +- .../StatefulMultiplayerClient.cs | 6 ++--- .../{Multiplayer => Rooms}/APICreatedRoom.cs | 2 +- .../{Multiplayer => Rooms}/APILeaderboard.cs | 2 +- .../APIPlaylistBeatmap.cs | 2 +- .../{Multiplayer => Rooms}/APIScoreToken.cs | 2 +- .../CreateRoomRequest.cs | 2 +- .../CreateRoomScoreRequest.cs | 2 +- .../Online/{Multiplayer => Rooms}/GameType.cs | 2 +- .../GameTypes/GameTypeTag.cs | 2 +- .../GameTypes/GameTypeTagTeam.cs | 2 +- .../GameTypes/GameTypeTeamVersus.cs | 2 +- .../GameTypes/GameTypeTimeshift.cs | 2 +- .../GameTypes/GameTypeVersus.cs | 2 +- .../GameTypes/VersusRow.cs | 2 +- .../GetRoomLeaderboardRequest.cs | 2 +- .../{Multiplayer => Rooms}/GetRoomRequest.cs | 2 +- .../{Multiplayer => Rooms}/GetRoomsRequest.cs | 2 +- .../IndexPlaylistScoresRequest.cs | 2 +- .../IndexScoresParams.cs | 2 +- .../IndexedMultiplayerScores.cs | 2 +- .../{Multiplayer => Rooms}/JoinRoomRequest.cs | 2 +- .../MultiplayerScore.cs | 2 +- .../MultiplayerScores.cs | 2 +- .../MultiplayerScoresAround.cs | 2 +- .../{Multiplayer => Rooms}/PartRoomRequest.cs | 2 +- .../PlaylistExtensions.cs | 2 +- .../{Multiplayer => Rooms}/PlaylistItem.cs | 2 +- .../Online/{Multiplayer => Rooms}/Room.cs | 6 ++--- .../RoomAvailability.cs | 2 +- .../{Multiplayer => Rooms}/RoomCategory.cs | 4 ++-- .../{Multiplayer => Rooms}/RoomStatus.cs | 4 ++-- .../RoomStatuses/RoomStatusEnded.cs | 2 +- .../RoomStatuses/RoomStatusOpen.cs | 2 +- .../RoomStatuses/RoomStatusPlaying.cs | 2 +- .../ShowPlaylistUserScoreRequest.cs | 2 +- .../SubmitRoomScoreRequest.cs | 2 +- osu.Game/OsuGameBase.cs | 4 ++-- osu.Game/Screens/Menu/MainMenu.cs | 4 ++-- .../Multi/Components/DrawableGameType.cs | 2 +- .../Components/ListingPollingComponent.cs | 2 +- .../Components/MatchBeatmapDetailArea.cs | 2 +- .../Components/OverlinedPlaylistHeader.cs | 2 +- .../Screens/Multi/Components/ReadyButton.cs | 2 +- .../Screens/Multi/Components/RoomManager.cs | 2 +- .../Multi/Components/RoomPollingComponent.cs | 2 +- .../Multi/Components/RoomStatusInfo.cs | 4 ++-- .../Components/SelectionPollingComponent.cs | 2 +- .../Components/StatusColouredContainer.cs | 2 +- .../Screens/Multi/DrawableRoomPlaylist.cs | 2 +- .../Screens/Multi/DrawableRoomPlaylistItem.cs | 2 +- .../Multi/DrawableRoomPlaylistWithResults.cs | 2 +- osu.Game/Screens/Multi/IRoomManager.cs | 2 +- .../Multi/Lounge/Components/DrawableRoom.cs | 6 ++--- .../Multi/Lounge/Components/RoomsContainer.cs | 2 +- .../Screens/Multi/Lounge/LoungeSubScreen.cs | 2 +- .../Screens/Multi/Match/Components/Footer.cs | 2 +- .../Multi/Match/Components/GameTypePicker.cs | 4 ++-- .../Match/Components/MatchChatDisplay.cs | 2 +- .../Match/Components/MatchLeaderboard.cs | 2 +- .../Components/RoomAvailabilityPicker.cs | 2 +- osu.Game/Screens/Multi/Match/RoomSubScreen.cs | 4 ++-- .../CreateMultiplayerMatchButton.cs} | 6 ++--- .../Match/BeatmapSelectionControl.cs | 6 ++--- .../Match/MultiplayerMatchFooter.cs} | 10 ++++---- .../Match/MultiplayerMatchHeader.cs} | 6 ++--- .../Match/MultiplayerMatchSettingsOverlay.cs} | 6 ++--- .../Match/MultiplayerReadyButton.cs} | 8 +++---- .../Multiplayer.cs} | 16 ++++++------- .../MultiplayerFilterControl.cs} | 4 ++-- .../MultiplayerLoungeSubScreen.cs} | 10 ++++---- .../MultiplayerMatchSongSelect.cs} | 8 +++---- .../MultiplayerMatchSubScreen.cs} | 24 +++++++++---------- .../MultiplayerPlayer.cs} | 12 +++++----- .../MultiplayerResultsScreen.cs} | 8 +++---- .../MultiplayerRoomComposite.cs} | 6 ++--- .../MultiplayerRoomManager.cs} | 16 ++++++------- .../Participants/ParticipantPanel.cs | 6 ++--- .../Participants/ParticipantsList.cs | 4 ++-- .../Participants/ParticipantsListHeader.cs | 4 ++-- .../Participants/StateDisplay.cs | 4 ++-- .../Screens/Multi/MultiplayerComposite.cs | 2 +- .../{Multiplayer.cs => MultiplayerScreen.cs} | 6 ++--- .../Screens/Multi/Play/TimeshiftPlayer.cs | 2 +- .../Playlists/PlaylistsLoungeSubScreen.cs | 2 +- .../PlaylistsMatchSettingsOverlay.cs | 2 +- .../Multi/Playlists/PlaylistsMultiplayer.cs | 4 ++-- .../Multi/Playlists/PlaylistsReadyButton.cs | 2 +- .../Multi/Playlists/PlaylistsRoomSubScreen.cs | 4 ++-- .../Multi/Ranking/TimeshiftResultsScreen.cs | 2 +- osu.Game/Screens/Select/MatchSongSelect.cs | 2 +- .../MultiplayerTestScene.cs} | 16 ++++++------- .../TestMultiplayerClient.cs} | 6 ++--- .../TestMultiplayerRoomContainer.cs} | 16 ++++++------- .../TestMultiplayerRoomManager.cs} | 8 +++---- ...ltiplayerTestScene.cs => RoomTestScene.cs} | 4 ++-- osu.Game/Users/UserActivity.cs | 2 +- 127 files changed, 260 insertions(+), 265 deletions(-) rename osu.Game.Tests/Visual/Multiplayer/{TestSceneRealtimeMultiplayer.cs => TestSceneMultiplayer.cs} (77%) rename osu.Game.Tests/Visual/Multiplayer/{TestSceneRealtimeMatchSubScreen.cs => TestSceneMultiplayerMatchSubScreen.cs} (73%) rename osu.Game.Tests/Visual/Multiplayer/{TestSceneRealtimeMultiplayerParticipantsList.cs => TestSceneMultiplayerParticipantsList.cs} (94%) rename osu.Game.Tests/Visual/Multiplayer/{TestSceneRealtimeReadyButton.cs => TestSceneMultiplayerReadyButton.cs} (94%) rename osu.Game.Tests/Visual/Multiplayer/{TestSceneRealtimeRoomManager.cs => TestSceneMultiplayerRoomManager.cs} (92%) rename osu.Game/Online/{RealtimeMultiplayer => Multiplayer}/IMultiplayerClient.cs (98%) rename osu.Game/Online/{RealtimeMultiplayer => Multiplayer}/IMultiplayerLoungeServer.cs (93%) rename osu.Game/Online/{RealtimeMultiplayer => Multiplayer}/IMultiplayerRoomServer.cs (98%) rename osu.Game/Online/{RealtimeMultiplayer => Multiplayer}/IMultiplayerServer.cs (88%) rename osu.Game/Online/{RealtimeMultiplayer => Multiplayer}/InvalidStateChangeException.cs (93%) rename osu.Game/Online/{RealtimeMultiplayer => Multiplayer}/InvalidStateException.cs (92%) rename osu.Game/Online/{RealtimeMultiplayer/RealtimeMultiplayerClient.cs => Multiplayer/MultiplayerClient.cs} (97%) rename osu.Game/Online/{RealtimeMultiplayer => Multiplayer}/MultiplayerRoom.cs (98%) rename osu.Game/Online/{RealtimeMultiplayer => Multiplayer}/MultiplayerRoomSettings.cs (96%) rename osu.Game/Online/{RealtimeMultiplayer => Multiplayer}/MultiplayerRoomState.cs (86%) rename osu.Game/Online/{RealtimeMultiplayer => Multiplayer}/MultiplayerRoomUser.cs (96%) rename osu.Game/Online/{RealtimeMultiplayer => Multiplayer}/MultiplayerUserState.cs (98%) rename osu.Game/Online/{RealtimeMultiplayer => Multiplayer}/NotHostException.cs (92%) rename osu.Game/Online/{RealtimeMultiplayer => Multiplayer}/NotJoinedRoomException.cs (92%) rename osu.Game/Online/{RealtimeMultiplayer => Multiplayer}/StatefulMultiplayerClient.cs (99%) rename osu.Game/Online/{Multiplayer => Rooms}/APICreatedRoom.cs (88%) rename osu.Game/Online/{Multiplayer => Rooms}/APILeaderboard.cs (92%) rename osu.Game/Online/{Multiplayer => Rooms}/APIPlaylistBeatmap.cs (94%) rename osu.Game/Online/{Multiplayer => Rooms}/APIScoreToken.cs (88%) rename osu.Game/Online/{Multiplayer => Rooms}/CreateRoomRequest.cs (95%) rename osu.Game/Online/{Multiplayer => Rooms}/CreateRoomScoreRequest.cs (96%) rename osu.Game/Online/{Multiplayer => Rooms}/GameType.cs (93%) rename osu.Game/Online/{Multiplayer => Rooms}/GameTypes/GameTypeTag.cs (94%) rename osu.Game/Online/{Multiplayer => Rooms}/GameTypes/GameTypeTagTeam.cs (96%) rename osu.Game/Online/{Multiplayer => Rooms}/GameTypes/GameTypeTeamVersus.cs (95%) rename osu.Game/Online/{Multiplayer => Rooms}/GameTypes/GameTypeTimeshift.cs (93%) rename osu.Game/Online/{Multiplayer => Rooms}/GameTypes/GameTypeVersus.cs (92%) rename osu.Game/Online/{Multiplayer => Rooms}/GameTypes/VersusRow.cs (97%) rename osu.Game/Online/{Multiplayer => Rooms}/GetRoomLeaderboardRequest.cs (92%) rename osu.Game/Online/{Multiplayer => Rooms}/GetRoomRequest.cs (92%) rename osu.Game/Online/{Multiplayer => Rooms}/GetRoomsRequest.cs (96%) rename osu.Game/Online/{Multiplayer => Rooms}/IndexPlaylistScoresRequest.cs (97%) rename osu.Game/Online/{Multiplayer => Rooms}/IndexScoresParams.cs (94%) rename osu.Game/Online/{Multiplayer => Rooms}/IndexedMultiplayerScores.cs (95%) rename osu.Game/Online/{Multiplayer => Rooms}/JoinRoomRequest.cs (94%) rename osu.Game/Online/{Multiplayer => Rooms}/MultiplayerScore.cs (98%) rename osu.Game/Online/{Multiplayer => Rooms}/MultiplayerScores.cs (95%) rename osu.Game/Online/{Multiplayer => Rooms}/MultiplayerScoresAround.cs (95%) rename osu.Game/Online/{Multiplayer => Rooms}/PartRoomRequest.cs (94%) rename osu.Game/Online/{Multiplayer => Rooms}/PlaylistExtensions.cs (93%) rename osu.Game/Online/{Multiplayer => Rooms}/PlaylistItem.cs (98%) rename osu.Game/Online/{Multiplayer => Rooms}/Room.cs (97%) rename osu.Game/Online/{Multiplayer => Rooms}/RoomAvailability.cs (90%) rename osu.Game/Online/{Multiplayer => Rooms}/RoomCategory.cs (80%) rename osu.Game/Online/{Multiplayer => Rooms}/RoomStatus.cs (93%) rename osu.Game/Online/{Multiplayer => Rooms}/RoomStatuses/RoomStatusEnded.cs (88%) rename osu.Game/Online/{Multiplayer => Rooms}/RoomStatuses/RoomStatusOpen.cs (89%) rename osu.Game/Online/{Multiplayer => Rooms}/RoomStatuses/RoomStatusPlaying.cs (88%) rename osu.Game/Online/{Multiplayer => Rooms}/ShowPlaylistUserScoreRequest.cs (95%) rename osu.Game/Online/{Multiplayer => Rooms}/SubmitRoomScoreRequest.cs (97%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer/CreateRealtimeMatchButton.cs => Multiplayer/CreateMultiplayerMatchButton.cs} (77%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer => Multiplayer}/Match/BeatmapSelectionControl.cs (91%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer/Match/RealtimeMatchFooter.cs => Multiplayer/Match/MultiplayerMatchFooter.cs} (84%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer/Match/RealtimeMatchHeader.cs => Multiplayer/Match/MultiplayerMatchHeader.cs} (95%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs => Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs} (99%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer/Match/RealtimeReadyButton.cs => Multiplayer/Match/MultiplayerReadyButton.cs} (95%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer/RealtimeMultiplayer.cs => Multiplayer/Multiplayer.cs} (86%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer/RealtimeFilterControl.cs => Multiplayer/MultiplayerFilterControl.cs} (79%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer/RealtimeLoungeSubScreen.cs => Multiplayer/MultiplayerLoungeSubScreen.cs} (79%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer/RealtimeMatchSongSelect.cs => Multiplayer/MultiplayerMatchSongSelect.cs} (92%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer/RealtimeMatchSubScreen.cs => Multiplayer/MultiplayerMatchSubScreen.cs} (92%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer/RealtimePlayer.cs => Multiplayer/MultiplayerPlayer.cs} (93%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer/RealtimeResultsScreen.cs => Multiplayer/MultiplayerResultsScreen.cs} (55%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer/RealtimeRoomComposite.cs => Multiplayer/MultiplayerRoomComposite.cs} (83%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer/RealtimeRoomManager.cs => Multiplayer/MultiplayerRoomManager.cs} (92%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer => Multiplayer}/Participants/ParticipantPanel.cs (97%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer => Multiplayer}/Participants/ParticipantsList.cs (93%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer => Multiplayer}/Participants/ParticipantsListHeader.cs (86%) rename osu.Game/Screens/Multi/{RealtimeMultiplayer => Multiplayer}/Participants/StateDisplay.cs (97%) rename osu.Game/Screens/Multi/{Multiplayer.cs => MultiplayerScreen.cs} (99%) rename osu.Game/Tests/Visual/{RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs => Multiplayer/MultiplayerTestScene.cs} (67%) rename osu.Game/Tests/Visual/{RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs => Multiplayer/TestMultiplayerClient.cs} (95%) rename osu.Game/Tests/Visual/{RealtimeMultiplayer/TestRealtimeRoomContainer.cs => Multiplayer/TestMultiplayerRoomContainer.cs} (67%) rename osu.Game/Tests/Visual/{RealtimeMultiplayer/TestRealtimeRoomManager.cs => Multiplayer/TestMultiplayerRoomManager.cs} (95%) rename osu.Game/Tests/Visual/{MultiplayerTestScene.cs => RoomTestScene.cs} (90%) diff --git a/osu.Game.Tests/Visual/Multiplayer/RoomManagerTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/RoomManagerTestScene.cs index 8b7e0fd9da..a2c496a504 100644 --- a/osu.Game.Tests/Visual/Multiplayer/RoomManagerTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/RoomManagerTestScene.cs @@ -4,14 +4,14 @@ using System; using osu.Framework.Allocation; using osu.Game.Beatmaps; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Screens.Multi; using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { - public abstract class RoomManagerTestScene : MultiplayerTestScene + public abstract class RoomManagerTestScene : RoomTestScene { [Cached(Type = typeof(IRoomManager))] protected TestRoomManager RoomManager { get; } = new TestRoomManager(); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs b/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs index 9dd4aea4bd..7d9d4a6542 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs @@ -3,7 +3,7 @@ using System; using osu.Framework.Bindables; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Multi; namespace osu.Game.Tests.Visual.Multiplayer diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index 55b026eff6..722e1a50ef 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -13,7 +13,7 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs index 9baaa42c83..1359274512 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs @@ -4,7 +4,7 @@ using System; using NUnit.Framework; using osu.Framework.Graphics; -using osu.Game.Online.Multiplayer.RoomStatuses; +using osu.Game.Online.Rooms.RoomStatuses; using osu.Game.Screens.Multi.Lounge.Components; using osu.Game.Users; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs index e33d15cfff..9b6a6de7c2 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs @@ -6,7 +6,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Multi.Lounge.Components; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs index 6b1d90e06e..f4e0cc415c 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs @@ -5,7 +5,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs index ec5292e51e..e162009771 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs @@ -3,7 +3,7 @@ using NUnit.Framework; using osu.Game.Beatmaps; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.Multi.Match.Components; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs similarity index 77% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMultiplayer.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index cc07bb8e79..5c07b9d0ea 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -3,16 +3,15 @@ using NUnit.Framework; using osu.Game.Screens.Multi.Components; -using osu.Game.Tests.Visual.RealtimeMultiplayer; using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneRealtimeMultiplayer : RealtimeMultiplayerTestScene + public class TestSceneMultiplayer : MultiplayerTestScene { - public TestSceneRealtimeMultiplayer() + public TestSceneMultiplayer() { - var multi = new TestRealtimeMultiplayer(); + var multi = new TestMultiplayer(); AddStep("show", () => LoadScreen(multi)); AddUntilStep("wait for loaded", () => multi.IsLoaded); @@ -40,9 +39,9 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("room has 1 user", () => Client.Room?.Users.Count == 1); } - private class TestRealtimeMultiplayer : Screens.Multi.RealtimeMultiplayer.RealtimeMultiplayer + private class TestMultiplayer : Screens.Multi.Multiplayer.Multiplayer { - protected override RoomManager CreateRoomManager() => new TestRealtimeRoomManager(); + protected override RoomManager CreateRoomManager() => new TestMultiplayerRoomManager(); } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs similarity index 73% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMatchSubScreen.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs index dff375d1bb..6dc26dae57 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs @@ -5,21 +5,20 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Screens; using osu.Framework.Testing; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Rulesets.Osu; -using osu.Game.Screens.Multi.RealtimeMultiplayer; -using osu.Game.Screens.Multi.RealtimeMultiplayer.Match; +using osu.Game.Screens.Multi.Multiplayer; +using osu.Game.Screens.Multi.Multiplayer.Match; using osu.Game.Tests.Beatmaps; -using osu.Game.Tests.Visual.RealtimeMultiplayer; using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneRealtimeMatchSubScreen : RealtimeMultiplayerTestScene + public class TestSceneMultiplayerMatchSubScreen : MultiplayerTestScene { - private RealtimeMatchSubScreen screen; + private MultiplayerMatchSubScreen screen; - public TestSceneRealtimeMatchSubScreen() + public TestSceneMultiplayerMatchSubScreen() : base(false) { } @@ -33,14 +32,14 @@ namespace osu.Game.Tests.Visual.Multiplayer [SetUpSteps] public void SetupSteps() { - AddStep("load match", () => LoadScreen(screen = new RealtimeMatchSubScreen(Room))); + AddStep("load match", () => LoadScreen(screen = new MultiplayerMatchSubScreen(Room))); AddUntilStep("wait for load", () => screen.IsCurrentScreen()); } [Test] public void TestSettingValidity() { - AddAssert("create button not enabled", () => !this.ChildrenOfType().Single().Enabled.Value); + AddAssert("create button not enabled", () => !this.ChildrenOfType().Single().Enabled.Value); AddStep("set playlist", () => { @@ -51,7 +50,7 @@ namespace osu.Game.Tests.Visual.Multiplayer }); }); - AddAssert("create button enabled", () => this.ChildrenOfType().Single().Enabled.Value); + AddAssert("create button enabled", () => this.ChildrenOfType().Single().Enabled.Value); } [Test] @@ -68,7 +67,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("click create button", () => { - InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); InputManager.Click(MouseButton.Left); }); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs similarity index 94% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs index 7c26918927..ee2fa4ef5a 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs @@ -7,15 +7,14 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Testing; using osu.Framework.Utils; -using osu.Game.Online.RealtimeMultiplayer; -using osu.Game.Screens.Multi.RealtimeMultiplayer.Participants; -using osu.Game.Tests.Visual.RealtimeMultiplayer; +using osu.Game.Online.Multiplayer; +using osu.Game.Screens.Multi.Multiplayer.Participants; using osu.Game.Users; using osuTK; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneRealtimeMultiplayerParticipantsList : RealtimeMultiplayerTestScene + public class TestSceneMultiplayerParticipantsList : MultiplayerTestScene { [SetUp] public new void Setup() => Schedule(() => diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeReadyButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs similarity index 94% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeReadyButton.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs index 3c92276629..c8ebdb1b76 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeReadyButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs @@ -10,20 +10,19 @@ using osu.Framework.Platform; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Rooms; using osu.Game.Rulesets; -using osu.Game.Screens.Multi.RealtimeMultiplayer.Match; +using osu.Game.Screens.Multi.Multiplayer.Match; using osu.Game.Tests.Resources; -using osu.Game.Tests.Visual.RealtimeMultiplayer; using osu.Game.Users; using osuTK; using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneRealtimeReadyButton : RealtimeMultiplayerTestScene + public class TestSceneMultiplayerReadyButton : MultiplayerTestScene { - private RealtimeReadyButton button; + private MultiplayerReadyButton button; private BeatmapManager beatmaps; private RulesetStore rulesets; @@ -43,7 +42,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap); - Child = button = new RealtimeReadyButton + Child = button = new MultiplayerReadyButton { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeRoomManager.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs similarity index 92% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeRoomManager.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs index ba90e0840b..292c4846ab 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRealtimeRoomManager.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs @@ -4,16 +4,15 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Testing; -using osu.Game.Online.Multiplayer; -using osu.Game.Tests.Visual.RealtimeMultiplayer; +using osu.Game.Online.Rooms; namespace osu.Game.Tests.Visual.Multiplayer { [HeadlessTest] - public class TestSceneRealtimeRoomManager : MultiplayerTestScene + public class TestSceneMultiplayerRoomManager : MultiplayerTestScene { - private TestRealtimeRoomContainer roomContainer; - private TestRealtimeRoomManager roomManager => roomContainer.RoomManager; + private TestMultiplayerRoomContainer roomContainer; + private TestMultiplayerRoomManager roomManager => roomContainer.RoomManager; [Test] public void TestPollsInitially() @@ -137,9 +136,9 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("multiplayer room joined", () => roomContainer.Client.Room != null); } - private TestRealtimeRoomManager createRoomManager() + private TestMultiplayerRoomManager createRoomManager() { - Child = roomContainer = new TestRealtimeRoomContainer + Child = roomContainer = new TestMultiplayerRoomContainer { RoomManager = { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs index a6dd1437f7..788255501b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs @@ -4,8 +4,8 @@ using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.RoomStatuses; +using osu.Game.Online.Rooms; +using osu.Game.Online.Rooms.RoomStatuses; using osu.Game.Screens.Multi.Lounge.Components; namespace osu.Game.Tests.Visual.Multiplayer @@ -40,9 +40,9 @@ namespace osu.Game.Tests.Visual.Multiplayer }) { MatchingFilter = true }, new DrawableRoom(new Room { - Name = { Value = "Open (realtime)" }, + Name = { Value = "Open" }, Status = { Value = new RoomStatusOpen() }, - Category = { Value = RoomCategory.Realtime } + Category = { Value = RoomCategory.Multiplayer } }) { MatchingFilter = true }, } }; diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs index 2a110c0386..4e75619f13 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs @@ -9,13 +9,13 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Multi; using osu.Game.Screens.Multi.Playlists; namespace osu.Game.Tests.Visual.Playlists { - public class TestScenePlaylistsMatchSettingsOverlay : MultiplayerTestScene + public class TestScenePlaylistsMatchSettingsOverlay : RoomTestScene { [Cached(Type = typeof(IRoomManager))] private TestRoomManager roomManager = new TestRoomManager(); diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs index d5553e4527..5a0f196df9 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs @@ -8,7 +8,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Playlists { - public class TestScenePlaylistsParticipantsList : MultiplayerTestScene + public class TestScenePlaylistsParticipantsList : RoomTestScene { [SetUp] public new void Setup() => Schedule(() => diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs index 10ae44351b..b42f2e1d2d 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs @@ -15,7 +15,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs index aebff14c80..96ff93a145 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs @@ -12,7 +12,7 @@ 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.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Multi; @@ -24,7 +24,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Playlists { - public class TestScenePlaylistsRoomSubScreen : MultiplayerTestScene + public class TestScenePlaylistsRoomSubScreen : RoomTestScene { protected override bool UseOnlineAPI => true; diff --git a/osu.Game/Online/RealtimeMultiplayer/IMultiplayerClient.cs b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs similarity index 98% rename from osu.Game/Online/RealtimeMultiplayer/IMultiplayerClient.cs rename to osu.Game/Online/Multiplayer/IMultiplayerClient.cs index 9af0047137..b97fcc9ae7 100644 --- a/osu.Game/Online/RealtimeMultiplayer/IMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { /// /// An interface defining a multiplayer client instance. diff --git a/osu.Game/Online/RealtimeMultiplayer/IMultiplayerLoungeServer.cs b/osu.Game/Online/Multiplayer/IMultiplayerLoungeServer.cs similarity index 93% rename from osu.Game/Online/RealtimeMultiplayer/IMultiplayerLoungeServer.cs rename to osu.Game/Online/Multiplayer/IMultiplayerLoungeServer.cs index eecb61bcb0..4640640c5f 100644 --- a/osu.Game/Online/RealtimeMultiplayer/IMultiplayerLoungeServer.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerLoungeServer.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { /// /// Interface for an out-of-room multiplayer server. diff --git a/osu.Game/Online/RealtimeMultiplayer/IMultiplayerRoomServer.cs b/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs similarity index 98% rename from osu.Game/Online/RealtimeMultiplayer/IMultiplayerRoomServer.cs rename to osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs index 12dfe481c4..481e3fb1de 100644 --- a/osu.Game/Online/RealtimeMultiplayer/IMultiplayerRoomServer.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { /// /// Interface for an in-room multiplayer server. diff --git a/osu.Game/Online/RealtimeMultiplayer/IMultiplayerServer.cs b/osu.Game/Online/Multiplayer/IMultiplayerServer.cs similarity index 88% rename from osu.Game/Online/RealtimeMultiplayer/IMultiplayerServer.cs rename to osu.Game/Online/Multiplayer/IMultiplayerServer.cs index 1d093af743..d3a070af6d 100644 --- a/osu.Game/Online/RealtimeMultiplayer/IMultiplayerServer.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerServer.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { /// /// An interface defining the multiplayer server instance. diff --git a/osu.Game/Online/RealtimeMultiplayer/InvalidStateChangeException.cs b/osu.Game/Online/Multiplayer/InvalidStateChangeException.cs similarity index 93% rename from osu.Game/Online/RealtimeMultiplayer/InvalidStateChangeException.cs rename to osu.Game/Online/Multiplayer/InvalidStateChangeException.cs index d9a276fc19..69b6d4bc13 100644 --- a/osu.Game/Online/RealtimeMultiplayer/InvalidStateChangeException.cs +++ b/osu.Game/Online/Multiplayer/InvalidStateChangeException.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.Serialization; using Microsoft.AspNetCore.SignalR; -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { [Serializable] public class InvalidStateChangeException : HubException diff --git a/osu.Game/Online/RealtimeMultiplayer/InvalidStateException.cs b/osu.Game/Online/Multiplayer/InvalidStateException.cs similarity index 92% rename from osu.Game/Online/RealtimeMultiplayer/InvalidStateException.cs rename to osu.Game/Online/Multiplayer/InvalidStateException.cs index 7791bfc69f..77a3533dd3 100644 --- a/osu.Game/Online/RealtimeMultiplayer/InvalidStateException.cs +++ b/osu.Game/Online/Multiplayer/InvalidStateException.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.Serialization; using Microsoft.AspNetCore.SignalR; -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { [Serializable] public class InvalidStateException : HubException diff --git a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs similarity index 97% rename from osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs rename to osu.Game/Online/Multiplayer/MultiplayerClient.cs index cb5c21a8c9..24ea6abc4a 100644 --- a/osu.Game/Online/RealtimeMultiplayer/RealtimeMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -15,9 +15,9 @@ using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Game.Online.API; -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { - public class RealtimeMultiplayerClient : StatefulMultiplayerClient + public class MultiplayerClient : StatefulMultiplayerClient { public override IBindable IsConnected => isConnected; @@ -31,7 +31,7 @@ namespace osu.Game.Online.RealtimeMultiplayer private readonly string endpoint; - public RealtimeMultiplayerClient(EndpointConfiguration endpoints) + public MultiplayerClient(EndpointConfiguration endpoints) { endpoint = endpoints.MultiplayerEndpointUrl; } diff --git a/osu.Game/Online/RealtimeMultiplayer/MultiplayerRoom.cs b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs similarity index 98% rename from osu.Game/Online/RealtimeMultiplayer/MultiplayerRoom.cs rename to osu.Game/Online/Multiplayer/MultiplayerRoom.cs index e009a34707..2134e50d72 100644 --- a/osu.Game/Online/RealtimeMultiplayer/MultiplayerRoom.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs @@ -9,7 +9,7 @@ using System.Threading; using Newtonsoft.Json; using osu.Framework.Allocation; -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { /// /// A multiplayer room. diff --git a/osu.Game/Online/RealtimeMultiplayer/MultiplayerRoomSettings.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs similarity index 96% rename from osu.Game/Online/RealtimeMultiplayer/MultiplayerRoomSettings.cs rename to osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs index 60e0d1292e..857b38ea60 100644 --- a/osu.Game/Online/RealtimeMultiplayer/MultiplayerRoomSettings.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs @@ -9,7 +9,7 @@ using System.Linq; using JetBrains.Annotations; using osu.Game.Online.API; -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { [Serializable] public class MultiplayerRoomSettings : IEquatable diff --git a/osu.Game/Online/RealtimeMultiplayer/MultiplayerRoomState.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomState.cs similarity index 86% rename from osu.Game/Online/RealtimeMultiplayer/MultiplayerRoomState.cs rename to osu.Game/Online/Multiplayer/MultiplayerRoomState.cs index 69c04b09a8..48f25d7ca2 100644 --- a/osu.Game/Online/RealtimeMultiplayer/MultiplayerRoomState.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomState.cs @@ -3,10 +3,10 @@ #nullable enable -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { /// - /// The current overall state of a realtime multiplayer room. + /// The current overall state of a multiplayer room. /// public enum MultiplayerRoomState { diff --git a/osu.Game/Online/RealtimeMultiplayer/MultiplayerRoomUser.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs similarity index 96% rename from osu.Game/Online/RealtimeMultiplayer/MultiplayerRoomUser.cs rename to osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs index caf1a70197..99624dc3e7 100644 --- a/osu.Game/Online/RealtimeMultiplayer/MultiplayerRoomUser.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs @@ -7,7 +7,7 @@ using System; using Newtonsoft.Json; using osu.Game.Users; -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { [Serializable] public class MultiplayerRoomUser : IEquatable diff --git a/osu.Game/Online/RealtimeMultiplayer/MultiplayerUserState.cs b/osu.Game/Online/Multiplayer/MultiplayerUserState.cs similarity index 98% rename from osu.Game/Online/RealtimeMultiplayer/MultiplayerUserState.cs rename to osu.Game/Online/Multiplayer/MultiplayerUserState.cs index ed9acd146e..e54c71cd85 100644 --- a/osu.Game/Online/RealtimeMultiplayer/MultiplayerUserState.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerUserState.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { public enum MultiplayerUserState { diff --git a/osu.Game/Online/RealtimeMultiplayer/NotHostException.cs b/osu.Game/Online/Multiplayer/NotHostException.cs similarity index 92% rename from osu.Game/Online/RealtimeMultiplayer/NotHostException.cs rename to osu.Game/Online/Multiplayer/NotHostException.cs index 56095043f0..051cde45a0 100644 --- a/osu.Game/Online/RealtimeMultiplayer/NotHostException.cs +++ b/osu.Game/Online/Multiplayer/NotHostException.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.Serialization; using Microsoft.AspNetCore.SignalR; -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { [Serializable] public class NotHostException : HubException diff --git a/osu.Game/Online/RealtimeMultiplayer/NotJoinedRoomException.cs b/osu.Game/Online/Multiplayer/NotJoinedRoomException.cs similarity index 92% rename from osu.Game/Online/RealtimeMultiplayer/NotJoinedRoomException.cs rename to osu.Game/Online/Multiplayer/NotJoinedRoomException.cs index 7a6e089d0b..0e9902f002 100644 --- a/osu.Game/Online/RealtimeMultiplayer/NotJoinedRoomException.cs +++ b/osu.Game/Online/Multiplayer/NotJoinedRoomException.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.Serialization; using Microsoft.AspNetCore.SignalR; -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { [Serializable] public class NotJoinedRoomException : HubException diff --git a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs similarity index 99% rename from osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs rename to osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs index 9149bdcba3..e422e982ae 100644 --- a/osu.Game/Online/RealtimeMultiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs @@ -18,13 +18,13 @@ using osu.Game.Extensions; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.RoomStatuses; +using osu.Game.Online.Rooms; +using osu.Game.Online.Rooms.RoomStatuses; using osu.Game.Rulesets; using osu.Game.Users; using osu.Game.Utils; -namespace osu.Game.Online.RealtimeMultiplayer +namespace osu.Game.Online.Multiplayer { public abstract class StatefulMultiplayerClient : Component, IMultiplayerClient, IMultiplayerRoomServer { diff --git a/osu.Game/Online/Multiplayer/APICreatedRoom.cs b/osu.Game/Online/Rooms/APICreatedRoom.cs similarity index 88% rename from osu.Game/Online/Multiplayer/APICreatedRoom.cs rename to osu.Game/Online/Rooms/APICreatedRoom.cs index 2a3bb39647..d1062b2306 100644 --- a/osu.Game/Online/Multiplayer/APICreatedRoom.cs +++ b/osu.Game/Online/Rooms/APICreatedRoom.cs @@ -3,7 +3,7 @@ using Newtonsoft.Json; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class APICreatedRoom : Room { diff --git a/osu.Game/Online/Multiplayer/APILeaderboard.cs b/osu.Game/Online/Rooms/APILeaderboard.cs similarity index 92% rename from osu.Game/Online/Multiplayer/APILeaderboard.cs rename to osu.Game/Online/Rooms/APILeaderboard.cs index 65863d6e0e..c487123906 100644 --- a/osu.Game/Online/Multiplayer/APILeaderboard.cs +++ b/osu.Game/Online/Rooms/APILeaderboard.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using Newtonsoft.Json; using osu.Game.Online.API.Requests.Responses; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class APILeaderboard { diff --git a/osu.Game/Online/Multiplayer/APIPlaylistBeatmap.cs b/osu.Game/Online/Rooms/APIPlaylistBeatmap.cs similarity index 94% rename from osu.Game/Online/Multiplayer/APIPlaylistBeatmap.cs rename to osu.Game/Online/Rooms/APIPlaylistBeatmap.cs index 98972ef36d..973dccd528 100644 --- a/osu.Game/Online/Multiplayer/APIPlaylistBeatmap.cs +++ b/osu.Game/Online/Rooms/APIPlaylistBeatmap.cs @@ -6,7 +6,7 @@ using osu.Game.Beatmaps; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class APIPlaylistBeatmap : APIBeatmap { diff --git a/osu.Game/Online/Multiplayer/APIScoreToken.cs b/osu.Game/Online/Rooms/APIScoreToken.cs similarity index 88% rename from osu.Game/Online/Multiplayer/APIScoreToken.cs rename to osu.Game/Online/Rooms/APIScoreToken.cs index 1f0063d94e..f652c1720d 100644 --- a/osu.Game/Online/Multiplayer/APIScoreToken.cs +++ b/osu.Game/Online/Rooms/APIScoreToken.cs @@ -3,7 +3,7 @@ using Newtonsoft.Json; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class APIScoreToken { diff --git a/osu.Game/Online/Multiplayer/CreateRoomRequest.cs b/osu.Game/Online/Rooms/CreateRoomRequest.cs similarity index 95% rename from osu.Game/Online/Multiplayer/CreateRoomRequest.cs rename to osu.Game/Online/Rooms/CreateRoomRequest.cs index 5be99e9442..f058eb9ba8 100644 --- a/osu.Game/Online/Multiplayer/CreateRoomRequest.cs +++ b/osu.Game/Online/Rooms/CreateRoomRequest.cs @@ -6,7 +6,7 @@ using Newtonsoft.Json; using osu.Framework.IO.Network; using osu.Game.Online.API; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class CreateRoomRequest : APIRequest { diff --git a/osu.Game/Online/Multiplayer/CreateRoomScoreRequest.cs b/osu.Game/Online/Rooms/CreateRoomScoreRequest.cs similarity index 96% rename from osu.Game/Online/Multiplayer/CreateRoomScoreRequest.cs rename to osu.Game/Online/Rooms/CreateRoomScoreRequest.cs index 2d99b12519..afd0dadc7e 100644 --- a/osu.Game/Online/Multiplayer/CreateRoomScoreRequest.cs +++ b/osu.Game/Online/Rooms/CreateRoomScoreRequest.cs @@ -5,7 +5,7 @@ using System.Net.Http; using osu.Framework.IO.Network; using osu.Game.Online.API; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class CreateRoomScoreRequest : APIRequest { diff --git a/osu.Game/Online/Multiplayer/GameType.cs b/osu.Game/Online/Rooms/GameType.cs similarity index 93% rename from osu.Game/Online/Multiplayer/GameType.cs rename to osu.Game/Online/Rooms/GameType.cs index 10381d93bb..caa352d812 100644 --- a/osu.Game/Online/Multiplayer/GameType.cs +++ b/osu.Game/Online/Rooms/GameType.cs @@ -4,7 +4,7 @@ using osu.Framework.Graphics; using osu.Game.Graphics; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public abstract class GameType { diff --git a/osu.Game/Online/Multiplayer/GameTypes/GameTypeTag.cs b/osu.Game/Online/Rooms/GameTypes/GameTypeTag.cs similarity index 94% rename from osu.Game/Online/Multiplayer/GameTypes/GameTypeTag.cs rename to osu.Game/Online/Rooms/GameTypes/GameTypeTag.cs index 5ba5f1a415..e468612738 100644 --- a/osu.Game/Online/Multiplayer/GameTypes/GameTypeTag.cs +++ b/osu.Game/Online/Rooms/GameTypes/GameTypeTag.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osuTK; -namespace osu.Game.Online.Multiplayer.GameTypes +namespace osu.Game.Online.Rooms.GameTypes { public class GameTypeTag : GameType { diff --git a/osu.Game/Online/Multiplayer/GameTypes/GameTypeTagTeam.cs b/osu.Game/Online/Rooms/GameTypes/GameTypeTagTeam.cs similarity index 96% rename from osu.Game/Online/Multiplayer/GameTypes/GameTypeTagTeam.cs rename to osu.Game/Online/Rooms/GameTypes/GameTypeTagTeam.cs index ef0a00a9f0..b82f203fac 100644 --- a/osu.Game/Online/Multiplayer/GameTypes/GameTypeTagTeam.cs +++ b/osu.Game/Online/Rooms/GameTypes/GameTypeTagTeam.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osuTK; -namespace osu.Game.Online.Multiplayer.GameTypes +namespace osu.Game.Online.Rooms.GameTypes { public class GameTypeTagTeam : GameType { diff --git a/osu.Game/Online/Multiplayer/GameTypes/GameTypeTeamVersus.cs b/osu.Game/Online/Rooms/GameTypes/GameTypeTeamVersus.cs similarity index 95% rename from osu.Game/Online/Multiplayer/GameTypes/GameTypeTeamVersus.cs rename to osu.Game/Online/Rooms/GameTypes/GameTypeTeamVersus.cs index c25bce1c71..5ad4033dc9 100644 --- a/osu.Game/Online/Multiplayer/GameTypes/GameTypeTeamVersus.cs +++ b/osu.Game/Online/Rooms/GameTypes/GameTypeTeamVersus.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osuTK; -namespace osu.Game.Online.Multiplayer.GameTypes +namespace osu.Game.Online.Rooms.GameTypes { public class GameTypeTeamVersus : GameType { diff --git a/osu.Game/Online/Multiplayer/GameTypes/GameTypeTimeshift.cs b/osu.Game/Online/Rooms/GameTypes/GameTypeTimeshift.cs similarity index 93% rename from osu.Game/Online/Multiplayer/GameTypes/GameTypeTimeshift.cs rename to osu.Game/Online/Rooms/GameTypes/GameTypeTimeshift.cs index 5840ccb803..3425c6c5cd 100644 --- a/osu.Game/Online/Multiplayer/GameTypes/GameTypeTimeshift.cs +++ b/osu.Game/Online/Rooms/GameTypes/GameTypeTimeshift.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osuTK; -namespace osu.Game.Online.Multiplayer.GameTypes +namespace osu.Game.Online.Rooms.GameTypes { public class GameTypePlaylists : GameType { diff --git a/osu.Game/Online/Multiplayer/GameTypes/GameTypeVersus.cs b/osu.Game/Online/Rooms/GameTypes/GameTypeVersus.cs similarity index 92% rename from osu.Game/Online/Multiplayer/GameTypes/GameTypeVersus.cs rename to osu.Game/Online/Rooms/GameTypes/GameTypeVersus.cs index 4640c7b361..3783cc67b0 100644 --- a/osu.Game/Online/Multiplayer/GameTypes/GameTypeVersus.cs +++ b/osu.Game/Online/Rooms/GameTypes/GameTypeVersus.cs @@ -4,7 +4,7 @@ using osu.Framework.Graphics; using osu.Game.Graphics; -namespace osu.Game.Online.Multiplayer.GameTypes +namespace osu.Game.Online.Rooms.GameTypes { public class GameTypeVersus : GameType { diff --git a/osu.Game/Online/Multiplayer/GameTypes/VersusRow.cs b/osu.Game/Online/Rooms/GameTypes/VersusRow.cs similarity index 97% rename from osu.Game/Online/Multiplayer/GameTypes/VersusRow.cs rename to osu.Game/Online/Rooms/GameTypes/VersusRow.cs index b6e8e4458f..0bd09a23ac 100644 --- a/osu.Game/Online/Multiplayer/GameTypes/VersusRow.cs +++ b/osu.Game/Online/Rooms/GameTypes/VersusRow.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.Shapes; using osuTK; using osuTK.Graphics; -namespace osu.Game.Online.Multiplayer.GameTypes +namespace osu.Game.Online.Rooms.GameTypes { public class VersusRow : FillFlowContainer { diff --git a/osu.Game/Online/Multiplayer/GetRoomLeaderboardRequest.cs b/osu.Game/Online/Rooms/GetRoomLeaderboardRequest.cs similarity index 92% rename from osu.Game/Online/Multiplayer/GetRoomLeaderboardRequest.cs rename to osu.Game/Online/Rooms/GetRoomLeaderboardRequest.cs index 37c21457bc..15f1221a00 100644 --- a/osu.Game/Online/Multiplayer/GetRoomLeaderboardRequest.cs +++ b/osu.Game/Online/Rooms/GetRoomLeaderboardRequest.cs @@ -3,7 +3,7 @@ using osu.Game.Online.API; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class GetRoomLeaderboardRequest : APIRequest { diff --git a/osu.Game/Online/Multiplayer/GetRoomRequest.cs b/osu.Game/Online/Rooms/GetRoomRequest.cs similarity index 92% rename from osu.Game/Online/Multiplayer/GetRoomRequest.cs rename to osu.Game/Online/Rooms/GetRoomRequest.cs index 449c2c8e31..ce117075c7 100644 --- a/osu.Game/Online/Multiplayer/GetRoomRequest.cs +++ b/osu.Game/Online/Rooms/GetRoomRequest.cs @@ -3,7 +3,7 @@ using osu.Game.Online.API; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class GetRoomRequest : APIRequest { diff --git a/osu.Game/Online/Multiplayer/GetRoomsRequest.cs b/osu.Game/Online/Rooms/GetRoomsRequest.cs similarity index 96% rename from osu.Game/Online/Multiplayer/GetRoomsRequest.cs rename to osu.Game/Online/Rooms/GetRoomsRequest.cs index a0609f77dd..5084b8627f 100644 --- a/osu.Game/Online/Multiplayer/GetRoomsRequest.cs +++ b/osu.Game/Online/Rooms/GetRoomsRequest.cs @@ -7,7 +7,7 @@ using osu.Framework.IO.Network; using osu.Game.Online.API; using osu.Game.Screens.Multi.Lounge.Components; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class GetRoomsRequest : APIRequest> { diff --git a/osu.Game/Online/Multiplayer/IndexPlaylistScoresRequest.cs b/osu.Game/Online/Rooms/IndexPlaylistScoresRequest.cs similarity index 97% rename from osu.Game/Online/Multiplayer/IndexPlaylistScoresRequest.cs rename to osu.Game/Online/Rooms/IndexPlaylistScoresRequest.cs index 684d0aecd8..43f80a2dc4 100644 --- a/osu.Game/Online/Multiplayer/IndexPlaylistScoresRequest.cs +++ b/osu.Game/Online/Rooms/IndexPlaylistScoresRequest.cs @@ -8,7 +8,7 @@ using osu.Game.Extensions; using osu.Game.Online.API; using osu.Game.Online.API.Requests; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { /// /// Returns a list of scores for the specified playlist item. diff --git a/osu.Game/Online/Multiplayer/IndexScoresParams.cs b/osu.Game/Online/Rooms/IndexScoresParams.cs similarity index 94% rename from osu.Game/Online/Multiplayer/IndexScoresParams.cs rename to osu.Game/Online/Rooms/IndexScoresParams.cs index a511e9a780..3df8c8e753 100644 --- a/osu.Game/Online/Multiplayer/IndexScoresParams.cs +++ b/osu.Game/Online/Rooms/IndexScoresParams.cs @@ -6,7 +6,7 @@ using JetBrains.Annotations; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { /// /// A collection of parameters which should be passed to the index endpoint to fetch the next page. diff --git a/osu.Game/Online/Multiplayer/IndexedMultiplayerScores.cs b/osu.Game/Online/Rooms/IndexedMultiplayerScores.cs similarity index 95% rename from osu.Game/Online/Multiplayer/IndexedMultiplayerScores.cs rename to osu.Game/Online/Rooms/IndexedMultiplayerScores.cs index e237b7e3fb..2008d1aa52 100644 --- a/osu.Game/Online/Multiplayer/IndexedMultiplayerScores.cs +++ b/osu.Game/Online/Rooms/IndexedMultiplayerScores.cs @@ -4,7 +4,7 @@ using JetBrains.Annotations; using Newtonsoft.Json; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { /// /// A object returned via a . diff --git a/osu.Game/Online/Multiplayer/JoinRoomRequest.cs b/osu.Game/Online/Rooms/JoinRoomRequest.cs similarity index 94% rename from osu.Game/Online/Multiplayer/JoinRoomRequest.cs rename to osu.Game/Online/Rooms/JoinRoomRequest.cs index 74375af856..faa20a3e6c 100644 --- a/osu.Game/Online/Multiplayer/JoinRoomRequest.cs +++ b/osu.Game/Online/Rooms/JoinRoomRequest.cs @@ -5,7 +5,7 @@ using System.Net.Http; using osu.Framework.IO.Network; using osu.Game.Online.API; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class JoinRoomRequest : APIRequest { diff --git a/osu.Game/Online/Multiplayer/MultiplayerScore.cs b/osu.Game/Online/Rooms/MultiplayerScore.cs similarity index 98% rename from osu.Game/Online/Multiplayer/MultiplayerScore.cs rename to osu.Game/Online/Rooms/MultiplayerScore.cs index 8191003aad..677a3d3026 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerScore.cs +++ b/osu.Game/Online/Rooms/MultiplayerScore.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Users; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class MultiplayerScore { diff --git a/osu.Game/Online/Multiplayer/MultiplayerScores.cs b/osu.Game/Online/Rooms/MultiplayerScores.cs similarity index 95% rename from osu.Game/Online/Multiplayer/MultiplayerScores.cs rename to osu.Game/Online/Rooms/MultiplayerScores.cs index 7b9dcff828..3f970b2f8e 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerScores.cs +++ b/osu.Game/Online/Rooms/MultiplayerScores.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using Newtonsoft.Json; using osu.Game.Online.API.Requests; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { /// /// An object which contains scores and related data for fetching next pages. diff --git a/osu.Game/Online/Multiplayer/MultiplayerScoresAround.cs b/osu.Game/Online/Rooms/MultiplayerScoresAround.cs similarity index 95% rename from osu.Game/Online/Multiplayer/MultiplayerScoresAround.cs rename to osu.Game/Online/Rooms/MultiplayerScoresAround.cs index 2ac62d0300..a99439312a 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerScoresAround.cs +++ b/osu.Game/Online/Rooms/MultiplayerScoresAround.cs @@ -4,7 +4,7 @@ using JetBrains.Annotations; using Newtonsoft.Json; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { /// /// An object which stores scores higher and lower than the user's score. diff --git a/osu.Game/Online/Multiplayer/PartRoomRequest.cs b/osu.Game/Online/Rooms/PartRoomRequest.cs similarity index 94% rename from osu.Game/Online/Multiplayer/PartRoomRequest.cs rename to osu.Game/Online/Rooms/PartRoomRequest.cs index 54bb005d96..2f036abc8c 100644 --- a/osu.Game/Online/Multiplayer/PartRoomRequest.cs +++ b/osu.Game/Online/Rooms/PartRoomRequest.cs @@ -5,7 +5,7 @@ using System.Net.Http; using osu.Framework.IO.Network; using osu.Game.Online.API; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class PartRoomRequest : APIRequest { diff --git a/osu.Game/Online/Multiplayer/PlaylistExtensions.cs b/osu.Game/Online/Rooms/PlaylistExtensions.cs similarity index 93% rename from osu.Game/Online/Multiplayer/PlaylistExtensions.cs rename to osu.Game/Online/Rooms/PlaylistExtensions.cs index fe3d96e295..992011da3c 100644 --- a/osu.Game/Online/Multiplayer/PlaylistExtensions.cs +++ b/osu.Game/Online/Rooms/PlaylistExtensions.cs @@ -6,7 +6,7 @@ using Humanizer; using Humanizer.Localisation; using osu.Framework.Bindables; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public static class PlaylistExtensions { diff --git a/osu.Game/Online/Multiplayer/PlaylistItem.cs b/osu.Game/Online/Rooms/PlaylistItem.cs similarity index 98% rename from osu.Game/Online/Multiplayer/PlaylistItem.cs rename to osu.Game/Online/Rooms/PlaylistItem.cs index 4c4c071fc9..ada2140ca6 100644 --- a/osu.Game/Online/Multiplayer/PlaylistItem.cs +++ b/osu.Game/Online/Rooms/PlaylistItem.cs @@ -10,7 +10,7 @@ using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class PlaylistItem : IEquatable { diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Rooms/Room.cs similarity index 97% rename from osu.Game/Online/Multiplayer/Room.cs rename to osu.Game/Online/Rooms/Room.cs index d13d7dc774..67f874cdc4 100644 --- a/osu.Game/Online/Multiplayer/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -7,11 +7,11 @@ using Newtonsoft.Json; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.IO.Serialization.Converters; -using osu.Game.Online.Multiplayer.GameTypes; -using osu.Game.Online.Multiplayer.RoomStatuses; +using osu.Game.Online.Rooms.GameTypes; +using osu.Game.Online.Rooms.RoomStatuses; using osu.Game.Users; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class Room { diff --git a/osu.Game/Online/Multiplayer/RoomAvailability.cs b/osu.Game/Online/Rooms/RoomAvailability.cs similarity index 90% rename from osu.Game/Online/Multiplayer/RoomAvailability.cs rename to osu.Game/Online/Rooms/RoomAvailability.cs index 08fa853562..3aea0e5948 100644 --- a/osu.Game/Online/Multiplayer/RoomAvailability.cs +++ b/osu.Game/Online/Rooms/RoomAvailability.cs @@ -3,7 +3,7 @@ using System.ComponentModel; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public enum RoomAvailability { diff --git a/osu.Game/Online/Multiplayer/RoomCategory.cs b/osu.Game/Online/Rooms/RoomCategory.cs similarity index 80% rename from osu.Game/Online/Multiplayer/RoomCategory.cs rename to osu.Game/Online/Rooms/RoomCategory.cs index d6786a72fe..f485e65ba9 100644 --- a/osu.Game/Online/Multiplayer/RoomCategory.cs +++ b/osu.Game/Online/Rooms/RoomCategory.cs @@ -1,12 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public enum RoomCategory { Normal, Spotlight, - Realtime, + Multiplayer, } } diff --git a/osu.Game/Online/Multiplayer/RoomStatus.cs b/osu.Game/Online/Rooms/RoomStatus.cs similarity index 93% rename from osu.Game/Online/Multiplayer/RoomStatus.cs rename to osu.Game/Online/Rooms/RoomStatus.cs index 3ff2770ab4..87c5aa3fda 100644 --- a/osu.Game/Online/Multiplayer/RoomStatus.cs +++ b/osu.Game/Online/Rooms/RoomStatus.cs @@ -1,10 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osuTK.Graphics; using osu.Game.Graphics; +using osuTK.Graphics; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public abstract class RoomStatus { diff --git a/osu.Game/Online/Multiplayer/RoomStatuses/RoomStatusEnded.cs b/osu.Game/Online/Rooms/RoomStatuses/RoomStatusEnded.cs similarity index 88% rename from osu.Game/Online/Multiplayer/RoomStatuses/RoomStatusEnded.cs rename to osu.Game/Online/Rooms/RoomStatuses/RoomStatusEnded.cs index 4177d28a99..c852f86f6b 100644 --- a/osu.Game/Online/Multiplayer/RoomStatuses/RoomStatusEnded.cs +++ b/osu.Game/Online/Rooms/RoomStatuses/RoomStatusEnded.cs @@ -4,7 +4,7 @@ using osu.Game.Graphics; using osuTK.Graphics; -namespace osu.Game.Online.Multiplayer.RoomStatuses +namespace osu.Game.Online.Rooms.RoomStatuses { public class RoomStatusEnded : RoomStatus { diff --git a/osu.Game/Online/Multiplayer/RoomStatuses/RoomStatusOpen.cs b/osu.Game/Online/Rooms/RoomStatuses/RoomStatusOpen.cs similarity index 89% rename from osu.Game/Online/Multiplayer/RoomStatuses/RoomStatusOpen.cs rename to osu.Game/Online/Rooms/RoomStatuses/RoomStatusOpen.cs index 45a1cb1909..4f7f0d6f5d 100644 --- a/osu.Game/Online/Multiplayer/RoomStatuses/RoomStatusOpen.cs +++ b/osu.Game/Online/Rooms/RoomStatuses/RoomStatusOpen.cs @@ -4,7 +4,7 @@ using osu.Game.Graphics; using osuTK.Graphics; -namespace osu.Game.Online.Multiplayer.RoomStatuses +namespace osu.Game.Online.Rooms.RoomStatuses { public class RoomStatusOpen : RoomStatus { diff --git a/osu.Game/Online/Multiplayer/RoomStatuses/RoomStatusPlaying.cs b/osu.Game/Online/Rooms/RoomStatuses/RoomStatusPlaying.cs similarity index 88% rename from osu.Game/Online/Multiplayer/RoomStatuses/RoomStatusPlaying.cs rename to osu.Game/Online/Rooms/RoomStatuses/RoomStatusPlaying.cs index b2cb5c4510..f04f1b23af 100644 --- a/osu.Game/Online/Multiplayer/RoomStatuses/RoomStatusPlaying.cs +++ b/osu.Game/Online/Rooms/RoomStatuses/RoomStatusPlaying.cs @@ -4,7 +4,7 @@ using osu.Game.Graphics; using osuTK.Graphics; -namespace osu.Game.Online.Multiplayer.RoomStatuses +namespace osu.Game.Online.Rooms.RoomStatuses { public class RoomStatusPlaying : RoomStatus { diff --git a/osu.Game/Online/Multiplayer/ShowPlaylistUserScoreRequest.cs b/osu.Game/Online/Rooms/ShowPlaylistUserScoreRequest.cs similarity index 95% rename from osu.Game/Online/Multiplayer/ShowPlaylistUserScoreRequest.cs rename to osu.Game/Online/Rooms/ShowPlaylistUserScoreRequest.cs index 936b8bbe89..3f728a5417 100644 --- a/osu.Game/Online/Multiplayer/ShowPlaylistUserScoreRequest.cs +++ b/osu.Game/Online/Rooms/ShowPlaylistUserScoreRequest.cs @@ -3,7 +3,7 @@ using osu.Game.Online.API; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class ShowPlaylistUserScoreRequest : APIRequest { diff --git a/osu.Game/Online/Multiplayer/SubmitRoomScoreRequest.cs b/osu.Game/Online/Rooms/SubmitRoomScoreRequest.cs similarity index 97% rename from osu.Game/Online/Multiplayer/SubmitRoomScoreRequest.cs rename to osu.Game/Online/Rooms/SubmitRoomScoreRequest.cs index d31aef2ea5..5a78b9fabd 100644 --- a/osu.Game/Online/Multiplayer/SubmitRoomScoreRequest.cs +++ b/osu.Game/Online/Rooms/SubmitRoomScoreRequest.cs @@ -7,7 +7,7 @@ using osu.Framework.IO.Network; using osu.Game.Online.API; using osu.Game.Scoring; -namespace osu.Game.Online.Multiplayer +namespace osu.Game.Online.Rooms { public class SubmitRoomScoreRequest : APIRequest { diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index bdc9e5eb7b..0b5abc4e31 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -31,7 +31,7 @@ using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.IO; using osu.Game.Online; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Multiplayer; using osu.Game.Online.Spectator; using osu.Game.Overlays; using osu.Game.Resources; @@ -219,7 +219,7 @@ namespace osu.Game dependencies.CacheAs(API ??= new APIAccess(LocalConfig, endpoints)); dependencies.CacheAs(spectatorStreaming = new SpectatorStreamingClient(endpoints)); - dependencies.CacheAs(multiplayerClient = new RealtimeMultiplayerClient(endpoints)); + dependencies.CacheAs(multiplayerClient = new MultiplayerClient(endpoints)); var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures); diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 5650b22f25..15ac2237d3 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -17,7 +17,7 @@ using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; -using osu.Game.Screens.Multi.RealtimeMultiplayer; +using osu.Game.Screens.Multi.Multiplayer; using osu.Game.Screens.Multi.Playlists; using osu.Game.Screens.Select; @@ -105,7 +105,7 @@ namespace osu.Game.Screens.Menu this.Push(new Editor()); }, OnSolo = onSolo, - OnMultiplayer = () => this.Push(new RealtimeMultiplayer()), + OnMultiplayer = () => this.Push(new Multiplayer()), OnPlaylists = () => this.Push(new PlaylistsMultiplayer()), OnExit = confirmAndExit, } diff --git a/osu.Game/Screens/Multi/Components/DrawableGameType.cs b/osu.Game/Screens/Multi/Components/DrawableGameType.cs index 28240f0796..38af6d065e 100644 --- a/osu.Game/Screens/Multi/Components/DrawableGameType.cs +++ b/osu.Game/Screens/Multi/Components/DrawableGameType.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; namespace osu.Game.Screens.Multi.Components { diff --git a/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs b/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs index dff6c50bf2..edce5400d1 100644 --- a/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs +++ b/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Multi.Lounge.Components; namespace osu.Game.Screens.Multi.Components diff --git a/osu.Game/Screens/Multi/Components/MatchBeatmapDetailArea.cs b/osu.Game/Screens/Multi/Components/MatchBeatmapDetailArea.cs index 2c5fd2d397..6997840c92 100644 --- a/osu.Game/Screens/Multi/Components/MatchBeatmapDetailArea.cs +++ b/osu.Game/Screens/Multi/Components/MatchBeatmapDetailArea.cs @@ -8,7 +8,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Select; using osuTK; diff --git a/osu.Game/Screens/Multi/Components/OverlinedPlaylistHeader.cs b/osu.Game/Screens/Multi/Components/OverlinedPlaylistHeader.cs index 5552c1cb72..ebebe8b660 100644 --- a/osu.Game/Screens/Multi/Components/OverlinedPlaylistHeader.cs +++ b/osu.Game/Screens/Multi/Components/OverlinedPlaylistHeader.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; namespace osu.Game.Screens.Multi.Components { diff --git a/osu.Game/Screens/Multi/Components/ReadyButton.cs b/osu.Game/Screens/Multi/Components/ReadyButton.cs index 0bb4ed8617..68df30965d 100644 --- a/osu.Game/Screens/Multi/Components/ReadyButton.cs +++ b/osu.Game/Screens/Multi/Components/ReadyButton.cs @@ -9,7 +9,7 @@ using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; namespace osu.Game.Screens.Multi.Components { diff --git a/osu.Game/Screens/Multi/Components/RoomManager.cs b/osu.Game/Screens/Multi/Components/RoomManager.cs index f78d0d979e..7e0c8c4ec5 100644 --- a/osu.Game/Screens/Multi/Components/RoomManager.cs +++ b/osu.Game/Screens/Multi/Components/RoomManager.cs @@ -12,7 +12,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Online.API; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Rulesets; namespace osu.Game.Screens.Multi.Components diff --git a/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs b/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs index fbaf9dd930..1d10277d1c 100644 --- a/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs +++ b/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Game.Online; using osu.Game.Online.API; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; namespace osu.Game.Screens.Multi.Components { diff --git a/osu.Game/Screens/Multi/Components/RoomStatusInfo.cs b/osu.Game/Screens/Multi/Components/RoomStatusInfo.cs index b5676692a4..89021691f3 100644 --- a/osu.Game/Screens/Multi/Components/RoomStatusInfo.cs +++ b/osu.Game/Screens/Multi/Components/RoomStatusInfo.cs @@ -8,8 +8,8 @@ using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; -using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.RoomStatuses; +using osu.Game.Online.Rooms; +using osu.Game.Online.Rooms.RoomStatuses; namespace osu.Game.Screens.Multi.Components { diff --git a/osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs b/osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs index 37a190b5e0..3050765931 100644 --- a/osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs +++ b/osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; namespace osu.Game.Screens.Multi.Components { diff --git a/osu.Game/Screens/Multi/Components/StatusColouredContainer.cs b/osu.Game/Screens/Multi/Components/StatusColouredContainer.cs index a115f06e7b..68c14eeb15 100644 --- a/osu.Game/Screens/Multi/Components/StatusColouredContainer.cs +++ b/osu.Game/Screens/Multi/Components/StatusColouredContainer.cs @@ -6,7 +6,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; namespace osu.Game.Screens.Multi.Components { diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs b/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs index 89c335183b..956d38a90e 100644 --- a/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs +++ b/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs @@ -7,7 +7,7 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osuTK; namespace osu.Game.Screens.Multi diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs index bda00b65b5..a2aeae154a 100644 --- a/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs @@ -21,7 +21,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online; using osu.Game.Online.Chat; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Overlays.BeatmapListing.Panels; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylistWithResults.cs b/osu.Game/Screens/Multi/DrawableRoomPlaylistWithResults.cs index 439aaaa275..fa241a3c42 100644 --- a/osu.Game/Screens/Multi/DrawableRoomPlaylistWithResults.cs +++ b/osu.Game/Screens/Multi/DrawableRoomPlaylistWithResults.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; namespace osu.Game.Screens.Multi { diff --git a/osu.Game/Screens/Multi/IRoomManager.cs b/osu.Game/Screens/Multi/IRoomManager.cs index 630e3af91c..eee2a223a1 100644 --- a/osu.Game/Screens/Multi/IRoomManager.cs +++ b/osu.Game/Screens/Multi/IRoomManager.cs @@ -4,7 +4,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; namespace osu.Game.Screens.Multi { diff --git a/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs index 56116b219a..6e4d8b46ed 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs @@ -17,12 +17,12 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi.Components; using osuTK; using osuTK.Graphics; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; +using osu.Game.Online.Rooms; namespace osu.Game.Screens.Multi.Lounge.Components { @@ -42,7 +42,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components private CachedModelDependencyContainer dependencies; [Resolved(canBeNull: true)] - private Multiplayer multiplayer { get; set; } + private MultiplayerScreen multiplayer { get; set; } [Resolved] private BeatmapManager beatmaps { get; set; } @@ -228,7 +228,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components private class RoomName : OsuSpriteText { - [Resolved(typeof(Room), nameof(Online.Multiplayer.Room.Name))] + [Resolved(typeof(Room), nameof(Online.Rooms.Room.Name))] private Bindable name { get; set; } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs index c7c37cbc0d..fbd5f44a30 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs @@ -15,9 +15,9 @@ using osu.Framework.Threading; using osu.Game.Extensions; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; -using osu.Game.Online.Multiplayer; using osuTK; using osu.Game.Graphics.Cursor; +using osu.Game.Online.Rooms; namespace osu.Game.Screens.Multi.Lounge.Components { diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs index 6b08745dd7..cbab79e2ab 100644 --- a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs @@ -10,7 +10,7 @@ using osu.Framework.Input.Events; using osu.Framework.Screens; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Screens.Multi.Lounge.Components; using osu.Game.Screens.Multi.Match; diff --git a/osu.Game/Screens/Multi/Match/Components/Footer.cs b/osu.Game/Screens/Multi/Match/Components/Footer.cs index fdf1d0dbeb..7074ceca38 100644 --- a/osu.Game/Screens/Multi/Match/Components/Footer.cs +++ b/osu.Game/Screens/Multi/Match/Components/Footer.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Multi.Playlists; using osuTK; diff --git a/osu.Game/Screens/Multi/Match/Components/GameTypePicker.cs b/osu.Game/Screens/Multi/Match/Components/GameTypePicker.cs index c7fc329a1a..23a3da6e38 100644 --- a/osu.Game/Screens/Multi/Match/Components/GameTypePicker.cs +++ b/osu.Game/Screens/Multi/Match/Components/GameTypePicker.cs @@ -8,8 +8,8 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics; -using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.GameTypes; +using osu.Game.Online.Rooms; +using osu.Game.Online.Rooms.GameTypes; using osu.Game.Screens.Multi.Components; using osuTK; diff --git a/osu.Game/Screens/Multi/Match/Components/MatchChatDisplay.cs b/osu.Game/Screens/Multi/Match/Components/MatchChatDisplay.cs index f8b64a54ef..b790ad9be5 100644 --- a/osu.Game/Screens/Multi/Match/Components/MatchChatDisplay.cs +++ b/osu.Game/Screens/Multi/Match/Components/MatchChatDisplay.cs @@ -4,7 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Online.Chat; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; namespace osu.Game.Screens.Multi.Match.Components { diff --git a/osu.Game/Screens/Multi/Match/Components/MatchLeaderboard.cs b/osu.Game/Screens/Multi/Match/Components/MatchLeaderboard.cs index f2409d64e7..8cc7b62f98 100644 --- a/osu.Game/Screens/Multi/Match/Components/MatchLeaderboard.cs +++ b/osu.Game/Screens/Multi/Match/Components/MatchLeaderboard.cs @@ -8,7 +8,7 @@ using osu.Framework.Bindables; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Leaderboards; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; namespace osu.Game.Screens.Multi.Match.Components { diff --git a/osu.Game/Screens/Multi/Match/Components/RoomAvailabilityPicker.cs b/osu.Game/Screens/Multi/Match/Components/RoomAvailabilityPicker.cs index 7ef39c2a74..2292826d55 100644 --- a/osu.Game/Screens/Multi/Match/Components/RoomAvailabilityPicker.cs +++ b/osu.Game/Screens/Multi/Match/Components/RoomAvailabilityPicker.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Multi.Components; using osuTK; using osuTK.Graphics; diff --git a/osu.Game/Screens/Multi/Match/RoomSubScreen.cs b/osu.Game/Screens/Multi/Match/RoomSubScreen.cs index 0598524e81..b626156852 100644 --- a/osu.Game/Screens/Multi/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/Multi/Match/RoomSubScreen.cs @@ -10,7 +10,7 @@ using osu.Framework.Bindables; using osu.Framework.Screens; using osu.Game.Audio; using osu.Game.Beatmaps; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play; @@ -36,7 +36,7 @@ namespace osu.Game.Screens.Multi.Match private BeatmapManager beatmapManager { get; set; } [Resolved(canBeNull: true)] - protected Multiplayer Multiplayer { get; private set; } + protected MultiplayerScreen Multiplayer { get; private set; } private IBindable> managerUpdated; diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/CreateRealtimeMatchButton.cs b/osu.Game/Screens/Multi/Multiplayer/CreateMultiplayerMatchButton.cs similarity index 77% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/CreateRealtimeMatchButton.cs rename to osu.Game/Screens/Multi/Multiplayer/CreateMultiplayerMatchButton.cs index cdaeb6faec..b8b3f15fca 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/CreateRealtimeMatchButton.cs +++ b/osu.Game/Screens/Multi/Multiplayer/CreateMultiplayerMatchButton.cs @@ -3,12 +3,12 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi.Match.Components; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer +namespace osu.Game.Screens.Multi.Multiplayer { - public class CreateRealtimeMatchButton : PurpleTriangleButton + public class CreateMultiplayerMatchButton : PurpleTriangleButton { [BackgroundDependencyLoader] private void load(StatefulMultiplayerClient multiplayerClient) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/Multi/Multiplayer/Match/BeatmapSelectionControl.cs similarity index 91% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/Match/BeatmapSelectionControl.cs rename to osu.Game/Screens/Multi/Multiplayer/Match/BeatmapSelectionControl.cs index 1939744916..dfb6feeaf9 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/BeatmapSelectionControl.cs +++ b/osu.Game/Screens/Multi/Multiplayer/Match/BeatmapSelectionControl.cs @@ -11,12 +11,12 @@ using osu.Framework.Screens; using osu.Game.Online.API; using osu.Game.Screens.Multi.Match.Components; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match +namespace osu.Game.Screens.Multi.Multiplayer.Match { public class BeatmapSelectionControl : MultiplayerComposite { [Resolved] - private RealtimeMatchSubScreen matchSubScreen { get; set; } + private MultiplayerMatchSubScreen matchSubScreen { get; set; } [Resolved] private IAPIProvider api { get; set; } @@ -49,7 +49,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match RelativeSizeAxes = Axes.X, Height = 40, Text = "Select beatmap", - Action = () => matchSubScreen.Push(new RealtimeMatchSongSelect()), + Action = () => matchSubScreen.Push(new MultiplayerMatchSongSelect()), Alpha = 0 } } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchFooter.cs b/osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchFooter.cs similarity index 84% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchFooter.cs rename to osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchFooter.cs index 31871729f6..145ae18817 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchFooter.cs +++ b/osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchFooter.cs @@ -8,12 +8,12 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osuTK; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match +namespace osu.Game.Screens.Multi.Multiplayer.Match { - public class RealtimeMatchFooter : CompositeDrawable + public class MultiplayerMatchFooter : CompositeDrawable { public const float HEIGHT = 50; @@ -21,7 +21,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match private readonly Drawable background; - public RealtimeMatchFooter() + public MultiplayerMatchFooter() { RelativeSizeAxes = Axes.X; Height = HEIGHT; @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match InternalChildren = new[] { background = new Box { RelativeSizeAxes = Axes.Both }, - new RealtimeReadyButton + new MultiplayerReadyButton { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchHeader.cs b/osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchHeader.cs similarity index 95% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchHeader.cs rename to osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchHeader.cs index a9a10d1510..0c0e580a3e 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchHeader.cs +++ b/osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchHeader.cs @@ -17,9 +17,9 @@ using FontWeight = osu.Game.Graphics.FontWeight; using OsuColour = osu.Game.Graphics.OsuColour; using OsuFont = osu.Game.Graphics.OsuFont; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match +namespace osu.Game.Screens.Multi.Multiplayer.Match { - public class RealtimeMatchHeader : MultiplayerComposite + public class MultiplayerMatchHeader : MultiplayerComposite { public const float HEIGHT = 50; @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match [Resolved] private IAPIProvider api { get; set; } - public RealtimeMatchHeader() + public MultiplayerMatchHeader() { RelativeSizeAxes = Axes.X; Height = HEIGHT; diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs b/osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs similarity index 99% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs rename to osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index a93b1b09d1..4a5b5fd181 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeMatchSettingsOverlay.cs +++ b/osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -15,15 +15,15 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Screens.Multi.Match.Components; using osuTK; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match +namespace osu.Game.Screens.Multi.Multiplayer.Match { - public class RealtimeMatchSettingsOverlay : MatchSettingsOverlay + public class MultiplayerMatchSettingsOverlay : MatchSettingsOverlay { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs b/osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerReadyButton.cs similarity index 95% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs rename to osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerReadyButton.cs index be405feef1..cea1eeecbb 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Match/RealtimeReadyButton.cs +++ b/osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerReadyButton.cs @@ -14,13 +14,13 @@ using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; using osu.Game.Online.API; using osu.Game.Online.Multiplayer; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Multi.Components; using osuTK; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match +namespace osu.Game.Screens.Multi.Multiplayer.Match { - public class RealtimeReadyButton : RealtimeRoomComposite + public class MultiplayerReadyButton : MultiplayerRoomComposite { public Bindable SelectedItem => button.SelectedItem; @@ -39,7 +39,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Match private int countReady; - public RealtimeReadyButton() + public MultiplayerReadyButton() { InternalChild = button = new ButtonWithTrianglesExposed { diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs b/osu.Game/Screens/Multi/Multiplayer/Multiplayer.cs similarity index 86% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs rename to osu.Game/Screens/Multi/Multiplayer/Multiplayer.cs index 87c838f29f..97fa4cfa6e 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMultiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer/Multiplayer.cs @@ -7,13 +7,13 @@ using osu.Framework.Screens; using osu.Game.Extensions; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Multi.Lounge; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer +namespace osu.Game.Screens.Multi.Multiplayer { - public class RealtimeMultiplayer : Multiplayer + public class Multiplayer : MultiplayerScreen { [Resolved] private StatefulMultiplayerClient client { get; set; } @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer protected override void UpdatePollingRate(bool isIdle) { - var playlistsManager = (RealtimeRoomManager)RoomManager; + var playlistsManager = (MultiplayerRoomManager)RoomManager; if (!this.IsCurrentScreen()) { @@ -58,16 +58,16 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer protected override Room CreateNewRoom() { var room = new Room { Name = { Value = $"{API.LocalUser}'s awesome room" } }; - room.Category.Value = RoomCategory.Realtime; + room.Category.Value = RoomCategory.Multiplayer; return room; } protected override string ScreenTitle => "Multiplayer"; - protected override RoomManager CreateRoomManager() => new RealtimeRoomManager(); + protected override RoomManager CreateRoomManager() => new MultiplayerRoomManager(); - protected override LoungeSubScreen CreateLounge() => new RealtimeLoungeSubScreen(); + protected override LoungeSubScreen CreateLounge() => new MultiplayerLoungeSubScreen(); - protected override OsuButton CreateNewMultiplayerGameButton() => new CreateRealtimeMatchButton(); + protected override OsuButton CreateNewMultiplayerGameButton() => new CreateMultiplayerMatchButton(); } } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeFilterControl.cs b/osu.Game/Screens/Multi/Multiplayer/MultiplayerFilterControl.cs similarity index 79% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeFilterControl.cs rename to osu.Game/Screens/Multi/Multiplayer/MultiplayerFilterControl.cs index acd9a057e3..bebad1944e 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeFilterControl.cs +++ b/osu.Game/Screens/Multi/Multiplayer/MultiplayerFilterControl.cs @@ -3,9 +3,9 @@ using osu.Game.Screens.Multi.Lounge.Components; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer +namespace osu.Game.Screens.Multi.Multiplayer { - public class RealtimeFilterControl : FilterControl + public class MultiplayerFilterControl : FilterControl { protected override FilterCriteria CreateCriteria() { diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs b/osu.Game/Screens/Multi/Multiplayer/MultiplayerLoungeSubScreen.cs similarity index 79% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs rename to osu.Game/Screens/Multi/Multiplayer/MultiplayerLoungeSubScreen.cs index b53ec94519..ffc81efe3c 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeLoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -4,18 +4,18 @@ using osu.Framework.Allocation; using osu.Framework.Logging; using osu.Game.Online.Multiplayer; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Lounge.Components; using osu.Game.Screens.Multi.Match; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer +namespace osu.Game.Screens.Multi.Multiplayer { - public class RealtimeLoungeSubScreen : LoungeSubScreen + public class MultiplayerLoungeSubScreen : LoungeSubScreen { - protected override FilterControl CreateFilterControl() => new RealtimeFilterControl(); + protected override FilterControl CreateFilterControl() => new MultiplayerFilterControl(); - protected override RoomSubScreen CreateRoomSubScreen(Room room) => new RealtimeMatchSubScreen(room); + protected override RoomSubScreen CreateRoomSubScreen(Room room) => new MultiplayerMatchSubScreen(room); [Resolved] private StatefulMultiplayerClient client { get; set; } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs b/osu.Game/Screens/Multi/Multiplayer/MultiplayerMatchSongSelect.cs similarity index 92% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs rename to osu.Game/Screens/Multi/Multiplayer/MultiplayerMatchSongSelect.cs index 8f317800e3..ed1321d4e2 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSongSelect.cs +++ b/osu.Game/Screens/Multi/Multiplayer/MultiplayerMatchSongSelect.cs @@ -10,12 +10,12 @@ using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Select; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer +namespace osu.Game.Screens.Multi.Multiplayer { - public class RealtimeMatchSongSelect : SongSelect, IMultiplayerSubScreen + public class MultiplayerMatchSongSelect : SongSelect, IMultiplayerSubScreen { public string ShortTitle => "song selection"; @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer private LoadingLayer loadingLayer; - public RealtimeMatchSongSelect() + public MultiplayerMatchSongSelect() { Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs b/osu.Game/Screens/Multi/Multiplayer/MultiplayerMatchSubScreen.cs similarity index 92% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs rename to osu.Game/Screens/Multi/Multiplayer/MultiplayerMatchSubScreen.cs index 1778bc272c..4e371d4ed4 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeMatchSubScreen.cs +++ b/osu.Game/Screens/Multi/Multiplayer/MultiplayerMatchSubScreen.cs @@ -10,19 +10,19 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Game.Online.Multiplayer; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Multi.Match; using osu.Game.Screens.Multi.Match.Components; -using osu.Game.Screens.Multi.RealtimeMultiplayer.Match; -using osu.Game.Screens.Multi.RealtimeMultiplayer.Participants; +using osu.Game.Screens.Multi.Multiplayer.Match; +using osu.Game.Screens.Multi.Multiplayer.Participants; using osu.Game.Users; -using ParticipantsList = osu.Game.Screens.Multi.RealtimeMultiplayer.Participants.ParticipantsList; +using ParticipantsList = osu.Game.Screens.Multi.Multiplayer.Participants.ParticipantsList; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer +namespace osu.Game.Screens.Multi.Multiplayer { [Cached] - public class RealtimeMatchSubScreen : RoomSubScreen + public class MultiplayerMatchSubScreen : RoomSubScreen { public override string Title { get; } @@ -31,11 +31,11 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer [Resolved] private StatefulMultiplayerClient client { get; set; } - private RealtimeMatchSettingsOverlay settingsOverlay; + private MultiplayerMatchSettingsOverlay settingsOverlay; private IBindable isConnected; - public RealtimeMatchSubScreen(Room room) + public MultiplayerMatchSubScreen(Room room) { Title = room.RoomID.Value == null ? "New room" : room.Name.Value; Activity.Value = new UserActivity.InLobby(room); @@ -73,7 +73,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer { new Drawable[] { - new RealtimeMatchHeader + new MultiplayerMatchHeader { OpenSettings = () => settingsOverlay.Show() } @@ -150,7 +150,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer }, new Drawable[] { - new RealtimeMatchFooter { SelectedItem = { BindTarget = SelectedItem } } + new MultiplayerMatchFooter { SelectedItem = { BindTarget = SelectedItem } } } }, RowDimensions = new[] @@ -159,7 +159,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer new Dimension(GridSizeMode.AutoSize), } }, - settingsOverlay = new RealtimeMatchSettingsOverlay + settingsOverlay = new MultiplayerMatchSettingsOverlay { RelativeSizeAxes = Axes.Both, State = { Value = client.Room == null ? Visibility.Visible : Visibility.Hidden } @@ -202,7 +202,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer int[] userIds = client.Room.Users.Where(u => u.State >= MultiplayerUserState.WaitingForLoad).Select(u => u.UserID).ToArray(); - StartPlay(() => new RealtimePlayer(SelectedItem.Value, userIds)); + StartPlay(() => new MultiplayerPlayer(SelectedItem.Value, userIds)); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs b/osu.Game/Screens/Multi/Multiplayer/MultiplayerPlayer.cs similarity index 93% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs rename to osu.Game/Screens/Multi/Multiplayer/MultiplayerPlayer.cs index 033e4756eb..3255bcc642 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimePlayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer/MultiplayerPlayer.cs @@ -9,7 +9,7 @@ using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Rooms; using osu.Game.Scoring; using osu.Game.Screens.Multi.Play; using osu.Game.Screens.Play; @@ -17,10 +17,10 @@ using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Ranking; using osuTK; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer +namespace osu.Game.Screens.Multi.Multiplayer { // Todo: The "room" part of PlaylistsPlayer should be split out into an abstract player class to be inherited instead. - public class RealtimePlayer : PlaylistsPlayer + public class MultiplayerPlayer : PlaylistsPlayer { protected override bool PauseOnFocusLost => false; @@ -45,7 +45,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer /// /// The playlist item to be played. /// The users which are participating in this game. - public RealtimePlayer(PlaylistItem playlistItem, int[] userIds) + public MultiplayerPlayer(PlaylistItem playlistItem, int[] userIds) : base(playlistItem, new PlayerConfiguration { AllowPause = false, @@ -81,7 +81,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer { if (!connected.NewValue) { - // messaging to the user about this disconnect will be provided by the RealtimeMatchSubScreen. + // messaging to the user about this disconnect will be provided by the MultiplayerMatchSubScreen. failAndBail(); } }, true); @@ -142,7 +142,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer protected override ResultsScreen CreateResults(ScoreInfo score) { Debug.Assert(RoomId.Value != null); - return new RealtimeResultsScreen(score, RoomId.Value.Value, PlaylistItem); + return new MultiplayerResultsScreen(score, RoomId.Value.Value, PlaylistItem); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs b/osu.Game/Screens/Multi/Multiplayer/MultiplayerResultsScreen.cs similarity index 55% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs rename to osu.Game/Screens/Multi/Multiplayer/MultiplayerResultsScreen.cs index 6bec06cbba..a01930c5ef 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeResultsScreen.cs +++ b/osu.Game/Screens/Multi/Multiplayer/MultiplayerResultsScreen.cs @@ -1,15 +1,15 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Scoring; using osu.Game.Screens.Multi.Ranking; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer +namespace osu.Game.Screens.Multi.Multiplayer { - public class RealtimeResultsScreen : PlaylistsResultsScreen + public class MultiplayerResultsScreen : PlaylistsResultsScreen { - public RealtimeResultsScreen(ScoreInfo score, int roomId, PlaylistItem playlistItem) + public MultiplayerResultsScreen(ScoreInfo score, int roomId, PlaylistItem playlistItem) : base(score, roomId, playlistItem, false, false) { } diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomComposite.cs b/osu.Game/Screens/Multi/Multiplayer/MultiplayerRoomComposite.cs similarity index 83% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomComposite.cs rename to osu.Game/Screens/Multi/Multiplayer/MultiplayerRoomComposite.cs index e6d1274316..6fe7c10bfb 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomComposite.cs +++ b/osu.Game/Screens/Multi/Multiplayer/MultiplayerRoomComposite.cs @@ -3,11 +3,11 @@ using JetBrains.Annotations; using osu.Framework.Allocation; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Multiplayer; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer +namespace osu.Game.Screens.Multi.Multiplayer { - public abstract class RealtimeRoomComposite : MultiplayerComposite + public abstract class MultiplayerRoomComposite : MultiplayerComposite { [CanBeNull] protected MultiplayerRoom Room => Client.Room; diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs b/osu.Game/Screens/Multi/Multiplayer/MultiplayerRoomManager.cs similarity index 92% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs rename to osu.Game/Screens/Multi/Multiplayer/MultiplayerRoomManager.cs index eb6e5fad07..fdd46cdc2a 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/RealtimeRoomManager.cs +++ b/osu.Game/Screens/Multi/Multiplayer/MultiplayerRoomManager.cs @@ -11,13 +11,13 @@ using osu.Framework.Extensions.ExceptionExtensions; using osu.Framework.Logging; using osu.Game.Extensions; using osu.Game.Online.Multiplayer; -using osu.Game.Online.Multiplayer.RoomStatuses; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Rooms; +using osu.Game.Online.Rooms.RoomStatuses; using osu.Game.Screens.Multi.Components; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer +namespace osu.Game.Screens.Multi.Multiplayer { - public class RealtimeRoomManager : RoomManager + public class MultiplayerRoomManager : RoomManager { [Resolved] private StatefulMultiplayerClient multiplayerClient { get; set; } @@ -114,19 +114,19 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer protected override IEnumerable CreatePollingComponents() => new RoomPollingComponent[] { - listingPollingComponent = new RealtimeListingPollingComponent + listingPollingComponent = new MultiplayerListingPollingComponent { TimeBetweenPolls = { BindTarget = TimeBetweenListingPolls }, AllowPolling = { BindTarget = allowPolling } }, - new RealtimeSelectionPollingComponent + new MultiplayerSelectionPollingComponent { TimeBetweenPolls = { BindTarget = TimeBetweenSelectionPolls }, AllowPolling = { BindTarget = allowPolling } } }; - private class RealtimeListingPollingComponent : ListingPollingComponent + private class MultiplayerListingPollingComponent : ListingPollingComponent { public readonly IBindable AllowPolling = new Bindable(); @@ -147,7 +147,7 @@ namespace osu.Game.Screens.Multi.RealtimeMultiplayer protected override Task Poll() => !AllowPolling.Value ? Task.CompletedTask : base.Poll(); } - private class RealtimeSelectionPollingComponent : SelectionPollingComponent + private class MultiplayerSelectionPollingComponent : SelectionPollingComponent { public readonly IBindable AllowPolling = new Bindable(); diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantPanel.cs similarity index 97% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs rename to osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantPanel.cs index 85393d1bae..93f8a9de8b 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantPanel.cs @@ -16,15 +16,15 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Multiplayer; using osu.Game.Users; using osu.Game.Users.Drawables; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants +namespace osu.Game.Screens.Multi.Multiplayer.Participants { - public class ParticipantPanel : RealtimeRoomComposite, IHasContextMenu + public class ParticipantPanel : MultiplayerRoomComposite, IHasContextMenu { public readonly MultiplayerRoomUser User; diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsList.cs b/osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantsList.cs similarity index 93% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsList.cs rename to osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantsList.cs index 218c2cabb7..3f37274d4c 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsList.cs +++ b/osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantsList.cs @@ -9,9 +9,9 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osuTK; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants +namespace osu.Game.Screens.Multi.Multiplayer.Participants { - public class ParticipantsList : RealtimeRoomComposite + public class ParticipantsList : MultiplayerRoomComposite { private FillFlowContainer panels; diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsListHeader.cs b/osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantsListHeader.cs similarity index 86% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsListHeader.cs rename to osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantsListHeader.cs index 0ca7d34005..dc3ceedfd7 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/ParticipantsListHeader.cs +++ b/osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantsListHeader.cs @@ -2,10 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi.Components; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants +namespace osu.Game.Screens.Multi.Multiplayer.Participants { public class ParticipantsListHeader : OverlinedHeader { diff --git a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/StateDisplay.cs b/osu.Game/Screens/Multi/Multiplayer/Participants/StateDisplay.cs similarity index 97% rename from osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/StateDisplay.cs rename to osu.Game/Screens/Multi/Multiplayer/Participants/StateDisplay.cs index 844f239363..61faa0d85d 100644 --- a/osu.Game/Screens/Multi/RealtimeMultiplayer/Participants/StateDisplay.cs +++ b/osu.Game/Screens/Multi/Multiplayer/Participants/StateDisplay.cs @@ -8,10 +8,10 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Multiplayer; using osuTK; -namespace osu.Game.Screens.Multi.RealtimeMultiplayer.Participants +namespace osu.Game.Screens.Multi.Multiplayer.Participants { public class StateDisplay : CompositeDrawable { diff --git a/osu.Game/Screens/Multi/MultiplayerComposite.cs b/osu.Game/Screens/Multi/MultiplayerComposite.cs index 6e0c69d712..fe4ca759b0 100644 --- a/osu.Game/Screens/Multi/MultiplayerComposite.cs +++ b/osu.Game/Screens/Multi/MultiplayerComposite.cs @@ -5,7 +5,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Users; namespace osu.Game.Screens.Multi diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/MultiplayerScreen.cs similarity index 99% rename from osu.Game/Screens/Multi/Multiplayer.cs rename to osu.Game/Screens/Multi/MultiplayerScreen.cs index 34b7139f2d..983c7aeac9 100644 --- a/osu.Game/Screens/Multi/Multiplayer.cs +++ b/osu.Game/Screens/Multi/MultiplayerScreen.cs @@ -14,7 +14,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Input; using osu.Game.Online.API; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Screens.Menu; using osu.Game.Screens.Multi.Components; @@ -27,7 +27,7 @@ using osuTK; namespace osu.Game.Screens.Multi { [Cached] - public abstract class Multiplayer : OsuScreen + public abstract class MultiplayerScreen : OsuScreen { public override bool CursorVisible => (screenStack.CurrentScreen as IMultiplayerSubScreen)?.CursorVisible ?? true; @@ -67,7 +67,7 @@ namespace osu.Game.Screens.Multi private readonly Drawable header; private readonly Drawable headerBackground; - protected Multiplayer() + protected MultiplayerScreen() { Anchor = Anchor.Centre; Origin = Anchor.Centre; diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs index 65b0091505..f05f732494 100644 --- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs +++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs @@ -11,7 +11,7 @@ using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Online.API; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Scoring; using osu.Game.Screens.Multi.Ranking; diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsLoungeSubScreen.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsLoungeSubScreen.cs index b40c543b68..513854515b 100644 --- a/osu.Game/Screens/Multi/Playlists/PlaylistsLoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsLoungeSubScreen.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Lounge.Components; using osu.Game.Screens.Multi.Match; diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsMatchSettingsOverlay.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsMatchSettingsOverlay.cs index af29e8d34d..f3109a33e4 100644 --- a/osu.Game/Screens/Multi/Playlists/PlaylistsMatchSettingsOverlay.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsMatchSettingsOverlay.cs @@ -14,7 +14,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Screens.Multi.Match.Components; using osuTK; diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsMultiplayer.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsMultiplayer.cs index fce24da966..92b0160247 100644 --- a/osu.Game/Screens/Multi/Playlists/PlaylistsMultiplayer.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsMultiplayer.cs @@ -4,14 +4,14 @@ using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Multi.Lounge; using osu.Game.Screens.Multi.Match; namespace osu.Game.Screens.Multi.Playlists { - public class PlaylistsMultiplayer : Multiplayer + public class PlaylistsMultiplayer : MultiplayerScreen { protected override void UpdatePollingRate(bool isIdle) { diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsReadyButton.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsReadyButton.cs index f5adf899e3..3c35e2a6f3 100644 --- a/osu.Game/Screens/Multi/Playlists/PlaylistsReadyButton.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsReadyButton.cs @@ -5,7 +5,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Graphics; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Multi.Components; namespace osu.Game.Screens.Multi.Playlists diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs index b2bcba1724..67242003e6 100644 --- a/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Game.Online.API; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Multi.Match; using osu.Game.Screens.Multi.Match.Components; @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Multi.Playlists private Bindable roomId { get; set; } [Resolved(canBeNull: true)] - private Multiplayer multiplayer { get; set; } + private MultiplayerScreen multiplayer { get; set; } private MatchSettingsOverlay settingsOverlay; private MatchLeaderboard leaderboard; diff --git a/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs b/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs index c757433e2f..7b1ab2c5b7 100644 --- a/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs +++ b/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Scoring; using osu.Game.Screens.Ranking; diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index 8692833a21..80fd5c2067 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -9,7 +9,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Beatmaps; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.Multi; using osu.Game.Screens.Multi.Components; diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs similarity index 67% rename from osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs rename to osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs index 30bd3ebc32..0e23f4d8c6 100644 --- a/osu.Game/Tests/Visual/RealtimeMultiplayer/RealtimeMultiplayerTestScene.cs +++ b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs @@ -6,32 +6,32 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi; using osu.Game.Screens.Multi.Lounge.Components; -namespace osu.Game.Tests.Visual.RealtimeMultiplayer +namespace osu.Game.Tests.Visual.Multiplayer { - public abstract class RealtimeMultiplayerTestScene : MultiplayerTestScene + public abstract class MultiplayerTestScene : RoomTestScene { [Cached(typeof(StatefulMultiplayerClient))] - public TestRealtimeMultiplayerClient Client { get; } + public TestMultiplayerClient Client { get; } [Cached(typeof(IRoomManager))] - public TestRealtimeRoomManager RoomManager { get; } + public TestMultiplayerRoomManager RoomManager { get; } [Cached] public Bindable Filter { get; } protected override Container Content => content; - private readonly TestRealtimeRoomContainer content; + private readonly TestMultiplayerRoomContainer content; private readonly bool joinRoom; - protected RealtimeMultiplayerTestScene(bool joinRoom = true) + protected MultiplayerTestScene(bool joinRoom = true) { this.joinRoom = joinRoom; - base.Content.Add(content = new TestRealtimeRoomContainer { RelativeSizeAxes = Axes.Both }); + base.Content.Add(content = new TestMultiplayerRoomContainer { RelativeSizeAxes = Axes.Both }); Client = content.Client; RoomManager = content.RoomManager; diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs similarity index 95% rename from osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs rename to osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 52047016e2..9a839c8d22 100644 --- a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -9,12 +9,12 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Online.API; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Multiplayer; using osu.Game.Users; -namespace osu.Game.Tests.Visual.RealtimeMultiplayer +namespace osu.Game.Tests.Visual.Multiplayer { - public class TestRealtimeMultiplayerClient : StatefulMultiplayerClient + public class TestMultiplayerClient : StatefulMultiplayerClient { public override IBindable IsConnected => isConnected; private readonly Bindable isConnected = new Bindable(true); diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomContainer.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomContainer.cs similarity index 67% rename from osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomContainer.cs rename to osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomContainer.cs index 3565d6ac5d..0df397d98e 100644 --- a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomContainer.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomContainer.cs @@ -5,34 +5,34 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Online.RealtimeMultiplayer; +using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi; using osu.Game.Screens.Multi.Lounge.Components; -namespace osu.Game.Tests.Visual.RealtimeMultiplayer +namespace osu.Game.Tests.Visual.Multiplayer { - public class TestRealtimeRoomContainer : Container + public class TestMultiplayerRoomContainer : Container { protected override Container Content => content; private readonly Container content; [Cached(typeof(StatefulMultiplayerClient))] - public readonly TestRealtimeMultiplayerClient Client; + public readonly TestMultiplayerClient Client; [Cached(typeof(IRoomManager))] - public readonly TestRealtimeRoomManager RoomManager; + public readonly TestMultiplayerRoomManager RoomManager; [Cached] public readonly Bindable Filter = new Bindable(new FilterCriteria()); - public TestRealtimeRoomContainer() + public TestMultiplayerRoomContainer() { RelativeSizeAxes = Axes.Both; AddRangeInternal(new Drawable[] { - Client = new TestRealtimeMultiplayerClient(), - RoomManager = new TestRealtimeRoomManager(), + Client = new TestMultiplayerClient(), + RoomManager = new TestMultiplayerRoomManager(), content = new Container { RelativeSizeAxes = Axes.Both } }); } diff --git a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs similarity index 95% rename from osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs rename to osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs index 0d1314fb51..abfefd363a 100644 --- a/osu.Game/Tests/Visual/RealtimeMultiplayer/TestRealtimeRoomManager.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs @@ -8,15 +8,15 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Online.API; using osu.Game.Online.API.Requests; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Multi.Lounge.Components; -using osu.Game.Screens.Multi.RealtimeMultiplayer; +using osu.Game.Screens.Multi.Multiplayer; -namespace osu.Game.Tests.Visual.RealtimeMultiplayer +namespace osu.Game.Tests.Visual.Multiplayer { - public class TestRealtimeRoomManager : RealtimeRoomManager + public class TestMultiplayerRoomManager : MultiplayerRoomManager { [Resolved] private IAPIProvider api { get; set; } diff --git a/osu.Game/Tests/Visual/MultiplayerTestScene.cs b/osu.Game/Tests/Visual/RoomTestScene.cs similarity index 90% rename from osu.Game/Tests/Visual/MultiplayerTestScene.cs rename to osu.Game/Tests/Visual/RoomTestScene.cs index 6f24e00a92..aaf5c7624f 100644 --- a/osu.Game/Tests/Visual/MultiplayerTestScene.cs +++ b/osu.Game/Tests/Visual/RoomTestScene.cs @@ -4,11 +4,11 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; namespace osu.Game.Tests.Visual { - public abstract class MultiplayerTestScene : ScreenTestScene + public abstract class RoomTestScene : ScreenTestScene { [Cached] private readonly Bindable currentRoom = new Bindable(); diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 0b4fa94942..f633773d11 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -3,7 +3,7 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; -using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osuTK.Graphics; From e49dce2c866f804b2e1a93fa49b025c112fc8f06 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Dec 2020 15:34:13 +0900 Subject: [PATCH 301/328] Fix some missed renames --- .../GameTypes/{GameTypeTimeshift.cs => GameTypePlaylists.cs} | 0 .../{TimeshiftFilterControl.cs => PlaylistsFilterControl.cs} | 0 .../Screens/Multi/Play/{TimeshiftPlayer.cs => PlaylistsPlayer.cs} | 0 .../{TimeshiftResultsScreen.cs => PlaylistsResultsScreen.cs} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename osu.Game/Online/Rooms/GameTypes/{GameTypeTimeshift.cs => GameTypePlaylists.cs} (100%) rename osu.Game/Screens/Multi/Lounge/Components/{TimeshiftFilterControl.cs => PlaylistsFilterControl.cs} (100%) rename osu.Game/Screens/Multi/Play/{TimeshiftPlayer.cs => PlaylistsPlayer.cs} (100%) rename osu.Game/Screens/Multi/Ranking/{TimeshiftResultsScreen.cs => PlaylistsResultsScreen.cs} (100%) diff --git a/osu.Game/Online/Rooms/GameTypes/GameTypeTimeshift.cs b/osu.Game/Online/Rooms/GameTypes/GameTypePlaylists.cs similarity index 100% rename from osu.Game/Online/Rooms/GameTypes/GameTypeTimeshift.cs rename to osu.Game/Online/Rooms/GameTypes/GameTypePlaylists.cs diff --git a/osu.Game/Screens/Multi/Lounge/Components/TimeshiftFilterControl.cs b/osu.Game/Screens/Multi/Lounge/Components/PlaylistsFilterControl.cs similarity index 100% rename from osu.Game/Screens/Multi/Lounge/Components/TimeshiftFilterControl.cs rename to osu.Game/Screens/Multi/Lounge/Components/PlaylistsFilterControl.cs diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/PlaylistsPlayer.cs similarity index 100% rename from osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs rename to osu.Game/Screens/Multi/Play/PlaylistsPlayer.cs diff --git a/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs b/osu.Game/Screens/Multi/Ranking/PlaylistsResultsScreen.cs similarity index 100% rename from osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs rename to osu.Game/Screens/Multi/Ranking/PlaylistsResultsScreen.cs From 13c38c9b5556d988ab343beb70fbe2659a5237db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 25 Dec 2020 14:18:21 +0100 Subject: [PATCH 302/328] Fix tests failing due to wrong inheritance --- osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs | 2 +- .../Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs index a72f71d79c..71b8ad05ee 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMatchLeaderboard : MultiplayerTestScene + public class TestSceneMatchLeaderboard : RoomTestScene { protected override bool UseOnlineAPI => true; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs index 292c4846ab..7a3845cbf3 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs @@ -9,7 +9,7 @@ using osu.Game.Online.Rooms; namespace osu.Game.Tests.Visual.Multiplayer { [HeadlessTest] - public class TestSceneMultiplayerRoomManager : MultiplayerTestScene + public class TestSceneMultiplayerRoomManager : RoomTestScene { private TestMultiplayerRoomContainer roomContainer; private TestMultiplayerRoomManager roomManager => roomContainer.RoomManager; From da8365f9d0047301b63a10103f0e7630fc8b3a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 25 Dec 2020 14:34:47 +0100 Subject: [PATCH 303/328] Fix other missed cases of changing inheritance --- osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs | 2 +- .../Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs | 2 +- osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs | 2 +- osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs index 1359274512..f58e1114b8 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs @@ -10,7 +10,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneLoungeRoomInfo : MultiplayerTestScene + public class TestSceneLoungeRoomInfo : RoomTestScene { [SetUp] public new void Setup() => Schedule(() => diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs index f4e0cc415c..571330f50e 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMatchBeatmapDetailArea : MultiplayerTestScene + public class TestSceneMatchBeatmapDetailArea : RoomTestScene { [Resolved] private BeatmapManager beatmapManager { get; set; } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs index e162009771..61968dce46 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs @@ -11,7 +11,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMatchHeader : MultiplayerTestScene + public class TestSceneMatchHeader : RoomTestScene { public TestSceneMatchHeader() { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs index 4742fd0d84..157597e800 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs @@ -23,7 +23,7 @@ using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMatchSongSelect : MultiplayerTestScene + public class TestSceneMatchSongSelect : RoomTestScene { [Resolved] private BeatmapManager beatmapManager { get; set; } From 2d7f9bf29045e9096ad8cb9dc672a05ad6ab7c97 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Dec 2020 23:34:29 +0900 Subject: [PATCH 304/328] Revert RoomCategory naming change to avoid json deserialization failures --- osu.Game/Online/Rooms/RoomCategory.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Rooms/RoomCategory.cs b/osu.Game/Online/Rooms/RoomCategory.cs index f485e65ba9..bb9f1298d3 100644 --- a/osu.Game/Online/Rooms/RoomCategory.cs +++ b/osu.Game/Online/Rooms/RoomCategory.cs @@ -5,8 +5,9 @@ namespace osu.Game.Online.Rooms { public enum RoomCategory { + // used for osu-web deserialization so names shouldn't be changed. Normal, Spotlight, - Multiplayer, + Realtime, } } From e421b6d34e50642cae45794fdb28e64805c6efd5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Dec 2020 23:36:09 +0900 Subject: [PATCH 305/328] Update some missed variables --- .../Visual/Multiplayer/TestSceneRoomStatus.cs | 2 +- .../Screens/Multi/Multiplayer/Multiplayer.cs | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs index 788255501b..7140050bd5 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { Name = { Value = "Open" }, Status = { Value = new RoomStatusOpen() }, - Category = { Value = RoomCategory.Multiplayer } + Category = { Value = RoomCategory.Realtime } }) { MatchingFilter = true }, } }; diff --git a/osu.Game/Screens/Multi/Multiplayer/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer/Multiplayer.cs index 97fa4cfa6e..76aa6b9f8f 100644 --- a/osu.Game/Screens/Multi/Multiplayer/Multiplayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer/Multiplayer.cs @@ -28,37 +28,37 @@ namespace osu.Game.Screens.Multi.Multiplayer protected override void UpdatePollingRate(bool isIdle) { - var playlistsManager = (MultiplayerRoomManager)RoomManager; + var multiplayerRoomManager = (MultiplayerRoomManager)RoomManager; if (!this.IsCurrentScreen()) { - playlistsManager.TimeBetweenListingPolls.Value = 0; - playlistsManager.TimeBetweenSelectionPolls.Value = 0; + multiplayerRoomManager.TimeBetweenListingPolls.Value = 0; + multiplayerRoomManager.TimeBetweenSelectionPolls.Value = 0; } else { switch (CurrentSubScreen) { case LoungeSubScreen _: - playlistsManager.TimeBetweenListingPolls.Value = isIdle ? 120000 : 15000; - playlistsManager.TimeBetweenSelectionPolls.Value = isIdle ? 120000 : 15000; + multiplayerRoomManager.TimeBetweenListingPolls.Value = isIdle ? 120000 : 15000; + multiplayerRoomManager.TimeBetweenSelectionPolls.Value = isIdle ? 120000 : 15000; break; // Don't poll inside the match or anywhere else. default: - playlistsManager.TimeBetweenListingPolls.Value = 0; - playlistsManager.TimeBetweenSelectionPolls.Value = 0; + multiplayerRoomManager.TimeBetweenListingPolls.Value = 0; + multiplayerRoomManager.TimeBetweenSelectionPolls.Value = 0; break; } } - Logger.Log($"Polling adjusted (listing: {playlistsManager.TimeBetweenListingPolls.Value}, selection: {playlistsManager.TimeBetweenSelectionPolls.Value})"); + Logger.Log($"Polling adjusted (listing: {multiplayerRoomManager.TimeBetweenListingPolls.Value}, selection: {multiplayerRoomManager.TimeBetweenSelectionPolls.Value})"); } protected override Room CreateNewRoom() { var room = new Room { Name = { Value = $"{API.LocalUser}'s awesome room" } }; - room.Category.Value = RoomCategory.Multiplayer; + room.Category.Value = RoomCategory.Realtime; return room; } From 8a36eab060264b8b903142000657caf5c7d3056c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Dec 2020 23:42:02 +0900 Subject: [PATCH 306/328] Move missed file from Play namespace --- osu.Game/Screens/Multi/Multiplayer/MultiplayerPlayer.cs | 2 +- osu.Game/Screens/Multi/{Play => Playlists}/PlaylistsPlayer.cs | 2 +- osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) rename osu.Game/Screens/Multi/{Play => Playlists}/PlaylistsPlayer.cs (99%) diff --git a/osu.Game/Screens/Multi/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/Multi/Multiplayer/MultiplayerPlayer.cs index 3255bcc642..32d95aa11f 100644 --- a/osu.Game/Screens/Multi/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/Multi/Multiplayer/MultiplayerPlayer.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Scoring; -using osu.Game.Screens.Multi.Play; +using osu.Game.Screens.Multi.Playlists; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Ranking; diff --git a/osu.Game/Screens/Multi/Play/PlaylistsPlayer.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsPlayer.cs similarity index 99% rename from osu.Game/Screens/Multi/Play/PlaylistsPlayer.cs rename to osu.Game/Screens/Multi/Playlists/PlaylistsPlayer.cs index f05f732494..40198d82cd 100644 --- a/osu.Game/Screens/Multi/Play/PlaylistsPlayer.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsPlayer.cs @@ -18,7 +18,7 @@ using osu.Game.Screens.Multi.Ranking; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; -namespace osu.Game.Screens.Multi.Play +namespace osu.Game.Screens.Multi.Playlists { public class PlaylistsPlayer : Player { diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs index 67242003e6..f6d084b112 100644 --- a/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs @@ -13,7 +13,6 @@ using osu.Game.Online.Rooms; using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Multi.Match; using osu.Game.Screens.Multi.Match.Components; -using osu.Game.Screens.Multi.Play; using osu.Game.Screens.Multi.Ranking; using osu.Game.Screens.Select; using osu.Game.Users; From 836d1491d0d1576ee444179953eb863bb8c1d740 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Dec 2020 23:45:44 +0900 Subject: [PATCH 307/328] PlaylistsMultiplayer -> Playlists --- .../Visual/Navigation/TestSceneScreenNavigation.cs | 5 ++--- osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs | 3 +-- osu.Game/Screens/Menu/MainMenu.cs | 2 +- .../Playlists/{PlaylistsMultiplayer.cs => Playlists.cs} | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) rename osu.Game/Screens/Multi/Playlists/{PlaylistsMultiplayer.cs => Playlists.cs} (97%) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 381bbca74f..ac63c89183 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -11,7 +11,6 @@ using osu.Game.Beatmaps; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Overlays.Toolbar; -using osu.Game.Screens.Multi.Playlists; using osu.Game.Screens.Play; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Options; @@ -108,14 +107,14 @@ namespace osu.Game.Tests.Visual.Navigation [Test] public void TestExitMultiWithEscape() { - PushAndConfirm(() => new PlaylistsMultiplayer()); + PushAndConfirm(() => new Screens.Multi.Playlists.Playlists()); exitViaEscapeAndConfirm(); } [Test] public void TestExitMultiWithBackButton() { - PushAndConfirm(() => new PlaylistsMultiplayer()); + PushAndConfirm(() => new Screens.Multi.Playlists.Playlists()); exitViaBackButtonAndConfirm(); } diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs index 8203ca4845..b780eb5347 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs @@ -4,7 +4,6 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Game.Overlays; -using osu.Game.Screens.Multi.Playlists; namespace osu.Game.Tests.Visual.Playlists { @@ -18,7 +17,7 @@ namespace osu.Game.Tests.Visual.Playlists public TestScenePlaylistsScreen() { - var multi = new PlaylistsMultiplayer(); + var multi = new Screens.Multi.Playlists.Playlists(); AddStep("show", () => LoadScreen(multi)); AddUntilStep("wait for loaded", () => multi.IsLoaded); diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 15ac2237d3..aeb58a75fc 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -106,7 +106,7 @@ namespace osu.Game.Screens.Menu }, OnSolo = onSolo, OnMultiplayer = () => this.Push(new Multiplayer()), - OnPlaylists = () => this.Push(new PlaylistsMultiplayer()), + OnPlaylists = () => this.Push(new Playlists()), OnExit = confirmAndExit, } } diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsMultiplayer.cs b/osu.Game/Screens/Multi/Playlists/Playlists.cs similarity index 97% rename from osu.Game/Screens/Multi/Playlists/PlaylistsMultiplayer.cs rename to osu.Game/Screens/Multi/Playlists/Playlists.cs index 92b0160247..da6aade942 100644 --- a/osu.Game/Screens/Multi/Playlists/PlaylistsMultiplayer.cs +++ b/osu.Game/Screens/Multi/Playlists/Playlists.cs @@ -11,7 +11,7 @@ using osu.Game.Screens.Multi.Match; namespace osu.Game.Screens.Multi.Playlists { - public class PlaylistsMultiplayer : MultiplayerScreen + public class Playlists : MultiplayerScreen { protected override void UpdatePollingRate(bool isIdle) { From 9de1a67e0389017d5a233fa7b38478f26287b305 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Dec 2020 23:47:32 +0900 Subject: [PATCH 308/328] Move PlaylistsResultsScreen to correct namespace --- .../Visual/Playlists/TestScenePlaylistsResultsScreen.cs | 2 +- osu.Game/Screens/Multi/Multiplayer/MultiplayerResultsScreen.cs | 2 +- osu.Game/Screens/Multi/Playlists/PlaylistsPlayer.cs | 1 - .../Multi/{Ranking => Playlists}/PlaylistsResultsScreen.cs | 2 +- osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs | 1 - 5 files changed, 3 insertions(+), 5 deletions(-) rename osu.Game/Screens/Multi/{Ranking => Playlists}/PlaylistsResultsScreen.cs (99%) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs index b42f2e1d2d..97bb48c7b5 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs @@ -19,7 +19,7 @@ using osu.Game.Online.Rooms; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; -using osu.Game.Screens.Multi.Ranking; +using osu.Game.Screens.Multi.Playlists; using osu.Game.Screens.Ranking; using osu.Game.Tests.Beatmaps; using osu.Game.Users; diff --git a/osu.Game/Screens/Multi/Multiplayer/MultiplayerResultsScreen.cs b/osu.Game/Screens/Multi/Multiplayer/MultiplayerResultsScreen.cs index a01930c5ef..3e39473954 100644 --- a/osu.Game/Screens/Multi/Multiplayer/MultiplayerResultsScreen.cs +++ b/osu.Game/Screens/Multi/Multiplayer/MultiplayerResultsScreen.cs @@ -3,7 +3,7 @@ using osu.Game.Online.Rooms; using osu.Game.Scoring; -using osu.Game.Screens.Multi.Ranking; +using osu.Game.Screens.Multi.Playlists; namespace osu.Game.Screens.Multi.Multiplayer { diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsPlayer.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsPlayer.cs index 40198d82cd..25a3340ead 100644 --- a/osu.Game/Screens/Multi/Playlists/PlaylistsPlayer.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsPlayer.cs @@ -14,7 +14,6 @@ using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Scoring; -using osu.Game.Screens.Multi.Ranking; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; diff --git a/osu.Game/Screens/Multi/Ranking/PlaylistsResultsScreen.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsResultsScreen.cs similarity index 99% rename from osu.Game/Screens/Multi/Ranking/PlaylistsResultsScreen.cs rename to osu.Game/Screens/Multi/Playlists/PlaylistsResultsScreen.cs index 7b1ab2c5b7..5d1d3a2724 100644 --- a/osu.Game/Screens/Multi/Ranking/PlaylistsResultsScreen.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsResultsScreen.cs @@ -15,7 +15,7 @@ using osu.Game.Online.Rooms; using osu.Game.Scoring; using osu.Game.Screens.Ranking; -namespace osu.Game.Screens.Multi.Ranking +namespace osu.Game.Screens.Multi.Playlists { public class PlaylistsResultsScreen : ResultsScreen { diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs index f6d084b112..4867268fe1 100644 --- a/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs @@ -13,7 +13,6 @@ using osu.Game.Online.Rooms; using osu.Game.Screens.Multi.Components; using osu.Game.Screens.Multi.Match; using osu.Game.Screens.Multi.Match.Components; -using osu.Game.Screens.Multi.Ranking; using osu.Game.Screens.Select; using osu.Game.Users; using Footer = osu.Game.Screens.Multi.Match.Components.Footer; From e797e5ce7a73441cc2c65e4fd5909c789b3fc3fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 25 Dec 2020 16:48:03 +0100 Subject: [PATCH 309/328] Rename Multi directory to OnlinePlay --- .../Components/BeatmapDetailAreaPlaylistTabItem.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/Components/BeatmapTitle.cs | 0 .../Screens/{Multi => OnlinePlay}/Components/BeatmapTypeInfo.cs | 0 .../{Multi => OnlinePlay}/Components/DisableableTabControl.cs | 0 .../Screens/{Multi => OnlinePlay}/Components/DrawableGameType.cs | 0 .../{Multi => OnlinePlay}/Components/ListingPollingComponent.cs | 0 .../{Multi => OnlinePlay}/Components/MatchBeatmapDetailArea.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/Components/ModeTypeInfo.cs | 0 .../Components/MultiplayerBackgroundSprite.cs | 0 .../Screens/{Multi => OnlinePlay}/Components/OverlinedHeader.cs | 0 .../{Multi => OnlinePlay}/Components/OverlinedPlaylistHeader.cs | 0 .../{Multi => OnlinePlay}/Components/ParticipantCountDisplay.cs | 0 .../{Multi => OnlinePlay}/Components/ParticipantsDisplay.cs | 0 .../Screens/{Multi => OnlinePlay}/Components/ParticipantsList.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/Components/ReadyButton.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/Components/RoomManager.cs | 0 .../{Multi => OnlinePlay}/Components/RoomPollingComponent.cs | 0 .../Screens/{Multi => OnlinePlay}/Components/RoomStatusInfo.cs | 0 .../{Multi => OnlinePlay}/Components/SelectionPollingComponent.cs | 0 .../{Multi => OnlinePlay}/Components/StatusColouredContainer.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/DrawableRoomPlaylist.cs | 0 .../Screens/{Multi => OnlinePlay}/DrawableRoomPlaylistItem.cs | 0 .../{Multi => OnlinePlay}/DrawableRoomPlaylistWithResults.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/Header.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/IMultiplayerSubScreen.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/IRoomManager.cs | 0 .../{Multi => OnlinePlay}/Lounge/Components/DrawableRoom.cs | 0 .../{Multi => OnlinePlay}/Lounge/Components/FilterControl.cs | 0 .../{Multi => OnlinePlay}/Lounge/Components/FilterCriteria.cs | 0 .../{Multi => OnlinePlay}/Lounge/Components/ParticipantInfo.cs | 0 .../Lounge/Components/PlaylistsFilterControl.cs | 0 .../Screens/{Multi => OnlinePlay}/Lounge/Components/RoomInfo.cs | 0 .../{Multi => OnlinePlay}/Lounge/Components/RoomInspector.cs | 0 .../{Multi => OnlinePlay}/Lounge/Components/RoomStatusFilter.cs | 0 .../{Multi => OnlinePlay}/Lounge/Components/RoomsContainer.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/Lounge/LoungeSubScreen.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/Match/Components/Footer.cs | 0 .../{Multi => OnlinePlay}/Match/Components/GameTypePicker.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/Match/Components/Header.cs | 0 .../{Multi => OnlinePlay}/Match/Components/MatchChatDisplay.cs | 0 .../{Multi => OnlinePlay}/Match/Components/MatchLeaderboard.cs | 0 .../Match/Components/MatchLeaderboardScore.cs | 0 .../Match/Components/MatchSettingsOverlay.cs | 0 .../Match/Components/PurpleTriangleButton.cs | 0 .../Match/Components/RoomAvailabilityPicker.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/Match/RoomSubScreen.cs | 0 .../Multiplayer/CreateMultiplayerMatchButton.cs | 0 .../Multiplayer/Match/BeatmapSelectionControl.cs | 0 .../Multiplayer/Match/MultiplayerMatchFooter.cs | 0 .../Multiplayer/Match/MultiplayerMatchHeader.cs | 0 .../Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs | 0 .../Multiplayer/Match/MultiplayerReadyButton.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/Multiplayer.cs | 0 .../{Multi => OnlinePlay}/Multiplayer/MultiplayerFilterControl.cs | 0 .../Multiplayer/MultiplayerLoungeSubScreen.cs | 0 .../Multiplayer/MultiplayerMatchSongSelect.cs | 0 .../Multiplayer/MultiplayerMatchSubScreen.cs | 0 .../{Multi => OnlinePlay}/Multiplayer/MultiplayerPlayer.cs | 0 .../{Multi => OnlinePlay}/Multiplayer/MultiplayerResultsScreen.cs | 0 .../{Multi => OnlinePlay}/Multiplayer/MultiplayerRoomComposite.cs | 0 .../{Multi => OnlinePlay}/Multiplayer/MultiplayerRoomManager.cs | 0 .../Multiplayer/Participants/ParticipantPanel.cs | 0 .../Multiplayer/Participants/ParticipantsList.cs | 0 .../Multiplayer/Participants/ParticipantsListHeader.cs | 0 .../Multiplayer/Participants/StateDisplay.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/MultiplayerComposite.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/MultiplayerScreen.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/MultiplayerSubScreen.cs | 0 .../Screens/{Multi => OnlinePlay}/MultiplayerSubScreenStack.cs | 0 .../{Multi => OnlinePlay}/Playlists/CreatePlaylistsRoomButton.cs | 0 osu.Game/Screens/{Multi => OnlinePlay}/Playlists/Playlists.cs | 0 .../{Multi => OnlinePlay}/Playlists/PlaylistsLoungeSubScreen.cs | 0 .../Playlists/PlaylistsMatchSettingsOverlay.cs | 0 .../Screens/{Multi => OnlinePlay}/Playlists/PlaylistsPlayer.cs | 0 .../{Multi => OnlinePlay}/Playlists/PlaylistsReadyButton.cs | 0 .../{Multi => OnlinePlay}/Playlists/PlaylistsResultsScreen.cs | 0 .../{Multi => OnlinePlay}/Playlists/PlaylistsRoomManager.cs | 0 .../{Multi => OnlinePlay}/Playlists/PlaylistsRoomSubScreen.cs | 0 78 files changed, 0 insertions(+), 0 deletions(-) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/BeatmapDetailAreaPlaylistTabItem.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/BeatmapTitle.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/BeatmapTypeInfo.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/DisableableTabControl.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/DrawableGameType.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/ListingPollingComponent.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/MatchBeatmapDetailArea.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/ModeTypeInfo.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/MultiplayerBackgroundSprite.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/OverlinedHeader.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/OverlinedPlaylistHeader.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/ParticipantCountDisplay.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/ParticipantsDisplay.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/ParticipantsList.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/ReadyButton.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/RoomManager.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/RoomPollingComponent.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/RoomStatusInfo.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/SelectionPollingComponent.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Components/StatusColouredContainer.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/DrawableRoomPlaylist.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/DrawableRoomPlaylistItem.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/DrawableRoomPlaylistWithResults.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Header.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/IMultiplayerSubScreen.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/IRoomManager.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Lounge/Components/DrawableRoom.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Lounge/Components/FilterControl.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Lounge/Components/FilterCriteria.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Lounge/Components/ParticipantInfo.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Lounge/Components/PlaylistsFilterControl.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Lounge/Components/RoomInfo.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Lounge/Components/RoomInspector.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Lounge/Components/RoomStatusFilter.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Lounge/Components/RoomsContainer.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Lounge/LoungeSubScreen.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Match/Components/Footer.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Match/Components/GameTypePicker.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Match/Components/Header.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Match/Components/MatchChatDisplay.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Match/Components/MatchLeaderboard.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Match/Components/MatchLeaderboardScore.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Match/Components/MatchSettingsOverlay.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Match/Components/PurpleTriangleButton.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Match/Components/RoomAvailabilityPicker.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Match/RoomSubScreen.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/CreateMultiplayerMatchButton.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/Match/BeatmapSelectionControl.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/Match/MultiplayerMatchFooter.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/Match/MultiplayerMatchHeader.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/Match/MultiplayerReadyButton.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/Multiplayer.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/MultiplayerFilterControl.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/MultiplayerLoungeSubScreen.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/MultiplayerMatchSongSelect.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/MultiplayerMatchSubScreen.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/MultiplayerPlayer.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/MultiplayerResultsScreen.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/MultiplayerRoomComposite.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/MultiplayerRoomManager.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/Participants/ParticipantPanel.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/Participants/ParticipantsList.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/Participants/ParticipantsListHeader.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Multiplayer/Participants/StateDisplay.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/MultiplayerComposite.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/MultiplayerScreen.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/MultiplayerSubScreen.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/MultiplayerSubScreenStack.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Playlists/CreatePlaylistsRoomButton.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Playlists/Playlists.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Playlists/PlaylistsLoungeSubScreen.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Playlists/PlaylistsMatchSettingsOverlay.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Playlists/PlaylistsPlayer.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Playlists/PlaylistsReadyButton.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Playlists/PlaylistsResultsScreen.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Playlists/PlaylistsRoomManager.cs (100%) rename osu.Game/Screens/{Multi => OnlinePlay}/Playlists/PlaylistsRoomSubScreen.cs (100%) diff --git a/osu.Game/Screens/Multi/Components/BeatmapDetailAreaPlaylistTabItem.cs b/osu.Game/Screens/OnlinePlay/Components/BeatmapDetailAreaPlaylistTabItem.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/BeatmapDetailAreaPlaylistTabItem.cs rename to osu.Game/Screens/OnlinePlay/Components/BeatmapDetailAreaPlaylistTabItem.cs diff --git a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs b/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/BeatmapTitle.cs rename to osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs diff --git a/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs b/osu.Game/Screens/OnlinePlay/Components/BeatmapTypeInfo.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs rename to osu.Game/Screens/OnlinePlay/Components/BeatmapTypeInfo.cs diff --git a/osu.Game/Screens/Multi/Components/DisableableTabControl.cs b/osu.Game/Screens/OnlinePlay/Components/DisableableTabControl.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/DisableableTabControl.cs rename to osu.Game/Screens/OnlinePlay/Components/DisableableTabControl.cs diff --git a/osu.Game/Screens/Multi/Components/DrawableGameType.cs b/osu.Game/Screens/OnlinePlay/Components/DrawableGameType.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/DrawableGameType.cs rename to osu.Game/Screens/OnlinePlay/Components/DrawableGameType.cs diff --git a/osu.Game/Screens/Multi/Components/ListingPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/ListingPollingComponent.cs rename to osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs diff --git a/osu.Game/Screens/Multi/Components/MatchBeatmapDetailArea.cs b/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/MatchBeatmapDetailArea.cs rename to osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs diff --git a/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs b/osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/ModeTypeInfo.cs rename to osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs diff --git a/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs b/osu.Game/Screens/OnlinePlay/Components/MultiplayerBackgroundSprite.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs rename to osu.Game/Screens/OnlinePlay/Components/MultiplayerBackgroundSprite.cs diff --git a/osu.Game/Screens/Multi/Components/OverlinedHeader.cs b/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/OverlinedHeader.cs rename to osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs diff --git a/osu.Game/Screens/Multi/Components/OverlinedPlaylistHeader.cs b/osu.Game/Screens/OnlinePlay/Components/OverlinedPlaylistHeader.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/OverlinedPlaylistHeader.cs rename to osu.Game/Screens/OnlinePlay/Components/OverlinedPlaylistHeader.cs diff --git a/osu.Game/Screens/Multi/Components/ParticipantCountDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/ParticipantCountDisplay.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/ParticipantCountDisplay.cs rename to osu.Game/Screens/OnlinePlay/Components/ParticipantCountDisplay.cs diff --git a/osu.Game/Screens/Multi/Components/ParticipantsDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/ParticipantsDisplay.cs rename to osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs diff --git a/osu.Game/Screens/Multi/Components/ParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/ParticipantsList.cs rename to osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs diff --git a/osu.Game/Screens/Multi/Components/ReadyButton.cs b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/ReadyButton.cs rename to osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs diff --git a/osu.Game/Screens/Multi/Components/RoomManager.cs b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/RoomManager.cs rename to osu.Game/Screens/OnlinePlay/Components/RoomManager.cs diff --git a/osu.Game/Screens/Multi/Components/RoomPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/RoomPollingComponent.cs rename to osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs diff --git a/osu.Game/Screens/Multi/Components/RoomStatusInfo.cs b/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/RoomStatusInfo.cs rename to osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs diff --git a/osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/SelectionPollingComponent.cs rename to osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs diff --git a/osu.Game/Screens/Multi/Components/StatusColouredContainer.cs b/osu.Game/Screens/OnlinePlay/Components/StatusColouredContainer.cs similarity index 100% rename from osu.Game/Screens/Multi/Components/StatusColouredContainer.cs rename to osu.Game/Screens/OnlinePlay/Components/StatusColouredContainer.cs diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylist.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs similarity index 100% rename from osu.Game/Screens/Multi/DrawableRoomPlaylist.cs rename to osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs similarity index 100% rename from osu.Game/Screens/Multi/DrawableRoomPlaylistItem.cs rename to osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs diff --git a/osu.Game/Screens/Multi/DrawableRoomPlaylistWithResults.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistWithResults.cs similarity index 100% rename from osu.Game/Screens/Multi/DrawableRoomPlaylistWithResults.cs rename to osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistWithResults.cs diff --git a/osu.Game/Screens/Multi/Header.cs b/osu.Game/Screens/OnlinePlay/Header.cs similarity index 100% rename from osu.Game/Screens/Multi/Header.cs rename to osu.Game/Screens/OnlinePlay/Header.cs diff --git a/osu.Game/Screens/Multi/IMultiplayerSubScreen.cs b/osu.Game/Screens/OnlinePlay/IMultiplayerSubScreen.cs similarity index 100% rename from osu.Game/Screens/Multi/IMultiplayerSubScreen.cs rename to osu.Game/Screens/OnlinePlay/IMultiplayerSubScreen.cs diff --git a/osu.Game/Screens/Multi/IRoomManager.cs b/osu.Game/Screens/OnlinePlay/IRoomManager.cs similarity index 100% rename from osu.Game/Screens/Multi/IRoomManager.cs rename to osu.Game/Screens/OnlinePlay/IRoomManager.cs diff --git a/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs similarity index 100% rename from osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs diff --git a/osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs similarity index 100% rename from osu.Game/Screens/Multi/Lounge/Components/FilterControl.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs diff --git a/osu.Game/Screens/Multi/Lounge/Components/FilterCriteria.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterCriteria.cs similarity index 100% rename from osu.Game/Screens/Multi/Lounge/Components/FilterCriteria.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/FilterCriteria.cs diff --git a/osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs similarity index 100% rename from osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs diff --git a/osu.Game/Screens/Multi/Lounge/Components/PlaylistsFilterControl.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs similarity index 100% rename from osu.Game/Screens/Multi/Lounge/Components/PlaylistsFilterControl.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomInfo.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs similarity index 100% rename from osu.Game/Screens/Multi/Lounge/Components/RoomInfo.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs similarity index 100% rename from osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomStatusFilter.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusFilter.cs similarity index 100% rename from osu.Game/Screens/Multi/Lounge/Components/RoomStatusFilter.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusFilter.cs diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs similarity index 100% rename from osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs similarity index 100% rename from osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs rename to osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs diff --git a/osu.Game/Screens/Multi/Match/Components/Footer.cs b/osu.Game/Screens/OnlinePlay/Match/Components/Footer.cs similarity index 100% rename from osu.Game/Screens/Multi/Match/Components/Footer.cs rename to osu.Game/Screens/OnlinePlay/Match/Components/Footer.cs diff --git a/osu.Game/Screens/Multi/Match/Components/GameTypePicker.cs b/osu.Game/Screens/OnlinePlay/Match/Components/GameTypePicker.cs similarity index 100% rename from osu.Game/Screens/Multi/Match/Components/GameTypePicker.cs rename to osu.Game/Screens/OnlinePlay/Match/Components/GameTypePicker.cs diff --git a/osu.Game/Screens/Multi/Match/Components/Header.cs b/osu.Game/Screens/OnlinePlay/Match/Components/Header.cs similarity index 100% rename from osu.Game/Screens/Multi/Match/Components/Header.cs rename to osu.Game/Screens/OnlinePlay/Match/Components/Header.cs diff --git a/osu.Game/Screens/Multi/Match/Components/MatchChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs similarity index 100% rename from osu.Game/Screens/Multi/Match/Components/MatchChatDisplay.cs rename to osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs diff --git a/osu.Game/Screens/Multi/Match/Components/MatchLeaderboard.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboard.cs similarity index 100% rename from osu.Game/Screens/Multi/Match/Components/MatchLeaderboard.cs rename to osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboard.cs diff --git a/osu.Game/Screens/Multi/Match/Components/MatchLeaderboardScore.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboardScore.cs similarity index 100% rename from osu.Game/Screens/Multi/Match/Components/MatchLeaderboardScore.cs rename to osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboardScore.cs diff --git a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs similarity index 100% rename from osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs rename to osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs diff --git a/osu.Game/Screens/Multi/Match/Components/PurpleTriangleButton.cs b/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs similarity index 100% rename from osu.Game/Screens/Multi/Match/Components/PurpleTriangleButton.cs rename to osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs diff --git a/osu.Game/Screens/Multi/Match/Components/RoomAvailabilityPicker.cs b/osu.Game/Screens/OnlinePlay/Match/Components/RoomAvailabilityPicker.cs similarity index 100% rename from osu.Game/Screens/Multi/Match/Components/RoomAvailabilityPicker.cs rename to osu.Game/Screens/OnlinePlay/Match/Components/RoomAvailabilityPicker.cs diff --git a/osu.Game/Screens/Multi/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs similarity index 100% rename from osu.Game/Screens/Multi/Match/RoomSubScreen.cs rename to osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/CreateMultiplayerMatchButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/CreateMultiplayerMatchButton.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/Match/BeatmapSelectionControl.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchFooter.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchFooter.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchHeader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchHeader.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerReadyButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/Match/MultiplayerReadyButton.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/Multiplayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/Multiplayer.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/MultiplayerFilterControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerFilterControl.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/MultiplayerFilterControl.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerFilterControl.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/MultiplayerLoungeSubScreen.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/MultiplayerMatchSongSelect.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/MultiplayerMatchSubScreen.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/MultiplayerPlayer.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/MultiplayerResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/MultiplayerResultsScreen.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/MultiplayerRoomComposite.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/MultiplayerRoomComposite.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/MultiplayerRoomManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/MultiplayerRoomManager.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantPanel.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantsList.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantsListHeader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsListHeader.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/Participants/ParticipantsListHeader.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsListHeader.cs diff --git a/osu.Game/Screens/Multi/Multiplayer/Participants/StateDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs similarity index 100% rename from osu.Game/Screens/Multi/Multiplayer/Participants/StateDisplay.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs diff --git a/osu.Game/Screens/Multi/MultiplayerComposite.cs b/osu.Game/Screens/OnlinePlay/MultiplayerComposite.cs similarity index 100% rename from osu.Game/Screens/Multi/MultiplayerComposite.cs rename to osu.Game/Screens/OnlinePlay/MultiplayerComposite.cs diff --git a/osu.Game/Screens/Multi/MultiplayerScreen.cs b/osu.Game/Screens/OnlinePlay/MultiplayerScreen.cs similarity index 100% rename from osu.Game/Screens/Multi/MultiplayerScreen.cs rename to osu.Game/Screens/OnlinePlay/MultiplayerScreen.cs diff --git a/osu.Game/Screens/Multi/MultiplayerSubScreen.cs b/osu.Game/Screens/OnlinePlay/MultiplayerSubScreen.cs similarity index 100% rename from osu.Game/Screens/Multi/MultiplayerSubScreen.cs rename to osu.Game/Screens/OnlinePlay/MultiplayerSubScreen.cs diff --git a/osu.Game/Screens/Multi/MultiplayerSubScreenStack.cs b/osu.Game/Screens/OnlinePlay/MultiplayerSubScreenStack.cs similarity index 100% rename from osu.Game/Screens/Multi/MultiplayerSubScreenStack.cs rename to osu.Game/Screens/OnlinePlay/MultiplayerSubScreenStack.cs diff --git a/osu.Game/Screens/Multi/Playlists/CreatePlaylistsRoomButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs similarity index 100% rename from osu.Game/Screens/Multi/Playlists/CreatePlaylistsRoomButton.cs rename to osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs diff --git a/osu.Game/Screens/Multi/Playlists/Playlists.cs b/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs similarity index 100% rename from osu.Game/Screens/Multi/Playlists/Playlists.cs rename to osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs similarity index 100% rename from osu.Game/Screens/Multi/Playlists/PlaylistsLoungeSubScreen.cs rename to osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs similarity index 100% rename from osu.Game/Screens/Multi/Playlists/PlaylistsMatchSettingsOverlay.cs rename to osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsPlayer.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs similarity index 100% rename from osu.Game/Screens/Multi/Playlists/PlaylistsPlayer.cs rename to osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsReadyButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsReadyButton.cs similarity index 100% rename from osu.Game/Screens/Multi/Playlists/PlaylistsReadyButton.cs rename to osu.Game/Screens/OnlinePlay/Playlists/PlaylistsReadyButton.cs diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs similarity index 100% rename from osu.Game/Screens/Multi/Playlists/PlaylistsResultsScreen.cs rename to osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsRoomManager.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomManager.cs similarity index 100% rename from osu.Game/Screens/Multi/Playlists/PlaylistsRoomManager.cs rename to osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomManager.cs diff --git a/osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs similarity index 100% rename from osu.Game/Screens/Multi/Playlists/PlaylistsRoomSubScreen.cs rename to osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs From 83fb7c7a1ae3a0aac1e42ec8160c90d1aef5009e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 25 Dec 2020 16:50:00 +0100 Subject: [PATCH 310/328] Re-namespace all files in OnlinePlay directory --- .../Visual/Multiplayer/RoomManagerTestScene.cs | 2 +- .../Visual/Multiplayer/TestRoomManager.cs | 2 +- .../Multiplayer/TestSceneDrawableRoomPlaylist.cs | 2 +- .../Visual/Multiplayer/TestSceneLoungeRoomInfo.cs | 2 +- .../Multiplayer/TestSceneLoungeRoomsContainer.cs | 2 +- .../Multiplayer/TestSceneMatchBeatmapDetailArea.cs | 2 +- .../Visual/Multiplayer/TestSceneMatchHeader.cs | 2 +- .../Multiplayer/TestSceneMatchLeaderboard.cs | 2 +- .../Visual/Multiplayer/TestSceneMatchSongSelect.cs | 2 +- .../Visual/Multiplayer/TestSceneMultiHeader.cs | 2 +- .../Visual/Multiplayer/TestSceneMultiplayer.cs | 4 ++-- .../TestSceneMultiplayerMatchSubScreen.cs | 4 ++-- .../TestSceneMultiplayerParticipantsList.cs | 2 +- .../Multiplayer/TestSceneMultiplayerReadyButton.cs | 2 +- .../Visual/Multiplayer/TestSceneRoomStatus.cs | 2 +- .../Visual/Navigation/TestSceneScreenNavigation.cs | 4 ++-- .../Playlists/TestScenePlaylistsFilterControl.cs | 2 +- .../Playlists/TestScenePlaylistsLoungeSubScreen.cs | 6 +++--- .../TestScenePlaylistsMatchSettingsOverlay.cs | 4 ++-- .../TestScenePlaylistsParticipantsList.cs | 2 +- .../Playlists/TestScenePlaylistsResultsScreen.cs | 2 +- .../Playlists/TestScenePlaylistsRoomSubScreen.cs | 6 +++--- .../Visual/Playlists/TestScenePlaylistsScreen.cs | 2 +- osu.Game/Online/Rooms/GetRoomsRequest.cs | 2 +- .../Overlays/Dashboard/CurrentlyPlayingDisplay.cs | 2 +- osu.Game/Screens/Menu/MainMenu.cs | 4 ++-- .../Components/BeatmapDetailAreaPlaylistTabItem.cs | 2 +- .../Screens/OnlinePlay/Components/BeatmapTitle.cs | 2 +- .../OnlinePlay/Components/BeatmapTypeInfo.cs | 2 +- .../OnlinePlay/Components/DisableableTabControl.cs | 2 +- .../OnlinePlay/Components/DrawableGameType.cs | 2 +- .../Components/ListingPollingComponent.cs | 4 ++-- .../Components/MatchBeatmapDetailArea.cs | 2 +- .../Screens/OnlinePlay/Components/ModeTypeInfo.cs | 2 +- .../Components/MultiplayerBackgroundSprite.cs | 2 +- .../OnlinePlay/Components/OverlinedHeader.cs | 2 +- .../Components/OverlinedPlaylistHeader.cs | 2 +- .../Components/ParticipantCountDisplay.cs | 2 +- .../OnlinePlay/Components/ParticipantsDisplay.cs | 2 +- .../OnlinePlay/Components/ParticipantsList.cs | 2 +- .../Screens/OnlinePlay/Components/ReadyButton.cs | 2 +- .../Screens/OnlinePlay/Components/RoomManager.cs | 2 +- .../OnlinePlay/Components/RoomPollingComponent.cs | 2 +- .../OnlinePlay/Components/RoomStatusInfo.cs | 2 +- .../Components/SelectionPollingComponent.cs | 2 +- .../Components/StatusColouredContainer.cs | 2 +- .../Screens/OnlinePlay/DrawableRoomPlaylist.cs | 2 +- .../Screens/OnlinePlay/DrawableRoomPlaylistItem.cs | 2 +- .../OnlinePlay/DrawableRoomPlaylistWithResults.cs | 2 +- osu.Game/Screens/OnlinePlay/Header.cs | 4 ++-- .../Screens/OnlinePlay/IMultiplayerSubScreen.cs | 2 +- osu.Game/Screens/OnlinePlay/IRoomManager.cs | 2 +- .../OnlinePlay/Lounge/Components/DrawableRoom.cs | 10 +++++----- .../OnlinePlay/Lounge/Components/FilterControl.cs | 2 +- .../OnlinePlay/Lounge/Components/FilterCriteria.cs | 2 +- .../Lounge/Components/ParticipantInfo.cs | 2 +- .../Lounge/Components/PlaylistsFilterControl.cs | 2 +- .../OnlinePlay/Lounge/Components/RoomInfo.cs | 4 ++-- .../OnlinePlay/Lounge/Components/RoomInspector.cs | 4 ++-- .../Lounge/Components/RoomStatusFilter.cs | 2 +- .../OnlinePlay/Lounge/Components/RoomsContainer.cs | 6 +++--- .../Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 6 +++--- .../Screens/OnlinePlay/Match/Components/Footer.cs | 4 ++-- .../OnlinePlay/Match/Components/GameTypePicker.cs | 4 ++-- .../Screens/OnlinePlay/Match/Components/Header.cs | 2 +- .../Match/Components/MatchChatDisplay.cs | 2 +- .../Match/Components/MatchLeaderboard.cs | 2 +- .../Match/Components/MatchLeaderboardScore.cs | 2 +- .../Match/Components/MatchSettingsOverlay.cs | 2 +- .../Match/Components/PurpleTriangleButton.cs | 2 +- .../Match/Components/RoomAvailabilityPicker.cs | 4 ++-- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 2 +- .../Multiplayer/CreateMultiplayerMatchButton.cs | 4 ++-- .../Multiplayer/Match/BeatmapSelectionControl.cs | 4 ++-- .../Multiplayer/Match/MultiplayerMatchFooter.cs | 2 +- .../Multiplayer/Match/MultiplayerMatchHeader.cs | 4 ++-- .../Match/MultiplayerMatchSettingsOverlay.cs | 4 ++-- .../Multiplayer/Match/MultiplayerReadyButton.cs | 4 ++-- .../Screens/OnlinePlay/Multiplayer/Multiplayer.cs | 6 +++--- .../Multiplayer/MultiplayerFilterControl.cs | 4 ++-- .../Multiplayer/MultiplayerLoungeSubScreen.cs | 8 ++++---- .../Multiplayer/MultiplayerMatchSongSelect.cs | 2 +- .../Multiplayer/MultiplayerMatchSubScreen.cs | 14 +++++++------- .../OnlinePlay/Multiplayer/MultiplayerPlayer.cs | 4 ++-- .../Multiplayer/MultiplayerResultsScreen.cs | 4 ++-- .../Multiplayer/MultiplayerRoomComposite.cs | 2 +- .../Multiplayer/MultiplayerRoomManager.cs | 4 ++-- .../Multiplayer/Participants/ParticipantPanel.cs | 2 +- .../Multiplayer/Participants/ParticipantsList.cs | 2 +- .../Participants/ParticipantsListHeader.cs | 4 ++-- .../Multiplayer/Participants/StateDisplay.cs | 2 +- .../Screens/OnlinePlay/MultiplayerComposite.cs | 2 +- osu.Game/Screens/OnlinePlay/MultiplayerScreen.cs | 10 +++++----- .../Screens/OnlinePlay/MultiplayerSubScreen.cs | 2 +- .../OnlinePlay/MultiplayerSubScreenStack.cs | 2 +- .../Playlists/CreatePlaylistsRoomButton.cs | 4 ++-- osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs | 8 ++++---- .../Playlists/PlaylistsLoungeSubScreen.cs | 8 ++++---- .../Playlists/PlaylistsMatchSettingsOverlay.cs | 4 ++-- .../OnlinePlay/Playlists/PlaylistsPlayer.cs | 2 +- .../OnlinePlay/Playlists/PlaylistsReadyButton.cs | 4 ++-- .../OnlinePlay/Playlists/PlaylistsResultsScreen.cs | 2 +- .../OnlinePlay/Playlists/PlaylistsRoomManager.cs | 4 ++-- .../OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs | 10 +++++----- osu.Game/Screens/Play/Spectator.cs | 2 +- osu.Game/Screens/Select/MatchSongSelect.cs | 4 ++-- .../Visual/Multiplayer/MultiplayerTestScene.cs | 4 ++-- .../Multiplayer/TestMultiplayerRoomContainer.cs | 4 ++-- .../Multiplayer/TestMultiplayerRoomManager.cs | 4 ++-- 109 files changed, 176 insertions(+), 176 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/RoomManagerTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/RoomManagerTestScene.cs index a2c496a504..c665a57452 100644 --- a/osu.Game.Tests/Visual/Multiplayer/RoomManagerTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/RoomManagerTestScene.cs @@ -6,7 +6,7 @@ using osu.Framework.Allocation; using osu.Game.Beatmaps; using osu.Game.Online.Rooms; using osu.Game.Rulesets; -using osu.Game.Screens.Multi; +using osu.Game.Screens.OnlinePlay; using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer diff --git a/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs b/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs index 7d9d4a6542..1785c99784 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestRoomManager.cs @@ -4,7 +4,7 @@ using System; using osu.Framework.Bindables; using osu.Game.Online.Rooms; -using osu.Game.Screens.Multi; +using osu.Game.Screens.OnlinePlay; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index 722e1a50ef..65c0cfd328 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -18,7 +18,7 @@ using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.Multi; +using osu.Game.Screens.OnlinePlay; using osu.Game.Tests.Beatmaps; using osuTK; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs index f58e1114b8..9f24347ae9 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs @@ -5,7 +5,7 @@ using System; using NUnit.Framework; using osu.Framework.Graphics; using osu.Game.Online.Rooms.RoomStatuses; -using osu.Game.Screens.Multi.Lounge.Components; +using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs index 9b6a6de7c2..279dcfa584 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Osu; -using osu.Game.Screens.Multi.Lounge.Components; +using osu.Game.Screens.OnlinePlay.Lounge.Components; using osuTK.Graphics; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs index 571330f50e..9ad9f2c883 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs @@ -9,7 +9,7 @@ using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Tests.Beatmaps; using osuTK; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs index 61968dce46..7cdc6b1a7d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs @@ -6,7 +6,7 @@ using osu.Game.Beatmaps; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs index 71b8ad05ee..64eaf0556b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs @@ -7,7 +7,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Online.API; -using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Users; using osuTK; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs index 157597e800..e0fd7d9874 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs @@ -18,7 +18,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.Multiplayer diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs index 0ccd882d95..089de223fc 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs @@ -5,7 +5,7 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Screens; -using osu.Game.Screens.Multi; +using osu.Game.Screens.OnlinePlay; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 5c07b9d0ea..2e39471dc0 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer @@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("room has 1 user", () => Client.Room?.Users.Count == 1); } - private class TestMultiplayer : Screens.Multi.Multiplayer.Multiplayer + private class TestMultiplayer : Screens.OnlinePlay.Multiplayer.Multiplayer { protected override RoomManager CreateRoomManager() => new TestMultiplayerRoomManager(); } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs index 6dc26dae57..8869718fd1 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs @@ -7,8 +7,8 @@ using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Osu; -using osu.Game.Screens.Multi.Multiplayer; -using osu.Game.Screens.Multi.Multiplayer.Match; +using osu.Game.Screens.OnlinePlay.Multiplayer; +using osu.Game.Screens.OnlinePlay.Multiplayer.Match; using osu.Game.Tests.Beatmaps; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs index ee2fa4ef5a..9181170bee 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Online.Multiplayer; -using osu.Game.Screens.Multi.Multiplayer.Participants; +using osu.Game.Screens.OnlinePlay.Multiplayer.Participants; using osu.Game.Users; using osuTK; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs index c8ebdb1b76..6b11613f1c 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs @@ -12,7 +12,7 @@ using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Rulesets; -using osu.Game.Screens.Multi.Multiplayer.Match; +using osu.Game.Screens.OnlinePlay.Multiplayer.Match; using osu.Game.Tests.Resources; using osu.Game.Users; using osuTK; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs index 7140050bd5..cec40635f3 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.RoomStatuses; -using osu.Game.Screens.Multi.Lounge.Components; +using osu.Game.Screens.OnlinePlay.Lounge.Components; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index ac63c89183..8480e6eaaa 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -107,14 +107,14 @@ namespace osu.Game.Tests.Visual.Navigation [Test] public void TestExitMultiWithEscape() { - PushAndConfirm(() => new Screens.Multi.Playlists.Playlists()); + PushAndConfirm(() => new Screens.OnlinePlay.Playlists.Playlists()); exitViaEscapeAndConfirm(); } [Test] public void TestExitMultiWithBackButton() { - PushAndConfirm(() => new Screens.Multi.Playlists.Playlists()); + PushAndConfirm(() => new Screens.OnlinePlay.Playlists.Playlists()); exitViaBackButtonAndConfirm(); } diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsFilterControl.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsFilterControl.cs index 66992b27a2..40e191dd7e 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsFilterControl.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsFilterControl.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics; -using osu.Game.Screens.Multi.Lounge.Components; +using osu.Game.Screens.OnlinePlay.Lounge.Components; namespace osu.Game.Tests.Visual.Playlists { diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs index 04555857f5..008c862cc3 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs @@ -8,9 +8,9 @@ using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Graphics.Containers; -using osu.Game.Screens.Multi.Lounge; -using osu.Game.Screens.Multi.Lounge.Components; -using osu.Game.Screens.Multi.Playlists; +using osu.Game.Screens.OnlinePlay.Lounge; +using osu.Game.Screens.OnlinePlay.Lounge.Components; +using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.Visual.Playlists diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs index 4e75619f13..44a79b6598 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs @@ -10,8 +10,8 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; -using osu.Game.Screens.Multi; -using osu.Game.Screens.Multi.Playlists; +using osu.Game.Screens.OnlinePlay; +using osu.Game.Screens.OnlinePlay.Playlists; namespace osu.Game.Tests.Visual.Playlists { diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs index 5a0f196df9..8dd81e02e2 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs @@ -3,7 +3,7 @@ using NUnit.Framework; using osu.Framework.Graphics; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Users; namespace osu.Game.Tests.Visual.Playlists diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs index 97bb48c7b5..cdcded8f61 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs @@ -19,7 +19,7 @@ using osu.Game.Online.Rooms; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; -using osu.Game.Screens.Multi.Playlists; +using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Ranking; using osu.Game.Tests.Beatmaps; using osu.Game.Users; diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs index 96ff93a145..a4c87d3ace 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs @@ -15,9 +15,9 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; -using osu.Game.Screens.Multi; -using osu.Game.Screens.Multi.Match.Components; -using osu.Game.Screens.Multi.Playlists; +using osu.Game.Screens.OnlinePlay; +using osu.Game.Screens.OnlinePlay.Match.Components; +using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Tests.Beatmaps; using osu.Game.Users; using osuTK.Input; diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs index b780eb5347..e52f823f0b 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs @@ -17,7 +17,7 @@ namespace osu.Game.Tests.Visual.Playlists public TestScenePlaylistsScreen() { - var multi = new Screens.Multi.Playlists.Playlists(); + var multi = new Screens.OnlinePlay.Playlists.Playlists(); AddStep("show", () => LoadScreen(multi)); AddUntilStep("wait for loaded", () => multi.IsLoaded); diff --git a/osu.Game/Online/Rooms/GetRoomsRequest.cs b/osu.Game/Online/Rooms/GetRoomsRequest.cs index 5084b8627f..e45365797a 100644 --- a/osu.Game/Online/Rooms/GetRoomsRequest.cs +++ b/osu.Game/Online/Rooms/GetRoomsRequest.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using Humanizer; using osu.Framework.IO.Network; using osu.Game.Online.API; -using osu.Game.Screens.Multi.Lounge.Components; +using osu.Game.Screens.OnlinePlay.Lounge.Components; namespace osu.Game.Online.Rooms { diff --git a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs index d39a81f5e8..c89699f2ee 100644 --- a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs +++ b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs @@ -11,7 +11,7 @@ using osu.Framework.Screens; using osu.Game.Database; using osu.Game.Online.API; using osu.Game.Online.Spectator; -using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.Play; using osu.Game.Users; using osuTK; diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index aeb58a75fc..9d5720ff34 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -17,8 +17,8 @@ using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; -using osu.Game.Screens.Multi.Multiplayer; -using osu.Game.Screens.Multi.Playlists; +using osu.Game.Screens.OnlinePlay.Multiplayer; +using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Select; namespace osu.Game.Screens.Menu diff --git a/osu.Game/Screens/OnlinePlay/Components/BeatmapDetailAreaPlaylistTabItem.cs b/osu.Game/Screens/OnlinePlay/Components/BeatmapDetailAreaPlaylistTabItem.cs index 3f2ab28f1a..fb927411e6 100644 --- a/osu.Game/Screens/OnlinePlay/Components/BeatmapDetailAreaPlaylistTabItem.cs +++ b/osu.Game/Screens/OnlinePlay/Components/BeatmapDetailAreaPlaylistTabItem.cs @@ -3,7 +3,7 @@ using osu.Game.Screens.Select; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public class BeatmapDetailAreaPlaylistTabItem : BeatmapDetailAreaTabItem { diff --git a/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs b/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs index 9e7a59d7d2..bc355d18a9 100644 --- a/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs +++ b/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Online.Chat; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public class BeatmapTitle : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Components/BeatmapTypeInfo.cs b/osu.Game/Screens/OnlinePlay/Components/BeatmapTypeInfo.cs index ce3b612262..434d7b75ed 100644 --- a/osu.Game/Screens/OnlinePlay/Components/BeatmapTypeInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Components/BeatmapTypeInfo.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osuTK; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public class BeatmapTypeInfo : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Components/DisableableTabControl.cs b/osu.Game/Screens/OnlinePlay/Components/DisableableTabControl.cs index 27b5aec4d3..bbc407e926 100644 --- a/osu.Game/Screens/OnlinePlay/Components/DisableableTabControl.cs +++ b/osu.Game/Screens/OnlinePlay/Components/DisableableTabControl.cs @@ -5,7 +5,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public abstract class DisableableTabControl : TabControl { diff --git a/osu.Game/Screens/OnlinePlay/Components/DrawableGameType.cs b/osu.Game/Screens/OnlinePlay/Components/DrawableGameType.cs index 38af6d065e..c4dc2a2b8f 100644 --- a/osu.Game/Screens/OnlinePlay/Components/DrawableGameType.cs +++ b/osu.Game/Screens/OnlinePlay/Components/DrawableGameType.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Online.Rooms; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public class DrawableGameType : CircularContainer, IHasTooltip { diff --git a/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs index edce5400d1..e50784fcbe 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs @@ -5,9 +5,9 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Online.Rooms; -using osu.Game.Screens.Multi.Lounge.Components; +using osu.Game.Screens.OnlinePlay.Lounge.Components; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { /// /// A that polls for the lounge listing. diff --git a/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs b/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs index 6997840c92..b013cbafd8 100644 --- a/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs +++ b/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs @@ -12,7 +12,7 @@ using osu.Game.Online.Rooms; using osu.Game.Screens.Select; using osuTK; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public class MatchBeatmapDetailArea : BeatmapDetailArea { diff --git a/osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs b/osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs index f07bd8c3b2..719afcdd33 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps.Drawables; using osuTK; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public class ModeTypeInfo : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Components/MultiplayerBackgroundSprite.cs b/osu.Game/Screens/OnlinePlay/Components/MultiplayerBackgroundSprite.cs index 2240e55e2f..45e2c553e7 100644 --- a/osu.Game/Screens/OnlinePlay/Components/MultiplayerBackgroundSprite.cs +++ b/osu.Game/Screens/OnlinePlay/Components/MultiplayerBackgroundSprite.cs @@ -6,7 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps.Drawables; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public class MultiplayerBackgroundSprite : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs b/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs index 7ec20c8cae..c78dfef592 100644 --- a/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osuTK; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { /// /// A header used in the multiplayer interface which shows text / details beneath a line. diff --git a/osu.Game/Screens/OnlinePlay/Components/OverlinedPlaylistHeader.cs b/osu.Game/Screens/OnlinePlay/Components/OverlinedPlaylistHeader.cs index ebebe8b660..45b822d20a 100644 --- a/osu.Game/Screens/OnlinePlay/Components/OverlinedPlaylistHeader.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OverlinedPlaylistHeader.cs @@ -3,7 +3,7 @@ using osu.Game.Online.Rooms; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public class OverlinedPlaylistHeader : OverlinedHeader { diff --git a/osu.Game/Screens/OnlinePlay/Components/ParticipantCountDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/ParticipantCountDisplay.cs index 498eeb09b3..357974adfc 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ParticipantCountDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ParticipantCountDisplay.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public class ParticipantCountDisplay : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs index 6ea4283379..5184f873f3 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs @@ -6,7 +6,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Graphics.Containers; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public class ParticipantsDisplay : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs index 7978b4eaab..b5019b4cdc 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs @@ -12,7 +12,7 @@ using osu.Game.Users; using osu.Game.Users.Drawables; using osuTK; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public class ParticipantsList : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs index 68df30965d..08f89d8ed8 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public abstract class ReadyButton : TriangleButton { diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs index 7e0c8c4ec5..2ed259e2b8 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs @@ -15,7 +15,7 @@ using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Rulesets; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public abstract class RoomManager : CompositeDrawable, IRoomManager { diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs index 1d10277d1c..b2ea3a05d6 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs @@ -8,7 +8,7 @@ using osu.Game.Online; using osu.Game.Online.API; using osu.Game.Online.Rooms; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public abstract class RoomPollingComponent : PollingComponent { diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs b/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs index 89021691f3..58cb25f30e 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics; using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.RoomStatuses; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public class RoomStatusInfo : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs index 3050765931..0eec155060 100644 --- a/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs @@ -7,7 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Online.Rooms; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { /// /// A that polls for the currently-selected room. diff --git a/osu.Game/Screens/OnlinePlay/Components/StatusColouredContainer.cs b/osu.Game/Screens/OnlinePlay/Components/StatusColouredContainer.cs index 68c14eeb15..760de354dc 100644 --- a/osu.Game/Screens/OnlinePlay/Components/StatusColouredContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Components/StatusColouredContainer.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Online.Rooms; -namespace osu.Game.Screens.Multi.Components +namespace osu.Game.Screens.OnlinePlay.Components { public class StatusColouredContainer : Container { diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs index 956d38a90e..a08d9edb34 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Online.Rooms; using osuTK; -namespace osu.Game.Screens.Multi +namespace osu.Game.Screens.OnlinePlay { public class DrawableRoomPlaylist : OsuRearrangeableListContainer { diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index a2aeae154a..e3bce4029f 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -29,7 +29,7 @@ using osu.Game.Screens.Play.HUD; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.Multi +namespace osu.Game.Screens.OnlinePlay { public class DrawableRoomPlaylistItem : OsuRearrangeableListItem { diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistWithResults.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistWithResults.cs index fa241a3c42..575f336e58 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistWithResults.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistWithResults.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; -namespace osu.Game.Screens.Multi +namespace osu.Game.Screens.OnlinePlay { public class DrawableRoomPlaylistWithResults : DrawableRoomPlaylist { diff --git a/osu.Game/Screens/OnlinePlay/Header.cs b/osu.Game/Screens/OnlinePlay/Header.cs index 637d8bb52b..bffd744fdc 100644 --- a/osu.Game/Screens/OnlinePlay/Header.cs +++ b/osu.Game/Screens/OnlinePlay/Header.cs @@ -10,13 +10,13 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Screens; using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.Multi +namespace osu.Game.Screens.OnlinePlay { public class Header : Container { diff --git a/osu.Game/Screens/OnlinePlay/IMultiplayerSubScreen.cs b/osu.Game/Screens/OnlinePlay/IMultiplayerSubScreen.cs index 31ee123f83..fc149cd2b2 100644 --- a/osu.Game/Screens/OnlinePlay/IMultiplayerSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/IMultiplayerSubScreen.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -namespace osu.Game.Screens.Multi +namespace osu.Game.Screens.OnlinePlay { public interface IMultiplayerSubScreen : IOsuScreen { diff --git a/osu.Game/Screens/OnlinePlay/IRoomManager.cs b/osu.Game/Screens/OnlinePlay/IRoomManager.cs index eee2a223a1..8ff02536f3 100644 --- a/osu.Game/Screens/OnlinePlay/IRoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/IRoomManager.cs @@ -6,7 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Online.Rooms; -namespace osu.Game.Screens.Multi +namespace osu.Game.Screens.OnlinePlay { [Cached(typeof(IRoomManager))] public interface IRoomManager diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 6e4d8b46ed..6d37a483a9 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -9,22 +9,22 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Multi.Components; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Components; using osuTK; using osuTK.Graphics; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Online.Rooms; -namespace osu.Game.Screens.Multi.Lounge.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public class DrawableRoom : OsuClickableContainer, IStateful, IFilterable, IHasContextMenu { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs index 3712cbe33e..7fc1c670ca 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; using osuTK.Graphics; -namespace osu.Game.Screens.Multi.Lounge.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public abstract class FilterControl : CompositeDrawable { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterCriteria.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterCriteria.cs index 7b04be86b1..488af5d4de 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterCriteria.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterCriteria.cs @@ -3,7 +3,7 @@ using osu.Game.Rulesets; -namespace osu.Game.Screens.Multi.Lounge.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public class FilterCriteria { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs index 4152a9a3b2..895c0e3eda 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Users.Drawables; using osuTK; -namespace osu.Game.Screens.Multi.Lounge.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public class ParticipantInfo : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs index 3c55c3c43f..a463742097 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs @@ -5,7 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; -namespace osu.Game.Screens.Multi.Lounge.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public class PlaylistsFilterControl : FilterControl { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs index e6f6ce5ed2..8552d425aa 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs @@ -6,10 +6,10 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.OnlinePlay.Components; using osuTK; -namespace osu.Game.Screens.Multi.Lounge.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public class RoomInfo : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs index dfee278e87..4b1ec9ae89 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs @@ -7,10 +7,10 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Game.Graphics; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.OnlinePlay.Components; using osuTK.Graphics; -namespace osu.Game.Screens.Multi.Lounge.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public class RoomInspector : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusFilter.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusFilter.cs index 9da938ac8b..0c8dc8832b 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusFilter.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusFilter.cs @@ -3,7 +3,7 @@ using System.ComponentModel; -namespace osu.Game.Screens.Multi.Lounge.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public enum RoomStatusFilter { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index fbd5f44a30..f70c33babe 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -13,13 +13,13 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; using osu.Framework.Threading; using osu.Game.Extensions; +using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; -using osuTK; -using osu.Game.Graphics.Cursor; using osu.Game.Online.Rooms; +using osuTK; -namespace osu.Game.Screens.Multi.Lounge.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public class RoomsContainer : CompositeDrawable, IKeyBindingHandler { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index cbab79e2ab..cc56c11d32 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -12,11 +12,11 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; using osu.Game.Overlays; -using osu.Game.Screens.Multi.Lounge.Components; -using osu.Game.Screens.Multi.Match; +using osu.Game.Screens.OnlinePlay.Lounge.Components; +using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Users; -namespace osu.Game.Screens.Multi.Lounge +namespace osu.Game.Screens.OnlinePlay.Lounge { [Cached] public abstract class LoungeSubScreen : MultiplayerSubScreen diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/Footer.cs b/osu.Game/Screens/OnlinePlay/Match/Components/Footer.cs index 7074ceca38..5c27d78d50 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/Footer.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/Footer.cs @@ -10,10 +10,10 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Online.Rooms; -using osu.Game.Screens.Multi.Playlists; +using osu.Game.Screens.OnlinePlay.Playlists; using osuTK; -namespace osu.Game.Screens.Multi.Match.Components +namespace osu.Game.Screens.OnlinePlay.Match.Components { public class Footer : CompositeDrawable { diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/GameTypePicker.cs b/osu.Game/Screens/OnlinePlay/Match/Components/GameTypePicker.cs index 23a3da6e38..cca1f84bbb 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/GameTypePicker.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/GameTypePicker.cs @@ -10,10 +10,10 @@ using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.GameTypes; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.OnlinePlay.Components; using osuTK; -namespace osu.Game.Screens.Multi.Match.Components +namespace osu.Game.Screens.OnlinePlay.Match.Components { public class GameTypePicker : DisableableTabControl { diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/Header.cs b/osu.Game/Screens/OnlinePlay/Match/Components/Header.cs index 134a0b3f2e..df0dfc6ec1 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/Header.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/Header.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Users.Drawables; using osuTK; -namespace osu.Game.Screens.Multi.Match.Components +namespace osu.Game.Screens.OnlinePlay.Match.Components { public class Header : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs index b790ad9be5..8800215c2e 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs @@ -6,7 +6,7 @@ using osu.Framework.Bindables; using osu.Game.Online.Chat; using osu.Game.Online.Rooms; -namespace osu.Game.Screens.Multi.Match.Components +namespace osu.Game.Screens.OnlinePlay.Match.Components { public class MatchChatDisplay : StandAloneChatDisplay { diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboard.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboard.cs index 8cc7b62f98..50869f42ff 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboard.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboard.cs @@ -10,7 +10,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Leaderboards; using osu.Game.Online.Rooms; -namespace osu.Game.Screens.Multi.Match.Components +namespace osu.Game.Screens.OnlinePlay.Match.Components { public class MatchLeaderboard : Leaderboard { diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboardScore.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboardScore.cs index 1fabdbb86a..e8f5b1e826 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboardScore.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboardScore.cs @@ -8,7 +8,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Leaderboards; using osu.Game.Scoring; -namespace osu.Game.Screens.Multi.Match.Components +namespace osu.Game.Screens.OnlinePlay.Match.Components { public class MatchLeaderboardScore : LeaderboardScore { diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs index 0bb56d0cdf..998ab889d6 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.UserInterface; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.Multi.Match.Components +namespace osu.Game.Screens.OnlinePlay.Match.Components { public abstract class MatchSettingsOverlay : FocusedOverlayContainer { diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs b/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs index 1d93116d07..28e8961a9a 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs @@ -5,7 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Game.Graphics.UserInterface; -namespace osu.Game.Screens.Multi.Match.Components +namespace osu.Game.Screens.OnlinePlay.Match.Components { public class PurpleTriangleButton : TriangleButton { diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/RoomAvailabilityPicker.cs b/osu.Game/Screens/OnlinePlay/Match/Components/RoomAvailabilityPicker.cs index 2292826d55..677a5be0d9 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/RoomAvailabilityPicker.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/RoomAvailabilityPicker.cs @@ -11,11 +11,11 @@ using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.Rooms; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.OnlinePlay.Components; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.Multi.Match.Components +namespace osu.Game.Screens.OnlinePlay.Match.Components { public class RoomAvailabilityPicker : DisableableTabControl { diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index b626156852..2b0035c8bc 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play; -namespace osu.Game.Screens.Multi.Match +namespace osu.Game.Screens.OnlinePlay.Match { [Cached(typeof(IPreviewTrackOwner))] public abstract class RoomSubScreen : MultiplayerSubScreen, IPreviewTrackOwner diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs index b8b3f15fca..163efd9c20 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs @@ -4,9 +4,9 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Online.Multiplayer; -using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.OnlinePlay.Match.Components; -namespace osu.Game.Screens.Multi.Multiplayer +namespace osu.Game.Screens.OnlinePlay.Multiplayer { public class CreateMultiplayerMatchButton : PurpleTriangleButton { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs index dfb6feeaf9..1718ebd83a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs @@ -9,9 +9,9 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Screens; using osu.Game.Online.API; -using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.OnlinePlay.Match.Components; -namespace osu.Game.Screens.Multi.Multiplayer.Match +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { public class BeatmapSelectionControl : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs index 145ae18817..a52f62fe00 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics; using osu.Game.Online.Rooms; using osuTK; -namespace osu.Game.Screens.Multi.Multiplayer.Match +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { public class MultiplayerMatchFooter : CompositeDrawable { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs index 0c0e580a3e..42e34c4be3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs @@ -10,14 +10,14 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Online.API; -using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Users.Drawables; using osuTK; using FontWeight = osu.Game.Graphics.FontWeight; using OsuColour = osu.Game.Graphics.OsuColour; using OsuFont = osu.Game.Graphics.OsuFont; -namespace osu.Game.Screens.Multi.Multiplayer.Match +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { public class MultiplayerMatchHeader : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 4a5b5fd181..8741b0323d 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -18,10 +18,10 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Rulesets; -using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.OnlinePlay.Match.Components; using osuTK; -namespace osu.Game.Screens.Multi.Multiplayer.Match +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { public class MultiplayerMatchSettingsOverlay : MatchSettingsOverlay { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs index cea1eeecbb..15d6ef8aff 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs @@ -15,10 +15,10 @@ using osu.Game.Graphics.Backgrounds; using osu.Game.Online.API; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.OnlinePlay.Components; using osuTK; -namespace osu.Game.Screens.Multi.Multiplayer.Match +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { public class MultiplayerReadyButton : MultiplayerRoomComposite { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs index 76aa6b9f8f..ce4918dae1 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs @@ -8,10 +8,10 @@ using osu.Game.Extensions; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; -using osu.Game.Screens.Multi.Components; -using osu.Game.Screens.Multi.Lounge; +using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Screens.OnlinePlay.Lounge; -namespace osu.Game.Screens.Multi.Multiplayer +namespace osu.Game.Screens.OnlinePlay.Multiplayer { public class Multiplayer : MultiplayerScreen { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerFilterControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerFilterControl.cs index bebad1944e..37e0fd109a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerFilterControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerFilterControl.cs @@ -1,9 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Screens.Multi.Lounge.Components; +using osu.Game.Screens.OnlinePlay.Lounge.Components; -namespace osu.Game.Screens.Multi.Multiplayer +namespace osu.Game.Screens.OnlinePlay.Multiplayer { public class MultiplayerFilterControl : FilterControl { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index ffc81efe3c..0a9a3f680f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -5,11 +5,11 @@ using osu.Framework.Allocation; using osu.Framework.Logging; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; -using osu.Game.Screens.Multi.Lounge; -using osu.Game.Screens.Multi.Lounge.Components; -using osu.Game.Screens.Multi.Match; +using osu.Game.Screens.OnlinePlay.Lounge; +using osu.Game.Screens.OnlinePlay.Lounge.Components; +using osu.Game.Screens.OnlinePlay.Match; -namespace osu.Game.Screens.Multi.Multiplayer +namespace osu.Game.Screens.OnlinePlay.Multiplayer { public class MultiplayerLoungeSubScreen : LoungeSubScreen { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index ed1321d4e2..76869300e8 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -13,7 +13,7 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Screens.Select; -namespace osu.Game.Screens.Multi.Multiplayer +namespace osu.Game.Screens.OnlinePlay.Multiplayer { public class MultiplayerMatchSongSelect : SongSelect, IMultiplayerSubScreen { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 4e371d4ed4..58314c3774 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -11,15 +11,15 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; -using osu.Game.Screens.Multi.Components; -using osu.Game.Screens.Multi.Match; -using osu.Game.Screens.Multi.Match.Components; -using osu.Game.Screens.Multi.Multiplayer.Match; -using osu.Game.Screens.Multi.Multiplayer.Participants; +using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Screens.OnlinePlay.Match; +using osu.Game.Screens.OnlinePlay.Match.Components; +using osu.Game.Screens.OnlinePlay.Multiplayer.Match; +using osu.Game.Screens.OnlinePlay.Multiplayer.Participants; using osu.Game.Users; -using ParticipantsList = osu.Game.Screens.Multi.Multiplayer.Participants.ParticipantsList; +using ParticipantsList = osu.Game.Screens.OnlinePlay.Multiplayer.Participants.ParticipantsList; -namespace osu.Game.Screens.Multi.Multiplayer +namespace osu.Game.Screens.OnlinePlay.Multiplayer { [Cached] public class MultiplayerMatchSubScreen : RoomSubScreen diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 32d95aa11f..4247e954bd 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -11,13 +11,13 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Scoring; -using osu.Game.Screens.Multi.Playlists; +using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Ranking; using osuTK; -namespace osu.Game.Screens.Multi.Multiplayer +namespace osu.Game.Screens.OnlinePlay.Multiplayer { // Todo: The "room" part of PlaylistsPlayer should be split out into an abstract player class to be inherited instead. public class MultiplayerPlayer : PlaylistsPlayer diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs index 3e39473954..e3b47b3254 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs @@ -3,9 +3,9 @@ using osu.Game.Online.Rooms; using osu.Game.Scoring; -using osu.Game.Screens.Multi.Playlists; +using osu.Game.Screens.OnlinePlay.Playlists; -namespace osu.Game.Screens.Multi.Multiplayer +namespace osu.Game.Screens.OnlinePlay.Multiplayer { public class MultiplayerResultsScreen : PlaylistsResultsScreen { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs index 6fe7c10bfb..654dafe9aa 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs @@ -5,7 +5,7 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Game.Online.Multiplayer; -namespace osu.Game.Screens.Multi.Multiplayer +namespace osu.Game.Screens.OnlinePlay.Multiplayer { public abstract class MultiplayerRoomComposite : MultiplayerComposite { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs index fdd46cdc2a..3cb263298f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs @@ -13,9 +13,9 @@ using osu.Game.Extensions; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.RoomStatuses; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.OnlinePlay.Components; -namespace osu.Game.Screens.Multi.Multiplayer +namespace osu.Game.Screens.OnlinePlay.Multiplayer { public class MultiplayerRoomManager : RoomManager { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs index 93f8a9de8b..044afa7445 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs @@ -22,7 +22,7 @@ using osu.Game.Users.Drawables; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.Multi.Multiplayer.Participants +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { public class ParticipantPanel : MultiplayerRoomComposite, IHasContextMenu { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs index 3f37274d4c..b9ac096c4a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osuTK; -namespace osu.Game.Screens.Multi.Multiplayer.Participants +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { public class ParticipantsList : MultiplayerRoomComposite { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsListHeader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsListHeader.cs index dc3ceedfd7..6c1a55a0eb 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsListHeader.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsListHeader.cs @@ -3,9 +3,9 @@ using osu.Framework.Allocation; using osu.Game.Online.Multiplayer; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.OnlinePlay.Components; -namespace osu.Game.Screens.Multi.Multiplayer.Participants +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { public class ParticipantsListHeader : OverlinedHeader { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs index 61faa0d85d..8d2879fc93 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Online.Multiplayer; using osuTK; -namespace osu.Game.Screens.Multi.Multiplayer.Participants +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { public class StateDisplay : CompositeDrawable { diff --git a/osu.Game/Screens/OnlinePlay/MultiplayerComposite.cs b/osu.Game/Screens/OnlinePlay/MultiplayerComposite.cs index fe4ca759b0..ab54178ab4 100644 --- a/osu.Game/Screens/OnlinePlay/MultiplayerComposite.cs +++ b/osu.Game/Screens/OnlinePlay/MultiplayerComposite.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Online.Rooms; using osu.Game.Users; -namespace osu.Game.Screens.Multi +namespace osu.Game.Screens.OnlinePlay { public class MultiplayerComposite : CompositeDrawable { diff --git a/osu.Game/Screens/OnlinePlay/MultiplayerScreen.cs b/osu.Game/Screens/OnlinePlay/MultiplayerScreen.cs index 983c7aeac9..3693e897ae 100644 --- a/osu.Game/Screens/OnlinePlay/MultiplayerScreen.cs +++ b/osu.Game/Screens/OnlinePlay/MultiplayerScreen.cs @@ -17,14 +17,14 @@ using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Screens.Menu; -using osu.Game.Screens.Multi.Components; -using osu.Game.Screens.Multi.Lounge; -using osu.Game.Screens.Multi.Lounge.Components; -using osu.Game.Screens.Multi.Match; +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; using osu.Game.Users; using osuTK; -namespace osu.Game.Screens.Multi +namespace osu.Game.Screens.OnlinePlay { [Cached] public abstract class MultiplayerScreen : OsuScreen diff --git a/osu.Game/Screens/OnlinePlay/MultiplayerSubScreen.cs b/osu.Game/Screens/OnlinePlay/MultiplayerSubScreen.cs index 8e46de1a95..d7fca98ebe 100644 --- a/osu.Game/Screens/OnlinePlay/MultiplayerSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/MultiplayerSubScreen.cs @@ -5,7 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Screens; -namespace osu.Game.Screens.Multi +namespace osu.Game.Screens.OnlinePlay { public abstract class MultiplayerSubScreen : OsuScreen, IMultiplayerSubScreen { diff --git a/osu.Game/Screens/OnlinePlay/MultiplayerSubScreenStack.cs b/osu.Game/Screens/OnlinePlay/MultiplayerSubScreenStack.cs index 3b0ed0dba1..335da86a65 100644 --- a/osu.Game/Screens/OnlinePlay/MultiplayerSubScreenStack.cs +++ b/osu.Game/Screens/OnlinePlay/MultiplayerSubScreenStack.cs @@ -3,7 +3,7 @@ using osu.Framework.Screens; -namespace osu.Game.Screens.Multi +namespace osu.Game.Screens.OnlinePlay { public class MultiplayerSubScreenStack : OsuScreenStack { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs index acee063115..fcb773f8be 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs @@ -2,9 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.OnlinePlay.Match.Components; -namespace osu.Game.Screens.Multi.Playlists +namespace osu.Game.Screens.OnlinePlay.Playlists { public class CreatePlaylistsRoomButton : PurpleTriangleButton { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs b/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs index da6aade942..a7fb391fbc 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs @@ -5,11 +5,11 @@ using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; -using osu.Game.Screens.Multi.Components; -using osu.Game.Screens.Multi.Lounge; -using osu.Game.Screens.Multi.Match; +using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Screens.OnlinePlay.Lounge; +using osu.Game.Screens.OnlinePlay.Match; -namespace osu.Game.Screens.Multi.Playlists +namespace osu.Game.Screens.OnlinePlay.Playlists { public class Playlists : MultiplayerScreen { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs index 513854515b..bfbff4240c 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs @@ -2,11 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Online.Rooms; -using osu.Game.Screens.Multi.Lounge; -using osu.Game.Screens.Multi.Lounge.Components; -using osu.Game.Screens.Multi.Match; +using osu.Game.Screens.OnlinePlay.Lounge; +using osu.Game.Screens.OnlinePlay.Lounge.Components; +using osu.Game.Screens.OnlinePlay.Match; -namespace osu.Game.Screens.Multi.Playlists +namespace osu.Game.Screens.OnlinePlay.Playlists { public class PlaylistsLoungeSubScreen : LoungeSubScreen { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs index f3109a33e4..557f1df657 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs @@ -16,10 +16,10 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; using osu.Game.Overlays; -using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.OnlinePlay.Match.Components; using osuTK; -namespace osu.Game.Screens.Multi.Playlists +namespace osu.Game.Screens.OnlinePlay.Playlists { public class PlaylistsMatchSettingsOverlay : MatchSettingsOverlay { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs index 25a3340ead..2c3e7a12e2 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs @@ -17,7 +17,7 @@ using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; -namespace osu.Game.Screens.Multi.Playlists +namespace osu.Game.Screens.OnlinePlay.Playlists { public class PlaylistsPlayer : Player { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsReadyButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsReadyButton.cs index 3c35e2a6f3..edee8e571a 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsReadyButton.cs @@ -6,9 +6,9 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Graphics; using osu.Game.Online.Rooms; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.OnlinePlay.Components; -namespace osu.Game.Screens.Multi.Playlists +namespace osu.Game.Screens.OnlinePlay.Playlists { public class PlaylistsReadyButton : ReadyButton { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs index 5d1d3a2724..e13c8a9f82 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs @@ -15,7 +15,7 @@ using osu.Game.Online.Rooms; using osu.Game.Scoring; using osu.Game.Screens.Ranking; -namespace osu.Game.Screens.Multi.Playlists +namespace osu.Game.Screens.OnlinePlay.Playlists { public class PlaylistsResultsScreen : ResultsScreen { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomManager.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomManager.cs index ae57eeddcc..c55d1c3e94 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomManager.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using osu.Framework.Bindables; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.OnlinePlay.Components; -namespace osu.Game.Screens.Multi.Playlists +namespace osu.Game.Screens.OnlinePlay.Playlists { public class PlaylistsRoomManager : RoomManager { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 4867268fe1..51a9ae569e 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -10,14 +10,14 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Game.Online.API; using osu.Game.Online.Rooms; -using osu.Game.Screens.Multi.Components; -using osu.Game.Screens.Multi.Match; -using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Screens.OnlinePlay.Match; +using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.Select; using osu.Game.Users; -using Footer = osu.Game.Screens.Multi.Match.Components.Footer; +using Footer = osu.Game.Screens.OnlinePlay.Match.Components.Footer; -namespace osu.Game.Screens.Multi.Playlists +namespace osu.Game.Screens.OnlinePlay.Playlists { public class PlaylistsRoomSubScreen : RoomSubScreen { diff --git a/osu.Game/Screens/Play/Spectator.cs b/osu.Game/Screens/Play/Spectator.cs index 71ce157296..28311f5113 100644 --- a/osu.Game/Screens/Play/Spectator.cs +++ b/osu.Game/Screens/Play/Spectator.cs @@ -30,7 +30,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Replays.Types; using osu.Game.Scoring; -using osu.Game.Screens.Multi.Match.Components; +using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Users; using osuTK; diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index 80fd5c2067..1b89a58b40 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -10,8 +10,8 @@ using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Online.Rooms; -using osu.Game.Screens.Multi; -using osu.Game.Screens.Multi.Components; +using osu.Game.Screens.OnlinePlay; +using osu.Game.Screens.OnlinePlay.Components; namespace osu.Game.Screens.Select { diff --git a/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs index 0e23f4d8c6..da0e39d965 100644 --- a/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs +++ b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs @@ -7,8 +7,8 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.Multiplayer; -using osu.Game.Screens.Multi; -using osu.Game.Screens.Multi.Lounge.Components; +using osu.Game.Screens.OnlinePlay; +using osu.Game.Screens.OnlinePlay.Lounge.Components; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomContainer.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomContainer.cs index 0df397d98e..ad3e2f7105 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomContainer.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomContainer.cs @@ -6,8 +6,8 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.Multiplayer; -using osu.Game.Screens.Multi; -using osu.Game.Screens.Multi.Lounge.Components; +using osu.Game.Screens.OnlinePlay; +using osu.Game.Screens.OnlinePlay.Lounge.Components; namespace osu.Game.Tests.Visual.Multiplayer { diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs index abfefd363a..5e12156f3c 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs @@ -11,8 +11,8 @@ using osu.Game.Online.API.Requests; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; -using osu.Game.Screens.Multi.Lounge.Components; -using osu.Game.Screens.Multi.Multiplayer; +using osu.Game.Screens.OnlinePlay.Lounge.Components; +using osu.Game.Screens.OnlinePlay.Multiplayer; namespace osu.Game.Tests.Visual.Multiplayer { From 4caf75850b4faf18d62827fcb4e9b1b50f4f1b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 25 Dec 2020 17:00:00 +0100 Subject: [PATCH 311/328] Rename {Multiplayer -> OnlinePlay}Screen --- .../Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs | 4 ++-- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 4 ++-- osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs | 2 +- .../OnlinePlay/{MultiplayerScreen.cs => OnlinePlayScreen.cs} | 4 ++-- osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs | 2 +- .../Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs | 5 +---- 6 files changed, 9 insertions(+), 12 deletions(-) rename osu.Game/Screens/OnlinePlay/{MultiplayerScreen.cs => OnlinePlayScreen.cs} (99%) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 6d37a483a9..f4d167a193 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -42,7 +42,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private CachedModelDependencyContainer dependencies; [Resolved(canBeNull: true)] - private MultiplayerScreen multiplayer { get; set; } + private OnlinePlayScreen parentScreen { get; set; } [Resolved] private BeatmapManager beatmaps { get; set; } @@ -242,7 +242,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { new OsuMenuItem("Create copy", MenuItemType.Standard, () => { - multiplayer?.OpenNewRoom(Room.CreateCopy()); + parentScreen?.OpenNewRoom(Room.CreateCopy()); }) }; } diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 2b0035c8bc..3a5af90824 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.OnlinePlay.Match private BeatmapManager beatmapManager { get; set; } [Resolved(canBeNull: true)] - protected MultiplayerScreen Multiplayer { get; private set; } + protected OnlinePlayScreen ParentScreen { get; private set; } private IBindable> managerUpdated; @@ -88,7 +88,7 @@ namespace osu.Game.Screens.OnlinePlay.Match protected void StartPlay(Func player) { sampleStart?.Play(); - Multiplayer?.Push(new PlayerLoader(player)); + ParentScreen?.Push(new PlayerLoader(player)); } private void selectedItemChanged() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs index ce4918dae1..76f5c74433 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.OnlinePlay.Lounge; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class Multiplayer : MultiplayerScreen + public class Multiplayer : OnlinePlayScreen { [Resolved] private StatefulMultiplayerClient client { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/MultiplayerScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs similarity index 99% rename from osu.Game/Screens/OnlinePlay/MultiplayerScreen.cs rename to osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 3693e897ae..08741ef4fe 100644 --- a/osu.Game/Screens/OnlinePlay/MultiplayerScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -27,7 +27,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay { [Cached] - public abstract class MultiplayerScreen : OsuScreen + public abstract class OnlinePlayScreen : OsuScreen { public override bool CursorVisible => (screenStack.CurrentScreen as IMultiplayerSubScreen)?.CursorVisible ?? true; @@ -67,7 +67,7 @@ namespace osu.Game.Screens.OnlinePlay private readonly Drawable header; private readonly Drawable headerBackground; - protected MultiplayerScreen() + protected OnlinePlayScreen() { Anchor = Anchor.Centre; Origin = Anchor.Centre; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs b/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs index a7fb391fbc..5b132c97fd 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs @@ -11,7 +11,7 @@ using osu.Game.Screens.OnlinePlay.Match; namespace osu.Game.Screens.OnlinePlay.Playlists { - public class Playlists : MultiplayerScreen + public class Playlists : OnlinePlayScreen { protected override void UpdatePollingRate(bool isIdle) { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 51a9ae569e..e76ca995bf 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -28,9 +28,6 @@ namespace osu.Game.Screens.OnlinePlay.Playlists [Resolved(typeof(Room), nameof(Room.RoomID))] private Bindable roomId { get; set; } - [Resolved(canBeNull: true)] - private MultiplayerScreen multiplayer { get; set; } - private MatchSettingsOverlay settingsOverlay; private MatchLeaderboard leaderboard; @@ -124,7 +121,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists RequestShowResults = item => { Debug.Assert(roomId.Value != null); - multiplayer?.Push(new PlaylistsResultsScreen(null, roomId.Value.Value, item, false)); + ParentScreen?.Push(new PlaylistsResultsScreen(null, roomId.Value.Value, item, false)); } } }, From eb0f125fefb5691e82c31a1730db1da323a0a095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 25 Dec 2020 17:00:31 +0100 Subject: [PATCH 312/328] Rename {Multiplayer -> OnlinePlay}SubScreenStack --- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 2 +- ...MultiplayerSubScreenStack.cs => OnlinePlaySubScreenStack.cs} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename osu.Game/Screens/OnlinePlay/{MultiplayerSubScreenStack.cs => OnlinePlaySubScreenStack.cs} (93%) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 08741ef4fe..66309bd47e 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -124,7 +124,7 @@ namespace osu.Game.Screens.OnlinePlay } } }, - screenStack = new MultiplayerSubScreenStack { RelativeSizeAxes = Axes.Both } + screenStack = new OnlinePlaySubScreenStack { RelativeSizeAxes = Axes.Both } } }, new Header(ScreenTitle, screenStack), diff --git a/osu.Game/Screens/OnlinePlay/MultiplayerSubScreenStack.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs similarity index 93% rename from osu.Game/Screens/OnlinePlay/MultiplayerSubScreenStack.cs rename to osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs index 335da86a65..7f2a0980c1 100644 --- a/osu.Game/Screens/OnlinePlay/MultiplayerSubScreenStack.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs @@ -5,7 +5,7 @@ using osu.Framework.Screens; namespace osu.Game.Screens.OnlinePlay { - public class MultiplayerSubScreenStack : OsuScreenStack + public class OnlinePlaySubScreenStack : OsuScreenStack { protected override void ScreenChanged(IScreen prev, IScreen next) { From e5064ee930c58a01fcf79807c14aaf83a7e420d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 25 Dec 2020 17:02:35 +0100 Subject: [PATCH 313/328] Rename {Multiplayer -> OnlinePlay}SubScreen --- osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 2 +- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 2 +- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 8 ++++---- .../{MultiplayerSubScreen.cs => OnlinePlaySubScreen.cs} | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) rename osu.Game/Screens/OnlinePlay/{MultiplayerSubScreen.cs => OnlinePlaySubScreen.cs} (94%) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index cc56c11d32..79f5dfdee1 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -19,7 +19,7 @@ using osu.Game.Users; namespace osu.Game.Screens.OnlinePlay.Lounge { [Cached] - public abstract class LoungeSubScreen : MultiplayerSubScreen + public abstract class LoungeSubScreen : OnlinePlaySubScreen { public override string Title => "Lounge"; diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 3a5af90824..2449563c73 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -18,7 +18,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Match { [Cached(typeof(IPreviewTrackOwner))] - public abstract class RoomSubScreen : MultiplayerSubScreen, IPreviewTrackOwner + public abstract class RoomSubScreen : OnlinePlaySubScreen, IPreviewTrackOwner { protected readonly Bindable SelectedItem = new Bindable(); diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 66309bd47e..60897e8b4c 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -295,13 +295,13 @@ namespace osu.Game.Screens.OnlinePlay switch (newScreen) { case LoungeSubScreen _: - header.Delay(MultiplayerSubScreen.RESUME_TRANSITION_DELAY).ResizeHeightTo(400, MultiplayerSubScreen.APPEAR_DURATION, Easing.OutQuint); - headerBackground.MoveToX(0, MultiplayerSubScreen.X_MOVE_DURATION, Easing.OutQuint); + header.Delay(OnlinePlaySubScreen.RESUME_TRANSITION_DELAY).ResizeHeightTo(400, OnlinePlaySubScreen.APPEAR_DURATION, Easing.OutQuint); + headerBackground.MoveToX(0, OnlinePlaySubScreen.X_MOVE_DURATION, Easing.OutQuint); break; case RoomSubScreen _: - header.ResizeHeightTo(135, MultiplayerSubScreen.APPEAR_DURATION, Easing.OutQuint); - headerBackground.MoveToX(-MultiplayerSubScreen.X_SHIFT, MultiplayerSubScreen.X_MOVE_DURATION, Easing.OutQuint); + header.ResizeHeightTo(135, OnlinePlaySubScreen.APPEAR_DURATION, Easing.OutQuint); + headerBackground.MoveToX(-OnlinePlaySubScreen.X_SHIFT, OnlinePlaySubScreen.X_MOVE_DURATION, Easing.OutQuint); break; } diff --git a/osu.Game/Screens/OnlinePlay/MultiplayerSubScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs similarity index 94% rename from osu.Game/Screens/OnlinePlay/MultiplayerSubScreen.cs rename to osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs index d7fca98ebe..b6dcfe6dab 100644 --- a/osu.Game/Screens/OnlinePlay/MultiplayerSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs @@ -7,7 +7,7 @@ using osu.Framework.Screens; namespace osu.Game.Screens.OnlinePlay { - public abstract class MultiplayerSubScreen : OsuScreen, IMultiplayerSubScreen + public abstract class OnlinePlaySubScreen : OsuScreen, IMultiplayerSubScreen { public override bool DisallowExternalBeatmapRulesetChanges => false; @@ -16,7 +16,7 @@ namespace osu.Game.Screens.OnlinePlay [Resolved(CanBeNull = true)] protected IRoomManager RoomManager { get; private set; } - protected MultiplayerSubScreen() + protected OnlinePlaySubScreen() { Anchor = Anchor.Centre; Origin = Anchor.Centre; From 4c43a67b68a9b0d1c574f33a4aa4e739e80397e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 25 Dec 2020 17:05:29 +0100 Subject: [PATCH 314/328] Rename I{Multiplayer -> OnlinePlay}SubScreen --- osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs | 8 ++++---- osu.Game/Screens/OnlinePlay/Header.cs | 6 +++--- .../{IMultiplayerSubScreen.cs => IOnlinePlaySubScreen.cs} | 2 +- .../OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs | 2 +- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 4 ++-- osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs | 2 +- osu.Game/Screens/Select/MatchSongSelect.cs | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) rename osu.Game/Screens/OnlinePlay/{IMultiplayerSubScreen.cs => IOnlinePlaySubScreen.cs} (82%) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs index 089de223fc..2244dcfc56 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Multiplayer OsuScreenStack screenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both }; - screenStack.Push(new TestMultiplayerSubScreen(index)); + screenStack.Push(new TestOnlinePlaySubScreen(index)); Children = new Drawable[] { @@ -26,16 +26,16 @@ namespace osu.Game.Tests.Visual.Multiplayer new Header("Multiplayer", screenStack) }; - AddStep("push multi screen", () => screenStack.CurrentScreen.Push(new TestMultiplayerSubScreen(++index))); + AddStep("push multi screen", () => screenStack.CurrentScreen.Push(new TestOnlinePlaySubScreen(++index))); } - private class TestMultiplayerSubScreen : OsuScreen, IMultiplayerSubScreen + private class TestOnlinePlaySubScreen : OsuScreen, IOnlinePlaySubScreen { private readonly int index; public string ShortTitle => $"Screen {index}"; - public TestMultiplayerSubScreen(int index) + public TestOnlinePlaySubScreen(int index) { this.index = index; } diff --git a/osu.Game/Screens/OnlinePlay/Header.cs b/osu.Game/Screens/OnlinePlay/Header.cs index bffd744fdc..bf0a53cbb6 100644 --- a/osu.Game/Screens/OnlinePlay/Header.cs +++ b/osu.Game/Screens/OnlinePlay/Header.cs @@ -61,8 +61,8 @@ namespace osu.Game.Screens.OnlinePlay breadcrumbs.Current.ValueChanged += screen => { - if (screen.NewValue is IMultiplayerSubScreen multiScreen) - title.Screen = multiScreen; + if (screen.NewValue is IOnlinePlaySubScreen onlineSubScreen) + title.Screen = onlineSubScreen; }; breadcrumbs.Current.TriggerChange(); @@ -75,7 +75,7 @@ namespace osu.Game.Screens.OnlinePlay private readonly OsuSpriteText dot; private readonly OsuSpriteText pageTitle; - public IMultiplayerSubScreen Screen + public IOnlinePlaySubScreen Screen { set => pageTitle.Text = value.ShortTitle.Titleize(); } diff --git a/osu.Game/Screens/OnlinePlay/IMultiplayerSubScreen.cs b/osu.Game/Screens/OnlinePlay/IOnlinePlaySubScreen.cs similarity index 82% rename from osu.Game/Screens/OnlinePlay/IMultiplayerSubScreen.cs rename to osu.Game/Screens/OnlinePlay/IOnlinePlaySubScreen.cs index fc149cd2b2..a4762292a9 100644 --- a/osu.Game/Screens/OnlinePlay/IMultiplayerSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/IOnlinePlaySubScreen.cs @@ -3,7 +3,7 @@ namespace osu.Game.Screens.OnlinePlay { - public interface IMultiplayerSubScreen : IOsuScreen + public interface IOnlinePlaySubScreen : IOsuScreen { string Title { get; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 76869300e8..0842574f54 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -15,7 +15,7 @@ using osu.Game.Screens.Select; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class MultiplayerMatchSongSelect : SongSelect, IMultiplayerSubScreen + public class MultiplayerMatchSongSelect : SongSelect, IOnlinePlaySubScreen { public string ShortTitle => "song selection"; diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 60897e8b4c..9ba2e41d12 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.OnlinePlay [Cached] public abstract class OnlinePlayScreen : OsuScreen { - public override bool CursorVisible => (screenStack.CurrentScreen as IMultiplayerSubScreen)?.CursorVisible ?? true; + public override bool CursorVisible => (screenStack.CurrentScreen as IOnlinePlaySubScreen)?.CursorVisible ?? true; // this is required due to PlayerLoader eventually being pushed to the main stack // while leases may be taken out by a subscreen. @@ -245,7 +245,7 @@ namespace osu.Game.Screens.OnlinePlay public override bool OnBackButton() { - if ((screenStack.CurrentScreen as IMultiplayerSubScreen)?.OnBackButton() == true) + if ((screenStack.CurrentScreen as IOnlinePlaySubScreen)?.OnBackButton() == true) return true; if (screenStack.CurrentScreen != null && !(screenStack.CurrentScreen is LoungeSubScreen)) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs index b6dcfe6dab..e1bd889088 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs @@ -7,7 +7,7 @@ using osu.Framework.Screens; namespace osu.Game.Screens.OnlinePlay { - public abstract class OnlinePlaySubScreen : OsuScreen, IMultiplayerSubScreen + public abstract class OnlinePlaySubScreen : OsuScreen, IOnlinePlaySubScreen { public override bool DisallowExternalBeatmapRulesetChanges => false; diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index 1b89a58b40..0948a4d19a 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -15,7 +15,7 @@ using osu.Game.Screens.OnlinePlay.Components; namespace osu.Game.Screens.Select { - public class MatchSongSelect : SongSelect, IMultiplayerSubScreen + public class MatchSongSelect : SongSelect, IOnlinePlaySubScreen { public Action Selected; From ed4b8482b60d1133753296aebf78afd4fec95c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 25 Dec 2020 17:12:33 +0100 Subject: [PATCH 315/328] Rename {Multiplayer -> OnlinePlay}Composite --- osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs | 2 +- osu.Game/Screens/OnlinePlay/Components/BeatmapTypeInfo.cs | 2 +- osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs | 2 +- osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs | 2 +- .../Screens/OnlinePlay/Components/ParticipantCountDisplay.cs | 2 +- osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs | 2 +- osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs | 2 +- osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs | 2 +- osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs | 2 +- .../Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs | 2 +- osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs | 2 +- osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs | 2 +- osu.Game/Screens/OnlinePlay/Match/Components/Header.cs | 2 +- .../Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs | 2 +- .../OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs | 2 +- .../OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs | 2 +- .../Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs | 2 +- .../Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs | 2 +- .../{MultiplayerComposite.cs => OnlinePlayComposite.cs} | 2 +- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 2 +- .../OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) rename osu.Game/Screens/OnlinePlay/{MultiplayerComposite.cs => OnlinePlayComposite.cs} (96%) diff --git a/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs b/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs index bc355d18a9..acb82360b3 100644 --- a/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs +++ b/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs @@ -12,7 +12,7 @@ using osu.Game.Online.Chat; namespace osu.Game.Screens.OnlinePlay.Components { - public class BeatmapTitle : MultiplayerComposite + public class BeatmapTitle : OnlinePlayComposite { private readonly LinkFlowContainer textFlow; diff --git a/osu.Game/Screens/OnlinePlay/Components/BeatmapTypeInfo.cs b/osu.Game/Screens/OnlinePlay/Components/BeatmapTypeInfo.cs index 434d7b75ed..3aa13458a4 100644 --- a/osu.Game/Screens/OnlinePlay/Components/BeatmapTypeInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Components/BeatmapTypeInfo.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Components { - public class BeatmapTypeInfo : MultiplayerComposite + public class BeatmapTypeInfo : OnlinePlayComposite { private LinkFlowContainer beatmapAuthor; diff --git a/osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs b/osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs index 719afcdd33..03b27b605c 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Components { - public class ModeTypeInfo : MultiplayerComposite + public class ModeTypeInfo : OnlinePlayComposite { private const float height = 30; private const float transition_duration = 100; diff --git a/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs b/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs index c78dfef592..08a0a3405e 100644 --- a/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.OnlinePlay.Components /// /// A header used in the multiplayer interface which shows text / details beneath a line. /// - public class OverlinedHeader : MultiplayerComposite + public class OverlinedHeader : OnlinePlayComposite { private bool showLine = true; diff --git a/osu.Game/Screens/OnlinePlay/Components/ParticipantCountDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/ParticipantCountDisplay.cs index 357974adfc..53821da8fd 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ParticipantCountDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ParticipantCountDisplay.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.OnlinePlay.Components { - public class ParticipantCountDisplay : MultiplayerComposite + public class ParticipantCountDisplay : OnlinePlayComposite { private const float text_size = 30; private const float transition_duration = 100; diff --git a/osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs index 5184f873f3..c36d1a2e76 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs @@ -8,7 +8,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Screens.OnlinePlay.Components { - public class ParticipantsDisplay : MultiplayerComposite + public class ParticipantsDisplay : OnlinePlayComposite { public Bindable Details = new Bindable(); diff --git a/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs index b5019b4cdc..9aceb39a27 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Components { - public class ParticipantsList : MultiplayerComposite + public class ParticipantsList : OnlinePlayComposite { public const float TILE_SIZE = 35; diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs b/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs index 58cb25f30e..bcc256bcff 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs @@ -13,7 +13,7 @@ using osu.Game.Online.Rooms.RoomStatuses; namespace osu.Game.Screens.OnlinePlay.Components { - public class RoomStatusInfo : MultiplayerComposite + public class RoomStatusInfo : OnlinePlayComposite { public RoomStatusInfo() { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index f4d167a193..0a7198a7fa 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -155,7 +155,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Width = cover_width, Masking = true, Margin = new MarginPadding { Left = stripWidth }, - Child = new MultiplayerBackgroundSprite(BeatmapSetCoverType.List) { RelativeSizeAxes = Axes.Both } + Child = new OnlinePlayBackgroundSprite(BeatmapSetCoverType.List) { RelativeSizeAxes = Axes.Both } }, new Container { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs index 895c0e3eda..0d5ce65d5a 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { - public class ParticipantInfo : MultiplayerComposite + public class ParticipantInfo : OnlinePlayComposite { public ParticipantInfo() { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs index 8552d425aa..0a17702f2a 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { - public class RoomInfo : MultiplayerComposite + public class RoomInfo : OnlinePlayComposite { private readonly List statusElements = new List(); private readonly OsuTextFlowContainer roomName; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs index 4b1ec9ae89..c28354c753 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { - public class RoomInspector : MultiplayerComposite + public class RoomInspector : OnlinePlayComposite { private const float transition_duration = 100; diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/Header.cs b/osu.Game/Screens/OnlinePlay/Match/Components/Header.cs index df0dfc6ec1..a2d11c54c1 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/Header.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/Header.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public class Header : MultiplayerComposite + public class Header : OnlinePlayComposite { public const float HEIGHT = 50; diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs index 998ab889d6..ea3951fc3b 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components protected const float TRANSITION_DURATION = 350; protected const float FIELD_PADDING = 45; - protected MultiplayerComposite Settings { get; set; } + protected OnlinePlayComposite Settings { get; set; } [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs index 1718ebd83a..f17e04d4d4 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.OnlinePlay.Match.Components; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { - public class BeatmapSelectionControl : MultiplayerComposite + public class BeatmapSelectionControl : OnlinePlayComposite { [Resolved] private MultiplayerMatchSubScreen matchSubScreen { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs index 42e34c4be3..bb351d06d3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs @@ -19,7 +19,7 @@ using OsuFont = osu.Game.Graphics.OsuFont; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { - public class MultiplayerMatchHeader : MultiplayerComposite + public class MultiplayerMatchHeader : OnlinePlayComposite { public const float HEIGHT = 50; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 8741b0323d..ae03d384f6 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match }; } - protected class MatchSettings : MultiplayerComposite + protected class MatchSettings : OnlinePlayComposite { private const float disabled_alpha = 0.2f; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs index 654dafe9aa..ac608a13d4 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs @@ -7,7 +7,7 @@ using osu.Game.Online.Multiplayer; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public abstract class MultiplayerRoomComposite : MultiplayerComposite + public abstract class MultiplayerRoomComposite : OnlinePlayComposite { [CanBeNull] protected MultiplayerRoom Room => Client.Room; diff --git a/osu.Game/Screens/OnlinePlay/MultiplayerComposite.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs similarity index 96% rename from osu.Game/Screens/OnlinePlay/MultiplayerComposite.cs rename to osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs index ab54178ab4..64792a32f3 100644 --- a/osu.Game/Screens/OnlinePlay/MultiplayerComposite.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs @@ -10,7 +10,7 @@ using osu.Game.Users; namespace osu.Game.Screens.OnlinePlay { - public class MultiplayerComposite : CompositeDrawable + public class OnlinePlayComposite : CompositeDrawable { [Resolved(typeof(Room))] protected Bindable RoomID { get; private set; } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 9ba2e41d12..4074dd1573 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -338,7 +338,7 @@ namespace osu.Game.Screens.OnlinePlay } } - private class HeaderBackgroundSprite : MultiplayerBackgroundSprite + private class HeaderBackgroundSprite : OnlinePlayBackgroundSprite { protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BackgroundSprite { RelativeSizeAxes = Axes.Both }; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs index 557f1df657..6b92526f35 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists }; } - protected class MatchSettings : MultiplayerComposite + protected class MatchSettings : OnlinePlayComposite { private const float disabled_alpha = 0.2f; From 2e4b1b95c283418818bd72f40a0885778112728f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 25 Dec 2020 17:12:46 +0100 Subject: [PATCH 316/328] Rename {Multiplayer -> OnlinePlay}BackgroundSprite --- ...layerBackgroundSprite.cs => OnlinePlayBackgroundSprite.cs} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename osu.Game/Screens/OnlinePlay/Components/{MultiplayerBackgroundSprite.cs => OnlinePlayBackgroundSprite.cs} (85%) diff --git a/osu.Game/Screens/OnlinePlay/Components/MultiplayerBackgroundSprite.cs b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs similarity index 85% rename from osu.Game/Screens/OnlinePlay/Components/MultiplayerBackgroundSprite.cs rename to osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs index 45e2c553e7..d8dfac496d 100644 --- a/osu.Game/Screens/OnlinePlay/Components/MultiplayerBackgroundSprite.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs @@ -8,12 +8,12 @@ using osu.Game.Beatmaps.Drawables; namespace osu.Game.Screens.OnlinePlay.Components { - public class MultiplayerBackgroundSprite : MultiplayerComposite + public class OnlinePlayBackgroundSprite : OnlinePlayComposite { private readonly BeatmapSetCoverType beatmapSetCoverType; private UpdateableBeatmapBackgroundSprite sprite; - public MultiplayerBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover) + public OnlinePlayBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover) { this.beatmapSetCoverType = beatmapSetCoverType; } From e0198c36aeebfddea645a9386a66a7439568d3d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 26 Dec 2020 09:48:13 +0900 Subject: [PATCH 317/328] Fix user population happening in single file --- osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs index e422e982ae..6d253d5992 100644 --- a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs @@ -108,8 +108,7 @@ namespace osu.Game.Online.Multiplayer Debug.Assert(Room != null); - foreach (var user in Room.Users) - await PopulateUser(user); + await Task.WhenAll(Room.Users.Select(PopulateUser)); updateLocalRoomSettings(Room.Settings); } From 5ce5b6cec06403b2bbbeea6864f97cf0ebca0bc0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 26 Dec 2020 10:25:16 +0900 Subject: [PATCH 318/328] Fix non-safe thread access to room users on room join --- .../Multiplayer/StatefulMultiplayerClient.cs | 44 ++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs index 6d253d5992..ec0967df75 100644 --- a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs @@ -4,8 +4,10 @@ #nullable enable using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Threading; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -108,7 +110,9 @@ namespace osu.Game.Online.Multiplayer Debug.Assert(Room != null); - await Task.WhenAll(Room.Users.Select(PopulateUser)); + var users = getRoomUsers(); + + await Task.WhenAll(users.Select(PopulateUser)); updateLocalRoomSettings(Room.Settings); } @@ -122,13 +126,16 @@ namespace osu.Game.Online.Multiplayer public virtual Task LeaveRoom() { - if (Room == null) - return Task.CompletedTask; + Schedule(() => + { + if (Room == null) + return; - apiRoom = null; - Room = null; + apiRoom = null; + Room = null; - Schedule(() => RoomChanged?.Invoke()); + RoomChanged?.Invoke(); + }); return Task.CompletedTask; } @@ -360,6 +367,31 @@ namespace osu.Game.Online.Multiplayer /// The to populate. protected async Task PopulateUser(MultiplayerRoomUser multiplayerUser) => multiplayerUser.User ??= await userLookupCache.GetUserAsync(multiplayerUser.UserID); + /// + /// Retrieve a copy of users currently in the joined in a thread-safe manner. + /// This should be used whenever accessing users from outside of an Update thread context (ie. when not calling ). + /// + /// A copy of users in the current room, or null if unavailable. + private List? getRoomUsers() + { + List? users = null; + + ManualResetEventSlim resetEvent = new ManualResetEventSlim(); + + // at some point we probably want to replace all these schedule calls with Room.LockForUpdate. + // for now, as this would require quite some consideration due to the number of accesses to the room instance, + // let's just to a schedule for the non-scheduled usages instead. + Schedule(() => + { + users = Room?.Users.ToList(); + resetEvent.Set(); + }); + + resetEvent.Wait(100); + + return users; + } + /// /// Updates the local room settings with the given . /// From f9900720d58e9b5e61f48f3a83643b8f2c11b88c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 26 Dec 2020 10:48:55 +0900 Subject: [PATCH 319/328] Rename OnRoomChanged to OnRoomUpdated to avoid confusion --- .../Multiplayer/StatefulMultiplayerClient.cs | 16 ++++++++-------- .../Multiplayer/Match/MultiplayerReadyButton.cs | 4 ++-- .../Multiplayer/MultiplayerRoomComposite.cs | 11 +++++++---- .../Multiplayer/Participants/ParticipantPanel.cs | 4 ++-- .../Multiplayer/Participants/ParticipantsList.cs | 4 ++-- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs index ec0967df75..8839b79c13 100644 --- a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs @@ -33,7 +33,7 @@ namespace osu.Game.Online.Multiplayer /// /// Invoked when any change occurs to the multiplayer room. /// - public event Action? RoomChanged; + public event Action? RoomUpdated; /// /// Invoked when the multiplayer server requests the current beatmap to be loaded into play. @@ -134,7 +134,7 @@ namespace osu.Game.Online.Multiplayer apiRoom = null; Room = null; - RoomChanged?.Invoke(); + RoomUpdated?.Invoke(); }); return Task.CompletedTask; @@ -214,7 +214,7 @@ namespace osu.Game.Online.Multiplayer break; } - RoomChanged?.Invoke(); + RoomUpdated?.Invoke(); }); return Task.CompletedTask; @@ -238,7 +238,7 @@ namespace osu.Game.Online.Multiplayer Room.Users.Add(user); - RoomChanged?.Invoke(); + RoomUpdated?.Invoke(); }); } @@ -255,7 +255,7 @@ namespace osu.Game.Online.Multiplayer Room.Users.Remove(user); PlayingUsers.Remove(user.UserID); - RoomChanged?.Invoke(); + RoomUpdated?.Invoke(); }); return Task.CompletedTask; @@ -278,7 +278,7 @@ namespace osu.Game.Online.Multiplayer Room.Host = user; apiRoom.Host.Value = user?.User; - RoomChanged?.Invoke(); + RoomUpdated?.Invoke(); }); return Task.CompletedTask; @@ -305,7 +305,7 @@ namespace osu.Game.Online.Multiplayer if (state != MultiplayerUserState.Playing) PlayingUsers.Remove(userId); - RoomChanged?.Invoke(); + RoomUpdated?.Invoke(); }); return Task.CompletedTask; @@ -419,7 +419,7 @@ namespace osu.Game.Online.Multiplayer // In-order for the client to not display an outdated beatmap, the playlist is forcefully cleared here. apiRoom.Playlist.Clear(); - RoomChanged?.Invoke(); + RoomUpdated?.Invoke(); var req = new GetBeatmapSetRequest(settings.BeatmapID, BeatmapSetLookupType.BeatmapId); req.Success += res => updatePlaylist(settings, res); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs index 15d6ef8aff..975a2cf023 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs @@ -56,9 +56,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match sampleReadyCount = audio.Samples.Get(@"SongSelect/select-difficulty"); } - protected override void OnRoomChanged() + protected override void OnRoomUpdated() { - base.OnRoomChanged(); + base.OnRoomUpdated(); localUser = Room?.Users.Single(u => u.User?.Id == api.LocalUser.Value.Id); button.Enabled.Value = Client.Room?.State == MultiplayerRoomState.Open; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs index ac608a13d4..8030107ad8 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs @@ -19,18 +19,21 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { base.LoadComplete(); - Client.RoomChanged += OnRoomChanged; - OnRoomChanged(); + Client.RoomUpdated += OnRoomUpdated; + OnRoomUpdated(); } - protected virtual void OnRoomChanged() + /// + /// Invoked when any change occurs to the multiplayer room. + /// + protected virtual void OnRoomUpdated() { } protected override void Dispose(bool isDisposing) { if (Client != null) - Client.RoomChanged -= OnRoomChanged; + Client.RoomUpdated -= OnRoomUpdated; base.Dispose(isDisposing); } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs index 044afa7445..de3069b2f6 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs @@ -135,9 +135,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants }; } - protected override void OnRoomChanged() + protected override void OnRoomUpdated() { - base.OnRoomChanged(); + base.OnRoomUpdated(); if (Room == null) return; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs index b9ac096c4a..3759e45f18 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs @@ -36,9 +36,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants }; } - protected override void OnRoomChanged() + protected override void OnRoomUpdated() { - base.OnRoomChanged(); + base.OnRoomUpdated(); if (Room == null) panels.Clear(); From fe1bbb1cac671b65dca154784955314db434adbc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 26 Dec 2020 10:49:22 +0900 Subject: [PATCH 320/328] Don't fail if the local user is not present in room users when updating ready button state --- .../OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs index 975a2cf023..281e92404c 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs @@ -60,7 +60,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { base.OnRoomUpdated(); - localUser = Room?.Users.Single(u => u.User?.Id == api.LocalUser.Value.Id); + // this method is called on leaving the room, so the local user may not exist in the room any more. + localUser = Room?.Users.SingleOrDefault(u => u.User?.Id == api.LocalUser.Value.Id); + button.Enabled.Value = Client.Room?.State == MultiplayerRoomState.Open; updateState(); } From e7339d6959ba8c94fd76ec2e5f2d0e9da0f5074d Mon Sep 17 00:00:00 2001 From: Neuheit <38368299+Neuheit@users.noreply.github.com> Date: Fri, 25 Dec 2020 21:07:33 -0500 Subject: [PATCH 321/328] fix(osu.Game): Ensure Category property is copied in Room. --- osu.Game/Online/Rooms/Room.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index 67f874cdc4..bb21971afa 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -130,6 +130,7 @@ namespace osu.Game.Online.Rooms { RoomID.Value = other.RoomID.Value; Name.Value = other.Name.Value; + Category.Value = other.Category.Value; if (other.Host.Value != null && Host.Value?.Id != other.Host.Value.Id) Host.Value = other.Host.Value; From dae27fefe433cefe70b1eb69be65e62b6c1f689b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 26 Dec 2020 10:59:14 +0100 Subject: [PATCH 322/328] Run user list copy inline if possible `getRoomUsers()` was not safe to call from the update thread, as evidenced by the test failures. This was due to the fact that the added reset event could never actually be set from within the method, as the wait was blocking the scheduled set from ever proceeding. Resolve by allowing the scheduled copy & set to run inline if on the update thread already. --- osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs index ec0967df75..06ed4b4a6c 100644 --- a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs @@ -380,12 +380,12 @@ namespace osu.Game.Online.Multiplayer // at some point we probably want to replace all these schedule calls with Room.LockForUpdate. // for now, as this would require quite some consideration due to the number of accesses to the room instance, - // let's just to a schedule for the non-scheduled usages instead. - Schedule(() => + // let's just add a manual schedule for the non-scheduled usages instead. + Scheduler.Add(() => { users = Room?.Users.ToList(); resetEvent.Set(); - }); + }, false); resetEvent.Wait(100); From 04d54c40dbdc65f08975f1ca065ddd4ca1b67d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 26 Dec 2020 11:58:25 +0100 Subject: [PATCH 323/328] Allow all StatefulMultiplayerClient schedules to run inline Fixes test failures due to not allowing to do so, therefore inverting execution order in some cases - for example, calling JoinRoom(room); LeaveRoom(); on the update thread would invert execution order due to the first being unscheduled but the second being scheduled. --- .../Multiplayer/StatefulMultiplayerClient.cs | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs index 06ed4b4a6c..98b53e723c 100644 --- a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs @@ -126,7 +126,7 @@ namespace osu.Game.Online.Multiplayer public virtual Task LeaveRoom() { - Schedule(() => + Scheduler.Add(() => { if (Room == null) return; @@ -135,7 +135,7 @@ namespace osu.Game.Online.Multiplayer Room = null; RoomChanged?.Invoke(); - }); + }, false); return Task.CompletedTask; } @@ -190,7 +190,7 @@ namespace osu.Game.Online.Multiplayer if (Room == null) return Task.CompletedTask; - Schedule(() => + Scheduler.Add(() => { if (Room == null) return; @@ -215,7 +215,7 @@ namespace osu.Game.Online.Multiplayer } RoomChanged?.Invoke(); - }); + }, false); return Task.CompletedTask; } @@ -227,7 +227,7 @@ namespace osu.Game.Online.Multiplayer await PopulateUser(user); - Schedule(() => + Scheduler.Add(() => { if (Room == null) return; @@ -239,7 +239,7 @@ namespace osu.Game.Online.Multiplayer Room.Users.Add(user); RoomChanged?.Invoke(); - }); + }, false); } Task IMultiplayerClient.UserLeft(MultiplayerRoomUser user) @@ -247,7 +247,7 @@ namespace osu.Game.Online.Multiplayer if (Room == null) return Task.CompletedTask; - Schedule(() => + Scheduler.Add(() => { if (Room == null) return; @@ -256,7 +256,7 @@ namespace osu.Game.Online.Multiplayer PlayingUsers.Remove(user.UserID); RoomChanged?.Invoke(); - }); + }, false); return Task.CompletedTask; } @@ -266,7 +266,7 @@ namespace osu.Game.Online.Multiplayer if (Room == null) return Task.CompletedTask; - Schedule(() => + Scheduler.Add(() => { if (Room == null) return; @@ -279,7 +279,7 @@ namespace osu.Game.Online.Multiplayer apiRoom.Host.Value = user?.User; RoomChanged?.Invoke(); - }); + }, false); return Task.CompletedTask; } @@ -295,7 +295,7 @@ namespace osu.Game.Online.Multiplayer if (Room == null) return Task.CompletedTask; - Schedule(() => + Scheduler.Add(() => { if (Room == null) return; @@ -306,7 +306,7 @@ namespace osu.Game.Online.Multiplayer PlayingUsers.Remove(userId); RoomChanged?.Invoke(); - }); + }, false); return Task.CompletedTask; } @@ -316,13 +316,13 @@ namespace osu.Game.Online.Multiplayer if (Room == null) return Task.CompletedTask; - Schedule(() => + Scheduler.Add(() => { if (Room == null) return; LoadRequested?.Invoke(); - }); + }, false); return Task.CompletedTask; } @@ -332,7 +332,7 @@ namespace osu.Game.Online.Multiplayer if (Room == null) return Task.CompletedTask; - Schedule(() => + Scheduler.Add(() => { if (Room == null) return; @@ -340,7 +340,7 @@ namespace osu.Game.Online.Multiplayer PlayingUsers.AddRange(Room.Users.Where(u => u.State == MultiplayerUserState.Playing).Select(u => u.UserID)); MatchStarted?.Invoke(); - }); + }, false); return Task.CompletedTask; } @@ -350,13 +350,13 @@ namespace osu.Game.Online.Multiplayer if (Room == null) return Task.CompletedTask; - Schedule(() => + Scheduler.Add(() => { if (Room == null) return; ResultsReady?.Invoke(); - }); + }, false); return Task.CompletedTask; } @@ -404,7 +404,7 @@ namespace osu.Game.Online.Multiplayer if (Room == null) return; - Schedule(() => + Scheduler.Add(() => { if (Room == null) return; @@ -425,7 +425,7 @@ namespace osu.Game.Online.Multiplayer req.Success += res => updatePlaylist(settings, res); api.Queue(req); - }); + }, false); } private void updatePlaylist(MultiplayerRoomSettings settings, APIBeatmapSet onlineSet) From b9d725ab4928c0385b63da2d5ed5496b0faee21a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 26 Dec 2020 20:13:28 +0900 Subject: [PATCH 324/328] Don't copy spotlight category --- osu.Game/Online/Rooms/Room.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index bb21971afa..763ba25d52 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -130,7 +130,9 @@ namespace osu.Game.Online.Rooms { RoomID.Value = other.RoomID.Value; Name.Value = other.Name.Value; - Category.Value = other.Category.Value; + + if (other.Category.Value != RoomCategory.Spotlight) + Category.Value = other.Category.Value; if (other.Host.Value != null && Host.Value?.Id != other.Host.Value.Id) Host.Value = other.Host.Value; From 0b42b4b95598dcb067a4d06b4b734a0e468204c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 26 Dec 2020 13:54:10 +0100 Subject: [PATCH 325/328] Rename {Drawable -> Clickable}Avatar --- osu.Game/Online/Leaderboards/LeaderboardScore.cs | 4 ++-- osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs | 4 ++-- .../Drawables/{DrawableAvatar.cs => ClickableAvatar.cs} | 7 ++++--- osu.Game/Users/Drawables/UpdateableAvatar.cs | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) rename osu.Game/Users/Drawables/{DrawableAvatar.cs => ClickableAvatar.cs} (90%) diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index d8207aa8f4..5608002513 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -78,7 +78,7 @@ namespace osu.Game.Online.Leaderboards statisticsLabels = GetStatistics(score).Select(s => new ScoreComponentLabel(s)).ToList(); - DrawableAvatar innerAvatar; + ClickableAvatar innerAvatar; Children = new Drawable[] { @@ -115,7 +115,7 @@ namespace osu.Game.Online.Leaderboards Children = new[] { avatar = new DelayedLoadWrapper( - innerAvatar = new DrawableAvatar(user) + innerAvatar = new ClickableAvatar(user) { RelativeSizeAxes = Axes.Both, CornerRadius = corner_radius, diff --git a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs index 5b428a3825..00f46b0035 100644 --- a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs +++ b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Chat.Tabs if (value.Type != ChannelType.PM) throw new ArgumentException("Argument value needs to have the targettype user!"); - DrawableAvatar avatar; + ClickableAvatar avatar; AddRange(new Drawable[] { @@ -48,7 +48,7 @@ namespace osu.Game.Overlays.Chat.Tabs Anchor = Anchor.Centre, Origin = Anchor.Centre, Masking = true, - Child = new DelayedLoadWrapper(avatar = new DrawableAvatar(value.Users.First()) + Child = new DelayedLoadWrapper(avatar = new ClickableAvatar(value.Users.First()) { RelativeSizeAxes = Axes.Both, OpenOnClick = { Value = false }, diff --git a/osu.Game/Users/Drawables/DrawableAvatar.cs b/osu.Game/Users/Drawables/ClickableAvatar.cs similarity index 90% rename from osu.Game/Users/Drawables/DrawableAvatar.cs rename to osu.Game/Users/Drawables/ClickableAvatar.cs index 42d2dbb1c6..61af2d8e27 100644 --- a/osu.Game/Users/Drawables/DrawableAvatar.cs +++ b/osu.Game/Users/Drawables/ClickableAvatar.cs @@ -14,7 +14,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Users.Drawables { [LongRunningLoad] - public class DrawableAvatar : Container + public class ClickableAvatar : Container { /// /// Whether to open the user's profile when clicked. @@ -27,10 +27,11 @@ namespace osu.Game.Users.Drawables private OsuGame game { get; set; } /// - /// An avatar for specified user. + /// A clickable avatar for specified user, with UI sounds included. + /// If is true, clicking will open the user's profile. /// /// The user. A null value will get a placeholder avatar. - public DrawableAvatar(User user = null) + public ClickableAvatar(User user = null) { this.user = user; } diff --git a/osu.Game/Users/Drawables/UpdateableAvatar.cs b/osu.Game/Users/Drawables/UpdateableAvatar.cs index 171462f3fc..4772207edf 100644 --- a/osu.Game/Users/Drawables/UpdateableAvatar.cs +++ b/osu.Game/Users/Drawables/UpdateableAvatar.cs @@ -65,7 +65,7 @@ namespace osu.Game.Users.Drawables if (user == null && !ShowGuestOnNull) return null; - var avatar = new DrawableAvatar(user) + var avatar = new ClickableAvatar(user) { RelativeSizeAxes = Axes.Both, }; From e8f96b24013827b5c173159b960a0443d18ee87c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 26 Dec 2020 14:02:53 +0100 Subject: [PATCH 326/328] Bring back DrawableAvatar as a simple sprite --- osu.Game/Users/Drawables/ClickableAvatar.cs | 22 ++---------- osu.Game/Users/Drawables/DrawableAvatar.cs | 39 +++++++++++++++++++++ 2 files changed, 42 insertions(+), 19 deletions(-) create mode 100644 osu.Game/Users/Drawables/DrawableAvatar.cs diff --git a/osu.Game/Users/Drawables/ClickableAvatar.cs b/osu.Game/Users/Drawables/ClickableAvatar.cs index 61af2d8e27..0fca9c7c9b 100644 --- a/osu.Game/Users/Drawables/ClickableAvatar.cs +++ b/osu.Game/Users/Drawables/ClickableAvatar.cs @@ -1,19 +1,16 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Events; using osu.Game.Graphics.Containers; namespace osu.Game.Users.Drawables { - [LongRunningLoad] public class ClickableAvatar : Container { /// @@ -27,7 +24,7 @@ namespace osu.Game.Users.Drawables private OsuGame game { get; set; } /// - /// A clickable avatar for specified user, with UI sounds included. + /// A clickable avatar for the specified user, with UI sounds included. /// If is true, clicking will open the user's profile. /// /// The user. A null value will get a placeholder avatar. @@ -39,28 +36,15 @@ namespace osu.Game.Users.Drawables [BackgroundDependencyLoader] private void load(LargeTextureStore textures) { - if (textures == null) - throw new ArgumentNullException(nameof(textures)); - - Texture texture = null; - if (user != null && user.Id > 1) texture = textures.Get($@"https://a.ppy.sh/{user.Id}"); - texture ??= textures.Get(@"Online/avatar-guest"); - ClickableArea clickableArea; Add(clickableArea = new ClickableArea { RelativeSizeAxes = Axes.Both, - Child = new Sprite - { - RelativeSizeAxes = Axes.Both, - Texture = texture, - FillMode = FillMode.Fit, - Anchor = Anchor.Centre, - Origin = Anchor.Centre - }, Action = openProfile }); + LoadComponentAsync(new DrawableAvatar(user), clickableArea.Add); + clickableArea.Enabled.BindTo(OpenOnClick); } diff --git a/osu.Game/Users/Drawables/DrawableAvatar.cs b/osu.Game/Users/Drawables/DrawableAvatar.cs new file mode 100644 index 0000000000..81f6ad52d9 --- /dev/null +++ b/osu.Game/Users/Drawables/DrawableAvatar.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; + +namespace osu.Game.Users.Drawables +{ + [LongRunningLoad] + public class DrawableAvatar : Sprite + { + private readonly User user; + + /// + /// A simple, non-interactable avatar sprite for the specified user. + /// + /// The user. A null value will get a placeholder avatar. + public DrawableAvatar(User user = null) + { + this.user = user; + + RelativeSizeAxes = Axes.Both; + FillMode = FillMode.Fit; + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + } + + [BackgroundDependencyLoader] + private void load(LargeTextureStore textures) + { + if (user != null && user.Id > 1) + Texture = textures.Get($@"https://a.ppy.sh/{user.Id}"); + + Texture ??= textures.Get(@"Online/avatar-guest"); + } + } +} From 8ec7970b6ab10a028d4066571255587e95baf29f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 26 Dec 2020 14:06:09 +0100 Subject: [PATCH 327/328] Move load-complete fade specification inside --- osu.Game/Users/Drawables/DrawableAvatar.cs | 6 ++++++ osu.Game/Users/Drawables/UpdateableAvatar.cs | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Users/Drawables/DrawableAvatar.cs b/osu.Game/Users/Drawables/DrawableAvatar.cs index 81f6ad52d9..3dae3afe3f 100644 --- a/osu.Game/Users/Drawables/DrawableAvatar.cs +++ b/osu.Game/Users/Drawables/DrawableAvatar.cs @@ -35,5 +35,11 @@ namespace osu.Game.Users.Drawables Texture ??= textures.Get(@"Online/avatar-guest"); } + + protected override void LoadComplete() + { + base.LoadComplete(); + this.FadeInFromZero(300, Easing.OutQuint); + } } } diff --git a/osu.Game/Users/Drawables/UpdateableAvatar.cs b/osu.Game/Users/Drawables/UpdateableAvatar.cs index 4772207edf..927e48cb56 100644 --- a/osu.Game/Users/Drawables/UpdateableAvatar.cs +++ b/osu.Game/Users/Drawables/UpdateableAvatar.cs @@ -70,7 +70,6 @@ namespace osu.Game.Users.Drawables RelativeSizeAxes = Axes.Both, }; - avatar.OnLoadComplete += d => d.FadeInFromZero(300, Easing.OutQuint); avatar.OpenOnClick.BindTo(OpenOnClick); return avatar; From 15948de2f0cbe1c64abf0b6a4a9fba813c047a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 26 Dec 2020 14:06:23 +0100 Subject: [PATCH 328/328] Fix gameplay leaderboard avatars being clickable --- .../Screens/Play/HUD/GameplayLeaderboardScore.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 58281debf1..51b19a8d45 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -78,6 +78,8 @@ namespace osu.Game.Screens.Play.HUD [BackgroundDependencyLoader] private void load(OsuColour colours) { + Container avatarContainer; + InternalChildren = new Drawable[] { mainFillContainer = new Container @@ -152,7 +154,7 @@ namespace osu.Game.Screens.Play.HUD Spacing = new Vector2(4f, 0f), Children = new Drawable[] { - new CircularContainer + avatarContainer = new CircularContainer { Masking = true, Anchor = Anchor.CentreLeft, @@ -166,11 +168,7 @@ namespace osu.Game.Screens.Play.HUD Alpha = 0.3f, RelativeSizeAxes = Axes.Both, Colour = colours.Gray4, - }, - new UpdateableAvatar(User) - { - RelativeSizeAxes = Axes.Both, - }, + } } }, usernameText = new OsuSpriteText @@ -227,6 +225,8 @@ namespace osu.Game.Screens.Play.HUD } }; + LoadComponentAsync(new DrawableAvatar(User), avatarContainer.Add); + TotalScore.BindValueChanged(v => scoreText.Text = v.NewValue.ToString("N0"), true); Accuracy.BindValueChanged(v => accuracyText.Text = v.NewValue.FormatAccuracy(), true); Combo.BindValueChanged(v => comboText.Text = $"{v.NewValue}x", true);