From 9542e3e24ada33a0d63030584b7c109f940a1ab3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Dec 2018 17:59:28 +0900 Subject: [PATCH 1/8] Add Updateable beatmap sprite --- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- .../UpdateableBeatmapBackgroundSprite.cs | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index c179821a7c..58c0819075 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -59,7 +59,7 @@ namespace osu.Game.Beatmaps /// /// A default representation of a WorkingBeatmap to use when no beatmap is available. /// - public WorkingBeatmap DefaultBeatmap { private get; set; } + public WorkingBeatmap DefaultBeatmap { get; set; } public override string[] HandledExtensions => new[] { ".osz" }; diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs new file mode 100644 index 0000000000..1808325466 --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs @@ -0,0 +1,47 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Beatmaps.Drawables +{ + /// + /// Display a baetmap background from a local source, but fallback to online source if not available. + /// + public class UpdateableBeatmapBackgroundSprite : ModelBackedDrawable + { + public readonly IBindable Beatmap = new Bindable(); + + [Resolved] + private BeatmapManager beatmaps { get; set; } + + public UpdateableBeatmapBackgroundSprite() + { + Beatmap.BindValueChanged(b => Schedule(() => Model = b)); + } + + protected override Drawable CreateDrawable(BeatmapInfo model) + { + Drawable drawable; + + var localBeatmap = beatmaps.GetWorkingBeatmap(model); + + if (localBeatmap == beatmaps.DefaultBeatmap && model?.BeatmapSet?.OnlineInfo != null) + drawable = new BeatmapSetCover(model.BeatmapSet); + else + drawable = new BeatmapBackgroundSprite(localBeatmap); + + drawable.RelativeSizeAxes = Axes.Both; + drawable.Anchor = Anchor.Centre; + drawable.Origin = Anchor.Centre; + drawable.FillMode = FillMode.Fill; + + return drawable; + } + + protected override double FadeDuration => 400; + } +} From 96c9e5f209bf6e9b8077997cd902a1a3987eb18d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 25 Dec 2018 18:34:45 +0900 Subject: [PATCH 2/8] Make DefaultBeatmap readonly --- osu.Game.Tests/Visual/TestCasePlaySongSelect.cs | 5 +---- osu.Game/Beatmaps/BeatmapManager.cs | 15 +++++++++------ osu.Game/OsuGameBase.cs | 9 ++++----- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index d87a8d0056..29060ceb12 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -87,10 +87,7 @@ namespace osu.Game.Tests.Visual usage.Migrate(); Dependencies.Cache(rulesets = new RulesetStore(factory)); - Dependencies.Cache(manager = new BeatmapManager(LocalStorage, factory, rulesets, null, null) - { - DefaultBeatmap = defaultBeatmap = Beatmap.Default - }); + Dependencies.Cache(manager = new BeatmapManager(LocalStorage, factory, rulesets, null, null, null, defaultBeatmap = Beatmap.Default)); Beatmap.SetDefault(); } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 58c0819075..73fd5da22c 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -59,7 +59,7 @@ namespace osu.Game.Beatmaps /// /// A default representation of a WorkingBeatmap to use when no beatmap is available. /// - public WorkingBeatmap DefaultBeatmap { get; set; } + public readonly WorkingBeatmap DefaultBeatmap; public override string[] HandledExtensions => new[] { ".osz" }; @@ -77,16 +77,19 @@ namespace osu.Game.Beatmaps private readonly List currentDownloads = new List(); - public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, APIAccess api, AudioManager audioManager, IIpcHost importHost = null) + public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, APIAccess api, AudioManager audioManager, IIpcHost importHost = null, + WorkingBeatmap defaultBeatmap = null) : base(storage, contextFactory, new BeatmapStore(contextFactory), importHost) { - beatmaps = (BeatmapStore)ModelStore; - beatmaps.BeatmapHidden += b => BeatmapHidden?.Invoke(b); - beatmaps.BeatmapRestored += b => BeatmapRestored?.Invoke(b); - this.rulesets = rulesets; this.api = api; this.audioManager = audioManager; + + DefaultBeatmap = defaultBeatmap; + + beatmaps = (BeatmapStore)ModelStore; + beatmaps.BeatmapHidden += b => BeatmapHidden?.Invoke(b); + beatmaps.BeatmapRestored += b => BeatmapRestored?.Invoke(b); } protected override void Populate(BeatmapSetInfo beatmapSet, ArchiveReader archive) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 0f1819d55b..002ef6ec32 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -153,9 +153,12 @@ namespace osu.Game dependencies.Cache(API); dependencies.CacheAs(API); + var defaultBeatmap = new DummyWorkingBeatmap(this); + beatmap = new OsuBindableBeatmap(defaultBeatmap, Audio); + dependencies.Cache(RulesetStore = new RulesetStore(contextFactory)); dependencies.Cache(FileStore = new FileStore(contextFactory, Host.Storage)); - dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory, RulesetStore, API, Audio, Host)); + dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap)); dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, BeatmapManager, Host.Storage, contextFactory, Host)); dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore)); dependencies.Cache(SettingsStore = new SettingsStore(contextFactory)); @@ -166,10 +169,6 @@ namespace osu.Game fileImporters.Add(ScoreManager); fileImporters.Add(SkinManager); - var defaultBeatmap = new DummyWorkingBeatmap(this); - beatmap = new OsuBindableBeatmap(defaultBeatmap, Audio); - BeatmapManager.DefaultBeatmap = defaultBeatmap; - // tracks play so loud our samples can't keep up. // this adds a global reduction of track volume for the time being. Audio.Track.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(0.8)); From c45c34d400003910f02638d359889222cc7fc3a3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Dec 2018 19:17:21 +0900 Subject: [PATCH 3/8] Make beatmap importing possible elsewhere in tests --- .../Beatmaps/IO/ImportBeatmapTest.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 26167cb24a..c8fd531fcc 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -29,7 +29,7 @@ namespace osu.Game.Tests.Beatmaps.IO { try { - loadOszIntoOsu(loadOsu(host)); + LoadOszIntoOsu(loadOsu(host)); } finally { @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Beatmaps.IO { var osu = loadOsu(host); - var imported = loadOszIntoOsu(osu); + var imported = LoadOszIntoOsu(osu); deleteBeatmapSet(imported, osu); } @@ -69,8 +69,8 @@ namespace osu.Game.Tests.Beatmaps.IO { var osu = loadOsu(host); - var imported = loadOszIntoOsu(osu); - var importedSecondTime = loadOszIntoOsu(osu); + var imported = LoadOszIntoOsu(osu); + var importedSecondTime = LoadOszIntoOsu(osu); // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash. Assert.IsTrue(imported.ID == importedSecondTime.ID); @@ -105,7 +105,7 @@ namespace osu.Game.Tests.Beatmaps.IO manager.ItemAdded += (_, __, ___) => fireCount++; manager.ItemRemoved += _ => fireCount++; - var imported = loadOszIntoOsu(osu); + var imported = LoadOszIntoOsu(osu); Assert.AreEqual(0, fireCount -= 1); @@ -160,12 +160,12 @@ namespace osu.Game.Tests.Beatmaps.IO var osu = loadOsu(host); var manager = osu.Dependencies.Get(); - var imported = loadOszIntoOsu(osu); + var imported = LoadOszIntoOsu(osu); imported.Hash += "-changed"; manager.Update(imported); - var importedSecondTime = loadOszIntoOsu(osu); + var importedSecondTime = LoadOszIntoOsu(osu); Assert.IsTrue(imported.ID != importedSecondTime.ID); Assert.IsTrue(imported.Beatmaps.First().ID < importedSecondTime.Beatmaps.First().ID); @@ -191,11 +191,11 @@ namespace osu.Game.Tests.Beatmaps.IO { var osu = loadOsu(host); - var imported = loadOszIntoOsu(osu); + var imported = LoadOszIntoOsu(osu); deleteBeatmapSet(imported, osu); - var importedSecondTime = loadOszIntoOsu(osu); + var importedSecondTime = LoadOszIntoOsu(osu); // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash. Assert.IsTrue(imported.ID == importedSecondTime.ID); @@ -262,7 +262,7 @@ namespace osu.Game.Tests.Beatmaps.IO } } - private string createTemporaryBeatmap() + private static string createTemporaryBeatmap() { var temp = Path.GetTempFileName() + ".osz"; File.Copy(TEST_OSZ_PATH, temp, true); @@ -270,7 +270,7 @@ namespace osu.Game.Tests.Beatmaps.IO return temp; } - private BeatmapSetInfo loadOszIntoOsu(OsuGameBase osu, string path = null) + public static BeatmapSetInfo LoadOszIntoOsu(OsuGameBase osu, string path = null) { var temp = path ?? createTemporaryBeatmap(); @@ -305,7 +305,7 @@ namespace osu.Game.Tests.Beatmaps.IO return osu; } - private void ensureLoaded(OsuGameBase osu, int timeout = 60000) + private static void ensureLoaded(OsuGameBase osu, int timeout = 60000) { IEnumerable resultSets = null; var store = osu.Dependencies.Get(); @@ -343,7 +343,7 @@ namespace osu.Game.Tests.Beatmaps.IO Assert.IsTrue(beatmap?.HitObjects.Any() == true); } - private void waitForOrAssert(Func result, string failureMessage, int timeout = 60000) + private static void waitForOrAssert(Func result, string failureMessage, int timeout = 60000) { Task task = Task.Run(() => { From c902c1587a8248d78ba6d6a13af78fc9674f4e9e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Dec 2018 19:17:32 +0900 Subject: [PATCH 4/8] Add tests and modify fallback logic --- ...stCaseUpdateableBeatmapBackgroundSprite.cs | 51 +++++++++++++++++++ .../UpdateableBeatmapBackgroundSprite.cs | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs diff --git a/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs b/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs new file mode 100644 index 0000000000..24701fccbc --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs @@ -0,0 +1,51 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Rulesets; +using osu.Game.Tests.Beatmaps.IO; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseUpdateableBeatmapBackgroundSprite : OsuTestCase + { + private UpdateableBeatmapBackgroundSprite backgroundSprite; + + [Resolved] + private BeatmapManager beatmaps { get; set; } + + [BackgroundDependencyLoader] + private void load(OsuGameBase osu, APIAccess api, RulesetStore rulesets) + { + Bindable beatmapBindable = new Bindable(); + + var imported = ImportBeatmapTest.LoadOszIntoOsu(osu); + + Child = backgroundSprite = new UpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both }; + + backgroundSprite.Beatmap.BindTo(beatmapBindable); + + var req = new GetBeatmapSetRequest(1); + api.Queue(req); + + AddStep("null", () => beatmapBindable.Value = null); + + AddStep("imported", () => beatmapBindable.Value = imported.Beatmaps.First()); + + if (api.IsLoggedIn) + AddUntilStep(() => req.Result != null, "wait for api response"); + + AddStep("online", () => beatmapBindable.Value = new BeatmapInfo + { + BeatmapSet = req.Result?.ToBeatmapSet(rulesets) + }); + } + } +} diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs index 1808325466..fd00576d21 100644 --- a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs +++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs @@ -29,7 +29,7 @@ namespace osu.Game.Beatmaps.Drawables var localBeatmap = beatmaps.GetWorkingBeatmap(model); - if (localBeatmap == beatmaps.DefaultBeatmap && model?.BeatmapSet?.OnlineInfo != null) + if (localBeatmap.BeatmapInfo.ID == 0 && model?.BeatmapSet?.OnlineInfo != null) drawable = new BeatmapSetCover(model.BeatmapSet); else drawable = new BeatmapBackgroundSprite(localBeatmap); From aeb2186539bb1cd62971b02ff9839482a9955e3e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 26 Dec 2018 16:06:39 +0900 Subject: [PATCH 5/8] Fix api get user request never failing --- osu.Game/Online/API/APIAccess.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 8038c1fc1f..10b4e73419 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -145,7 +145,8 @@ namespace osu.Game.Online.API if (!handleRequest(userReq)) { - Thread.Sleep(500); + if (State == APIState.Connecting) + State = APIState.Failing; continue; } From 63847890d15e64be77da4e4ecf9329711d8e392f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Dec 2018 18:05:12 +0900 Subject: [PATCH 6/8] Add better messaging when connecting or failing --- .../Graphics/Containers/LinkFlowContainer.cs | 21 ++++++++++++-- .../Sections/General/LoginSettings.cs | 29 +++++++++++-------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 54a2ea47f9..74315d2522 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using System.Collections.Generic; +using osu.Framework.Graphics; using osu.Framework.Logging; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; @@ -61,11 +62,25 @@ namespace osu.Game.Graphics.Containers } public void AddLink(string text, string url, LinkAction linkType = LinkAction.External, string linkArgument = null, string tooltipText = null, Action creationParameters = null) + => createLink(AddText(text, creationParameters), text, url, linkType, linkArgument, tooltipText); + + public void AddLink(string text, Action action, string tooltipText = null, Action creationParameters = null) + => createLink(AddText(text, creationParameters), text, tooltipText: tooltipText, action: action); + + public void AddLink(IEnumerable text, string url, LinkAction linkType = LinkAction.External, string linkArgument = null, string tooltipText = null) { - AddInternal(new DrawableLinkCompiler(AddText(text, creationParameters).ToList()) + foreach (var t in text) + AddArbitraryDrawable(t); + + createLink(text, null, url, linkType, linkArgument, tooltipText); + } + + private void createLink(IEnumerable drawables, string text, string url = null, LinkAction linkType = LinkAction.External, string linkArgument = null, string tooltipText = null, Action action = null) + { + AddInternal(new DrawableLinkCompiler(drawables.OfType().ToList()) { TooltipText = tooltipText ?? (url != text ? url : string.Empty), - Action = () => + Action = action ?? (() => { switch (linkType) { @@ -104,7 +119,7 @@ namespace osu.Game.Graphics.Containers default: throw new NotImplementedException($"This {nameof(LinkAction)} ({linkType.ToString()}) is missing an associated action."); } - }, + }), }); } } diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index 0cb6d2d1aa..163eced103 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -17,6 +17,7 @@ using osu.Game.Graphics; using osuTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Input.Events; +using osu.Game.Graphics.Containers; using RectangleF = osu.Framework.Graphics.Primitives.RectangleF; using Container = osu.Framework.Graphics.Containers.Container; @@ -86,25 +87,29 @@ namespace osu.Game.Overlays.Settings.Sections.General }; break; case APIState.Failing: - Children = new Drawable[] - { - new OsuSpriteText - { - Text = "Connection failing :(", - }, - }; - break; case APIState.Connecting: + LinkFlowContainer linkFlow; + Children = new Drawable[] { - new OsuSpriteText + new LoadingAnimation { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "Connecting...", + State = Visibility.Visible, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + linkFlow = new LinkFlowContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + TextAnchor = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, + Text = state == APIState.Failing ? "Connection is failing, will attempt to reconnect... " : "Attempting to connect... ", Margin = new MarginPadding { Top = 10, Bottom = 10 }, }, }; + + linkFlow.AddLink("cancel", api.Logout, string.Empty); break; case APIState.Online: Children = new Drawable[] From edfb027ff274fc50c67c3d9204bfd3ce4067abf3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Dec 2018 18:49:33 +0900 Subject: [PATCH 7/8] Update framework --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 18addaefb6..103c7c20d6 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + From ae47eb61caf9ef810cd0d2d56f12164d78f45c05 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Dec 2018 20:42:47 +0900 Subject: [PATCH 8/8] Fix test not working when not logged in --- .../TestCaseUpdateableBeatmapBackgroundSprite.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs b/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs index 24701fccbc..bc449f645b 100644 --- a/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs +++ b/osu.Game.Tests/Visual/TestCaseUpdateableBeatmapBackgroundSprite.cs @@ -40,12 +40,18 @@ namespace osu.Game.Tests.Visual AddStep("imported", () => beatmapBindable.Value = imported.Beatmaps.First()); if (api.IsLoggedIn) + { AddUntilStep(() => req.Result != null, "wait for api response"); - AddStep("online", () => beatmapBindable.Value = new BeatmapInfo + AddStep("online", () => beatmapBindable.Value = new BeatmapInfo + { + BeatmapSet = req.Result?.ToBeatmapSet(rulesets) + }); + } + else { - BeatmapSet = req.Result?.ToBeatmapSet(rulesets) - }); + AddStep("online (login first)", () => { }); + } } } }