diff --git a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs index daa3f61de3..8dd00756f2 100644 --- a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs +++ b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs @@ -43,10 +43,13 @@ namespace osu.Game.Rulesets.Catch.Replays float positionChange = Math.Abs(lastPosition - h.X); double timeAvailable = h.StartTime - lastTime; - //So we can either make it there without a dash or not. - double speedRequired = positionChange / timeAvailable; + // So we can either make it there without a dash or not. + // If positionChange is 0, we don't need to move, so speedRequired should also be 0 (could be NaN if timeAvailable is 0 too) + // The case where positionChange > 0 and timeAvailable == 0 results in PositiveInfinity which provides expected beheaviour. + double speedRequired = positionChange == 0 ? 0 : positionChange / timeAvailable; - bool dashRequired = speedRequired > movement_speed && h.StartTime != 0; + bool dashRequired = speedRequired > movement_speed; + bool impossibleJump = speedRequired > movement_speed * 2; // todo: get correct catcher size, based on difficulty CS. const float catcher_width_half = CatcherArea.CATCHER_SIZE / CatchPlayfield.BASE_WIDTH * 0.3f * 0.5f; @@ -59,9 +62,8 @@ namespace osu.Game.Rulesets.Catch.Replays return; } - if (h is Banana) + if (impossibleJump) { - // auto bananas unrealistically warp to catch 100% combo. Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X)); } else if (h.HyperDash) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs new file mode 100644 index 0000000000..237fee1594 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs @@ -0,0 +1,109 @@ +// 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 NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Track; +using osu.Framework.MathUtils; +using osu.Framework.Timing; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.UI; +using osu.Game.Screens.Play; +using osuTK; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneGameplayRewinding : PlayerTestScene + { + private RulesetExposingPlayer player => (RulesetExposingPlayer)Player; + + [Resolved] + private AudioManager audioManager { get; set; } + + public TestSceneGameplayRewinding() + : base(new OsuRuleset()) + { + } + + private Track track; + + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) + { + var working = new ClockBackedTestWorkingBeatmap(beatmap, new FramedClock(new ManualClock { Rate = 1 }), audioManager); + track = working.Track; + return working; + } + + [Test] + public void TestNoJudgementsOnRewind() + { + AddUntilStep("wait for track to start running", () => track.IsRunning); + addSeekStep(3000); + AddAssert("all judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged)); + AddStep("clear results", () => player.AppliedResults.Clear()); + addSeekStep(0); + AddAssert("none judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => !h.Judged)); + AddAssert("no results triggered", () => player.AppliedResults.Count == 0); + } + + private void addSeekStep(double time) + { + AddStep($"seek to {time}", () => track.Seek(time)); + + // Allow a few frames of lenience + AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, player.DrawableRuleset.FrameStableClock.CurrentTime, 100)); + } + + protected override Player CreatePlayer(Ruleset ruleset) + { + Mods.Value = Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray(); + return new RulesetExposingPlayer(); + } + + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) + { + var beatmap = new Beatmap + { + BeatmapInfo = { BaseDifficulty = { ApproachRate = 9 } }, + }; + + for (int i = 0; i < 15; i++) + { + beatmap.HitObjects.Add(new HitCircle + { + Position = new Vector2(256, 192), + StartTime = 1000 + 30 * i + }); + } + + return beatmap; + } + + private class RulesetExposingPlayer : Player + { + public readonly List AppliedResults = new List(); + + public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer; + + public new DrawableRuleset DrawableRuleset => base.DrawableRuleset; + + public RulesetExposingPlayer() + : base(false, false) + { + } + + [BackgroundDependencyLoader] + private void load() + { + ScoreProcessor.NewJudgement += r => AppliedResults.Add(r); + } + } + } +} diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index 5910da7b88..fb2d4efc68 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -41,6 +41,9 @@ namespace osu.Game.Tests.Visual.Online typeof(SuccessRate), }; + private RulesetInfo maniaRuleset; + private RulesetInfo taikoRuleset; + public TestSceneBeatmapSetOverlay() { Add(overlay = new BeatmapSetOverlay()); @@ -49,13 +52,25 @@ namespace osu.Game.Tests.Visual.Online [BackgroundDependencyLoader] private void load(RulesetStore rulesets) { - var mania = rulesets.GetRuleset(3); - var taiko = rulesets.GetRuleset(1); + maniaRuleset = rulesets.GetRuleset(3); + taikoRuleset = rulesets.GetRuleset(1); + } + [Test] + public void TestLoading() + { AddStep(@"show loading", () => overlay.ShowBeatmapSet(null)); + } + [Test] + public void TestOnline() + { AddStep(@"show online", () => overlay.FetchAndShowBeatmapSet(55)); + } + [Test] + public void TestLocalBeatmaps() + { AddStep(@"show first", () => { overlay.ShowBeatmapSet(new BeatmapSetInfo @@ -87,13 +102,14 @@ namespace osu.Game.Tests.Visual.Online Cover = @"https://assets.ppy.sh/beatmaps/415886/covers/cover.jpg?1465651778", }, }, + Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }, Beatmaps = new List { new BeatmapInfo { StarDifficulty = 1.36, Version = @"BASIC", - Ruleset = mania, + Ruleset = maniaRuleset, BaseDifficulty = new BeatmapDifficulty { CircleSize = 4, @@ -111,16 +127,15 @@ namespace osu.Game.Tests.Visual.Online }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, }, new BeatmapInfo { StarDifficulty = 2.22, Version = @"NOVICE", - Ruleset = mania, + Ruleset = maniaRuleset, BaseDifficulty = new BeatmapDifficulty { CircleSize = 4, @@ -138,16 +153,15 @@ namespace osu.Game.Tests.Visual.Online }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, }, new BeatmapInfo { StarDifficulty = 3.49, Version = @"ADVANCED", - Ruleset = mania, + Ruleset = maniaRuleset, BaseDifficulty = new BeatmapDifficulty { CircleSize = 4, @@ -165,16 +179,15 @@ namespace osu.Game.Tests.Visual.Online }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, }, new BeatmapInfo { StarDifficulty = 4.24, Version = @"EXHAUST", - Ruleset = mania, + Ruleset = maniaRuleset, BaseDifficulty = new BeatmapDifficulty { CircleSize = 4, @@ -192,16 +205,15 @@ namespace osu.Game.Tests.Visual.Online }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, }, new BeatmapInfo { StarDifficulty = 5.26, Version = @"GRAVITY", - Ruleset = mania, + Ruleset = maniaRuleset, BaseDifficulty = new BeatmapDifficulty { CircleSize = 4, @@ -219,9 +231,8 @@ namespace osu.Game.Tests.Visual.Online }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, }, }, @@ -258,13 +269,14 @@ namespace osu.Game.Tests.Visual.Online Cover = @"https://assets.ppy.sh/beatmaps/625493/covers/cover.jpg?1499167472", }, }, + Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }, Beatmaps = new List { new BeatmapInfo { StarDifficulty = 1.40, Version = @"yzrin's Kantan", - Ruleset = taiko, + Ruleset = taikoRuleset, BaseDifficulty = new BeatmapDifficulty { CircleSize = 2, @@ -282,16 +294,15 @@ namespace osu.Game.Tests.Visual.Online }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, }, new BeatmapInfo { StarDifficulty = 2.23, Version = @"Futsuu", - Ruleset = taiko, + Ruleset = taikoRuleset, BaseDifficulty = new BeatmapDifficulty { CircleSize = 2, @@ -309,16 +320,15 @@ namespace osu.Game.Tests.Visual.Online }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, }, new BeatmapInfo { StarDifficulty = 3.19, Version = @"Muzukashii", - Ruleset = taiko, + Ruleset = taikoRuleset, BaseDifficulty = new BeatmapDifficulty { CircleSize = 2, @@ -336,16 +346,15 @@ namespace osu.Game.Tests.Visual.Online }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, }, new BeatmapInfo { StarDifficulty = 3.97, Version = @"Charlotte's Oni", - Ruleset = taiko, + Ruleset = taikoRuleset, BaseDifficulty = new BeatmapDifficulty { CircleSize = 5, @@ -363,16 +372,15 @@ namespace osu.Game.Tests.Visual.Online }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, }, new BeatmapInfo { StarDifficulty = 5.08, Version = @"Labyrinth Oni", - Ruleset = taiko, + Ruleset = taikoRuleset, BaseDifficulty = new BeatmapDifficulty { CircleSize = 5, @@ -390,16 +398,24 @@ namespace osu.Game.Tests.Visual.Online }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, }, }, }); }); + } + [Test] + public void TestHide() + { AddStep(@"hide", overlay.Hide); + } + + [Test] + public void TestShowWithNoReload() + { AddStep(@"show without reload", overlay.Show); } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs new file mode 100644 index 0000000000..2a45e68c0a --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.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; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.MathUtils; +using osu.Game.Beatmaps; +using osu.Game.Overlays.BeatmapSet; +using osu.Game.Screens.Select.Details; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneBeatmapSetOverlayDetails : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(Details) + }; + + private RatingsExposingDetails details; + + [SetUp] + public void Setup() => Schedule(() => + { + Child = details = new RatingsExposingDetails + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }; + }); + + [Test] + public void TestMetrics() + { + var firstSet = createSet(); + var secondSet = createSet(); + + AddStep("set first set", () => details.BeatmapSet = firstSet); + AddAssert("ratings set", () => details.Ratings.Metrics == firstSet.Metrics); + + AddStep("set second set", () => details.BeatmapSet = secondSet); + AddAssert("ratings set", () => details.Ratings.Metrics == secondSet.Metrics); + + BeatmapSetInfo createSet() => new BeatmapSetInfo + { + Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).Select(_ => RNG.Next(10)).ToArray() }, + Beatmaps = new List + { + new BeatmapInfo + { + Metrics = new BeatmapMetrics + { + Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(), + } + } + } + }; + } + + private class RatingsExposingDetails : Details + { + public new UserRatings Ratings => base.Ratings; + } + } +} diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs new file mode 100644 index 0000000000..05f5c117e4 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs @@ -0,0 +1,82 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.MathUtils; +using osu.Game.Beatmaps; +using osu.Game.Overlays.BeatmapSet; +using osu.Game.Screens.Select.Details; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneBeatmapSetOverlaySuccessRate : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(Details) + }; + + private GraphExposingSuccessRate successRate; + + [SetUp] + public void Setup() => Schedule(() => + { + Child = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(275, 220), + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Gray, + }, + successRate = new GraphExposingSuccessRate + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(275, 220), + Padding = new MarginPadding(20) + } + } + }; + }); + + [Test] + public void TestMetrics() + { + var firstBeatmap = createBeatmap(); + var secondBeatmap = createBeatmap(); + + AddStep("set first set", () => successRate.Beatmap = firstBeatmap); + AddAssert("ratings set", () => successRate.Graph.Metrics == firstBeatmap.Metrics); + + AddStep("set second set", () => successRate.Beatmap = secondBeatmap); + AddAssert("ratings set", () => successRate.Graph.Metrics == secondBeatmap.Metrics); + + BeatmapInfo createBeatmap() => new BeatmapInfo + { + Metrics = new BeatmapMetrics + { + Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(), + } + }; + } + + private class GraphExposingSuccessRate : SuccessRate + { + public new FailRetryGraph Graph => base.Graph; + } + } +} diff --git a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs index 455807649a..883f0c5e3f 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs @@ -5,9 +5,9 @@ using System; using System.Collections.Generic; using NUnit.Framework; 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.Overlays.Profile.Sections; using osu.Game.Overlays.Profile.Sections.Historical; using osu.Game.Users; @@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual.Online Colour = OsuColour.Gray(0.2f) }); - Add(new ScrollContainer + Add(new OsuScrollContainer { RelativeSizeAxes = Axes.Both, Child = section = new HistoricalSection(), diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs index d60e723102..f022425bf6 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs @@ -9,6 +9,7 @@ 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.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Profile.Sections; @@ -36,7 +37,7 @@ namespace osu.Game.Tests.Visual.Online RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(0.2f) }, - new ScrollContainer + new OsuScrollContainer { RelativeSizeAxes = Axes.Both, Child = new FillFlowContainer diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs b/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs index 70118b5ebd..9f0a8c769a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs @@ -8,6 +8,7 @@ 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.Overlays.Profile.Sections; using osu.Game.Overlays.Profile.Sections.Ranks; using osu.Game.Users; @@ -33,7 +34,7 @@ namespace osu.Game.Tests.Visual.Online RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(0.2f) }, - new ScrollContainer + new OsuScrollContainer { RelativeSizeAxes = Axes.Both, Child = ranks = new RanksSection(), diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs index 8395ece457..7b97a27732 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs @@ -32,6 +32,10 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("all metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null) { + BeatmapSetInfo = + { + Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() } + }, BeatmapInfo = { Version = "All Metrics", @@ -50,9 +54,8 @@ namespace osu.Game.Tests.Visual.SongSelect StarDifficulty = 5.3f, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, } } @@ -60,6 +63,10 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("all except source", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null) { + BeatmapSetInfo = + { + Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() } + }, BeatmapInfo = { Version = "All Metrics", @@ -77,15 +84,18 @@ namespace osu.Game.Tests.Visual.SongSelect StarDifficulty = 5.3f, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, } }); AddStep("ratings", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null) { + BeatmapSetInfo = + { + Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() } + }, BeatmapInfo = { Version = "Only Ratings", @@ -101,11 +111,7 @@ namespace osu.Game.Tests.Visual.SongSelect OverallDifficulty = 6, ApproachRate = 6, }, - StarDifficulty = 4.8f, - Metrics = new BeatmapMetrics - { - Ratings = Enumerable.Range(0, 11), - }, + StarDifficulty = 4.8f } }); @@ -129,8 +135,8 @@ namespace osu.Game.Tests.Visual.SongSelect StarDifficulty = 2.91f, Metrics = new BeatmapMetrics { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, } }); diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs index acbbd4e18b..acf037198f 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs @@ -1,28 +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.ComponentModel; using System.Linq; +using NUnit.Framework; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.SongSelect { - [Description("PlaySongSelect beatmap details")] + [System.ComponentModel.Description("PlaySongSelect beatmap details")] public class TestSceneBeatmapDetails : OsuTestScene { - public TestSceneBeatmapDetails() + private BeatmapDetails details; + + [SetUp] + public void Setup() => Schedule(() => { - BeatmapDetails details; - Add(details = new BeatmapDetails + Child = details = new BeatmapDetails { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(150), - }); + }; + }); + [Test] + public void TestAllMetrics() + { AddStep("all metrics", () => details.Beatmap = new BeatmapInfo { + BeatmapSet = new BeatmapSetInfo + { + Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() } + }, Version = "All Metrics", Metadata = new BeatmapMetadata { @@ -39,14 +49,21 @@ namespace osu.Game.Tests.Visual.SongSelect StarDifficulty = 5.3f, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, }); + } + [Test] + public void TestAllMetricsExceptSource() + { AddStep("all except source", () => details.Beatmap = new BeatmapInfo { + BeatmapSet = new BeatmapSetInfo + { + Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() } + }, Version = "All Metrics", Metadata = new BeatmapMetadata { @@ -62,14 +79,21 @@ namespace osu.Game.Tests.Visual.SongSelect StarDifficulty = 5.3f, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, }); + } + [Test] + public void TestOnlyRatings() + { AddStep("ratings", () => details.Beatmap = new BeatmapInfo { + BeatmapSet = new BeatmapSetInfo + { + Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() } + }, Version = "Only Ratings", Metadata = new BeatmapMetadata { @@ -84,12 +108,12 @@ namespace osu.Game.Tests.Visual.SongSelect ApproachRate = 6, }, StarDifficulty = 4.8f, - Metrics = new BeatmapMetrics - { - Ratings = Enumerable.Range(0, 11), - }, }); + } + [Test] + public void TestOnlyFailsAndRetries() + { AddStep("fails retries", () => details.Beatmap = new BeatmapInfo { Version = "Only Retries and Fails", @@ -108,11 +132,15 @@ namespace osu.Game.Tests.Visual.SongSelect StarDifficulty = 2.91f, Metrics = new BeatmapMetrics { - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, }); + } + [Test] + public void TestNoMetrics() + { AddStep("no metrics", () => details.Beatmap = new BeatmapInfo { Version = "No Metrics", @@ -129,10 +157,22 @@ namespace osu.Game.Tests.Visual.SongSelect ApproachRate = 6.5f, }, StarDifficulty = 1.97f, - Metrics = new BeatmapMetrics(), }); + } + [Test] + public void TestNullBeatmap() + { AddStep("null beatmap", () => details.Beatmap = null); } + + [Test] + public void TestOnlineMetrics() + { + AddStep("online ratings/retries/fails", () => details.Beatmap = new BeatmapInfo + { + OnlineBeatmapID = 162, + }); + } } } diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs index 9365e2c5b1..157e572606 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs @@ -270,9 +270,8 @@ namespace osu.Game.Tests.Visual.SongSelect }, Metrics = new BeatmapMetrics { - Ratings = Enumerable.Range(0, 11), - Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), - Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), + Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(), + Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(), }, }; } diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index f5115c50a9..738b7f14f3 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -18,6 +18,7 @@ using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Taiko; using osu.Game.Screens.Select; @@ -100,8 +101,11 @@ namespace osu.Game.Tests.Visual.SongSelect } [SetUp] - public virtual void SetUp() => - Schedule(() => { manager?.Delete(manager.GetAllUsableBeatmapSets()); }); + public virtual void SetUp() => Schedule(() => + { + Ruleset.Value = new OsuRuleset().RulesetInfo; + manager?.Delete(manager.GetAllUsableBeatmapSets()); + }); [Test] public void TestDummy() @@ -185,7 +189,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("empty mods", () => !Mods.Value.Any()); void onModChange(ValueChangedEvent> e) => modChangeIndex = actionIndex++; - void onRulesetChange(ValueChangedEvent e) => rulesetChangeIndex = actionIndex--; + void onRulesetChange(ValueChangedEvent e) => rulesetChangeIndex = actionIndex++; } [Test] diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneIconButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneIconButton.cs index 0c9ce50288..c80b3e6297 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneIconButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneIconButton.cs @@ -26,8 +26,7 @@ namespace osu.Game.Tests.Visual.UserInterface { new NamedIconButton("No change", new IconButton()), new NamedIconButton("Background colours", new ColouredIconButton()), - new NamedIconButton("Full-width", new IconButton { ButtonSize = new Vector2(200, 30) }), - new NamedIconButton("Unchanging size", new IconButton(), false), + new NamedIconButton("Full-width", new IconButton { Size = new Vector2(200, 30) }), new NamedIconButton("Icon colours", new IconButton { IconColour = Color4.Green, @@ -48,7 +47,7 @@ namespace osu.Game.Tests.Visual.UserInterface private class NamedIconButton : Container { - public NamedIconButton(string name, IconButton button, bool allowSizeChange = true) + public NamedIconButton(string name, IconButton button) { AutoSizeAxes = Axes.Y; Width = 200; @@ -101,13 +100,7 @@ namespace osu.Game.Tests.Visual.UserInterface } }; - if (allowSizeChange) - iconContainer.AutoSizeAxes = Axes.Both; - else - { - iconContainer.RelativeSizeAxes = Axes.X; - iconContainer.Height = 30; - } + iconContainer.AutoSizeAxes = Axes.Both; button.Anchor = Anchor.Centre; button.Origin = Anchor.Centre; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneMusicController.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneMusicController.cs index 2f2a40925f..ab2ca47100 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneMusicController.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneMusicController.cs @@ -3,7 +3,6 @@ using NUnit.Framework; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Timing; using osu.Game.Overlays; @@ -23,9 +22,9 @@ namespace osu.Game.Tests.Visual.UserInterface }; Add(mc); - AddToggleStep(@"toggle visibility", state => mc.State.Value = state ? Visibility.Visible : Visibility.Hidden); AddStep(@"show", () => mc.Show()); AddToggleStep(@"toggle beatmap lock", state => Beatmap.Disabled = state); + AddStep(@"show", () => mc.Hide()); } } } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuIcon.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuIcon.cs index 2c2a28394c..061039b297 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuIcon.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuIcon.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osuTK; using osuTK.Graphics; @@ -29,7 +30,7 @@ namespace osu.Game.Tests.Visual.UserInterface Colour = Color4.Teal, RelativeSizeAxes = Axes.Both, }, - new ScrollContainer + new OsuScrollContainer { RelativeSizeAxes = Axes.Both, Child = flow = new FillFlowContainer diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs index c361598354..9cdfcb6cc4 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; +using osu.Game.Graphics.Containers; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Rulesets; @@ -92,13 +93,13 @@ namespace osu.Game.Tests.Visual.UserInterface public void TestUnloadAndReload() { var backgrounds = new List(); - ScrollContainer scrollContainer = null; + OsuScrollContainer scrollContainer = null; AddStep("create backgrounds hierarchy", () => { FillFlowContainer backgroundFlow; - Child = scrollContainer = new ScrollContainer + Child = scrollContainer = new OsuScrollContainer { Size = new Vector2(500), Child = backgroundFlow = new FillFlowContainer diff --git a/osu.Game/Beatmaps/BeatmapMetrics.cs b/osu.Game/Beatmaps/BeatmapMetrics.cs index 95413e6d2a..b164aa6b30 100644 --- a/osu.Game/Beatmaps/BeatmapMetrics.cs +++ b/osu.Game/Beatmaps/BeatmapMetrics.cs @@ -1,31 +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.Collections.Generic; +using System; using Newtonsoft.Json; namespace osu.Game.Beatmaps { /// - /// Beatmap metrics based on acculumated online data from community plays. + /// Beatmap metrics based on accumulated online data from community plays. /// public class BeatmapMetrics { - /// - /// Total vote counts of user ratings on a scale of 0..10 where 0 is unused (probably will be fixed at API?). - /// - public IEnumerable Ratings { get; set; } - /// /// Points of failure on a relative time scale (usually 0..100). /// [JsonProperty(@"fail")] - public IEnumerable Fails { get; set; } + public int[] Fails { get; set; } = Array.Empty(); /// /// Points of retry on a relative time scale (usually 0..100). /// [JsonProperty(@"exit")] - public IEnumerable Retries { get; set; } + public int[] Retries { get; set; } = Array.Empty(); } } diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index 390236e053..c09119ab14 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -32,6 +32,9 @@ namespace osu.Game.Beatmaps [NotMapped] public BeatmapSetOnlineInfo OnlineInfo { get; set; } + [NotMapped] + public BeatmapSetMetrics Metrics { get; set; } + public double MaxStarDifficulty => Beatmaps?.Max(b => b.StarDifficulty) ?? 0; [NotMapped] diff --git a/osu.Game/Beatmaps/BeatmapSetMetrics.cs b/osu.Game/Beatmaps/BeatmapSetMetrics.cs new file mode 100644 index 0000000000..51c5de19a6 --- /dev/null +++ b/osu.Game/Beatmaps/BeatmapSetMetrics.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 System; +using Newtonsoft.Json; + +namespace osu.Game.Beatmaps +{ + public class BeatmapSetMetrics + { + /// + /// Total vote counts of user ratings on a scale of 0..10 where 0 is unused (probably will be fixed at API?). + /// + [JsonProperty("ratings")] + public int[] Ratings { get; set; } = Array.Empty(); + } +} diff --git a/osu.Game/Graphics/Containers/OsuScrollContainer.cs b/osu.Game/Graphics/Containers/OsuScrollContainer.cs index f7d406a419..53092ddc9e 100644 --- a/osu.Game/Graphics/Containers/OsuScrollContainer.cs +++ b/osu.Game/Graphics/Containers/OsuScrollContainer.cs @@ -1,13 +1,18 @@ // 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.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; +using osuTK; +using osuTK.Graphics; using osuTK.Input; namespace osu.Game.Graphics.Containers { - public class OsuScrollContainer : ScrollContainer + public class OsuScrollContainer : ScrollContainer { /// /// Allows controlling the scroll bar from any position in the container using the right mouse button. @@ -28,6 +33,11 @@ namespace osu.Game.Graphics.Containers protected override bool IsDragging => base.IsDragging || mouseScrollBarDragging; + public OsuScrollContainer(Direction scrollDirection = Direction.Vertical) + : base(scrollDirection) + { + } + protected override bool OnMouseDown(MouseDownEvent e) { if (shouldPerformRightMouseScroll(e)) @@ -71,5 +81,87 @@ namespace osu.Game.Graphics.Containers return base.OnDragEnd(e); } + + protected override ScrollbarContainer CreateScrollbar(Direction direction) => new OsuScrollbar(direction); + + protected class OsuScrollbar : ScrollbarContainer + { + private const float dim_size = 10; + + private Color4 hoverColour; + private Color4 defaultColour; + private Color4 highlightColour; + + private readonly Box box; + + public OsuScrollbar(Direction scrollDir) + : base(scrollDir) + { + Blending = BlendingMode.Additive; + + CornerRadius = 5; + + const float margin = 3; + + Margin = new MarginPadding + { + Left = scrollDir == Direction.Vertical ? margin : 0, + Right = scrollDir == Direction.Vertical ? margin : 0, + Top = scrollDir == Direction.Horizontal ? margin : 0, + Bottom = scrollDir == Direction.Horizontal ? margin : 0, + }; + + Masking = true; + Child = box = new Box { RelativeSizeAxes = Axes.Both }; + + ResizeTo(1); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = defaultColour = colours.Gray8; + hoverColour = colours.GrayF; + highlightColour = colours.Green; + } + + public override void ResizeTo(float val, int duration = 0, Easing easing = Easing.None) + { + Vector2 size = new Vector2(dim_size) + { + [(int)ScrollDirection] = val + }; + this.ResizeTo(size, duration, easing); + } + + protected override bool OnHover(HoverEvent e) + { + this.FadeColour(hoverColour, 100); + return true; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + this.FadeColour(defaultColour, 100); + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (!base.OnMouseDown(e)) return false; + + //note that we are changing the colour of the box here as to not interfere with the hover effect. + box.FadeColour(highlightColour, 100); + return true; + } + + protected override bool OnMouseUp(MouseUpEvent e) + { + if (e.Button != MouseButton.Left) return false; + + box.FadeColour(Color4.White, 100); + + return base.OnMouseUp(e); + } + } } } diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index a8d0e03c01..9d886c457f 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -16,7 +16,7 @@ namespace osu.Game.Graphics.Containers where T : Drawable { private Drawable expandableHeader, fixedHeader, footer, headerBackground; - private readonly ScrollContainer scrollContainer; + private readonly OsuScrollContainer scrollContainer; private readonly Container headerBackgroundContainer; private readonly FlowContainer scrollContentContainer; @@ -124,7 +124,7 @@ namespace osu.Game.Graphics.Containers public SectionsContainer() { - AddInternal(scrollContainer = new ScrollContainer + AddInternal(scrollContainer = new OsuScrollContainer { RelativeSizeAxes = Axes.Both, Masking = true, diff --git a/osu.Game/Graphics/UserInterface/IconButton.cs b/osu.Game/Graphics/UserInterface/IconButton.cs index 052e9194fa..27427581fd 100644 --- a/osu.Game/Graphics/UserInterface/IconButton.cs +++ b/osu.Game/Graphics/UserInterface/IconButton.cs @@ -11,7 +11,7 @@ namespace osu.Game.Graphics.UserInterface { public class IconButton : OsuAnimatedButton { - public const float BUTTON_SIZE = 30; + public const float DEFAULT_BUTTON_SIZE = 30; private Color4? iconColour; @@ -57,26 +57,11 @@ namespace osu.Game.Graphics.UserInterface set => icon.Scale = value; } - /// - /// The size of the while it is not being pressed. - /// - public Vector2 ButtonSize - { - get => Content.Size; - set - { - Content.RelativeSizeAxes = Axes.None; - Content.AutoSizeAxes = Axes.None; - Content.Size = value; - } - } - private readonly SpriteIcon icon; public IconButton() { - AutoSizeAxes = Axes.Both; - ButtonSize = new Vector2(BUTTON_SIZE); + Size = new Vector2(DEFAULT_BUTTON_SIZE); Add(icon = new SpriteIcon { diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 12b38fab1e..d722c7a98a 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -262,8 +262,9 @@ namespace osu.Game.Online.API handleWebException(we); return false; } - catch + catch (Exception ex) { + Logger.Error(ex, "Error occurred while handling an API request."); return false; } } diff --git a/osu.Game/Online/API/APIDownloadRequest.cs b/osu.Game/Online/API/APIDownloadRequest.cs index efc832a71e..940b9b4803 100644 --- a/osu.Game/Online/API/APIDownloadRequest.cs +++ b/osu.Game/Online/API/APIDownloadRequest.cs @@ -10,9 +10,18 @@ namespace osu.Game.Online.API { private string filename; + /// + /// Used to set the extension of the file returned by this request. + /// + protected virtual string FileExtension { get; } = @".tmp"; + protected override WebRequest CreateWebRequest() { - var request = new FileWebRequest(filename = Path.GetTempFileName(), Uri); + var file = Path.GetTempFileName(); + + File.Move(file, filename = Path.ChangeExtension(file, FileExtension)); + + var request = new FileWebRequest(filename, Uri); request.DownloadProgress += request_Progress; return request; } diff --git a/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs deleted file mode 100644 index ed5efa2849..0000000000 --- a/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs +++ /dev/null @@ -1,20 +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.Game.Beatmaps; -using osu.Game.Online.API.Requests.Responses; - -namespace osu.Game.Online.API.Requests -{ - public class GetBeatmapDetailsRequest : APIRequest - { - private readonly BeatmapInfo beatmap; - - public GetBeatmapDetailsRequest(BeatmapInfo beatmap) - { - this.beatmap = beatmap; - } - - protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}"; - } -} diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index edbcbed59f..bcbe060f82 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -57,6 +57,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"version")] private string version { get; set; } + [JsonProperty(@"failtimes")] + private BeatmapMetrics metrics { get; set; } + public BeatmapInfo ToBeatmap(RulesetStore rulesets) { var set = BeatmapSet?.ToBeatmapSet(rulesets); @@ -70,6 +73,7 @@ namespace osu.Game.Online.API.Requests.Responses Version = version, Status = Status, BeatmapSet = set, + Metrics = metrics, BaseDifficulty = new BeatmapDifficulty { DrainRate = drainRate, diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapMetrics.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapMetrics.cs deleted file mode 100644 index f049b3aed4..0000000000 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapMetrics.cs +++ /dev/null @@ -1,29 +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 Newtonsoft.Json; -using osu.Game.Beatmaps; - -namespace osu.Game.Online.API.Requests.Responses -{ - public class APIBeatmapMetrics : BeatmapMetrics - { - //the online API returns some metrics as a nested object. - [JsonProperty(@"failtimes")] - private BeatmapMetrics failTimes - { - set - { - Fails = value.Fails; - Retries = value.Retries; - } - } - - //and other metrics in the beatmap set. - [JsonProperty(@"beatmapset")] - private BeatmapMetrics beatmapSet - { - set => Ratings = value.Ratings; - } - } -} diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index 1abb7c1a7d..00e08633dd 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -54,6 +54,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"last_updated")] private DateTimeOffset lastUpdated { get; set; } + [JsonProperty(@"ratings")] + private int[] ratings { get; set; } + [JsonProperty(@"user_id")] private long creatorId { @@ -70,6 +73,7 @@ namespace osu.Game.Online.API.Requests.Responses OnlineBeatmapSetID = OnlineBeatmapSetID, Metadata = this, Status = Status, + Metrics = ratings == null ? null : new BeatmapSetMetrics { Ratings = ratings }, OnlineInfo = new BeatmapSetOnlineInfo { Covers = covers, diff --git a/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs b/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs index 40f1b791f9..36407c7b0e 100644 --- a/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs +++ b/osu.Game/Online/API/Requests/Responses/APIChangelogBuild.cs @@ -31,9 +31,9 @@ namespace osu.Game.Online.API.Requests.Responses public List ChangelogEntries { get; set; } [JsonProperty("versions")] - public VersionNatigation Versions { get; set; } + public VersionNavigation Versions { get; set; } - public class VersionNatigation + public class VersionNavigation { [JsonProperty("next")] public APIChangelogBuild Next { get; set; } diff --git a/osu.Game/Online/API/Requests/SubmitRoomScoreRequest.cs b/osu.Game/Online/API/Requests/SubmitRoomScoreRequest.cs index 1a2503f339..50b62cd6ed 100644 --- a/osu.Game/Online/API/Requests/SubmitRoomScoreRequest.cs +++ b/osu.Game/Online/API/Requests/SubmitRoomScoreRequest.cs @@ -30,7 +30,10 @@ namespace osu.Game.Online.API.Requests req.ContentType = "application/json"; req.Method = HttpMethod.Put; - req.AddRaw(JsonConvert.SerializeObject(scoreInfo)); + req.AddRaw(JsonConvert.SerializeObject(scoreInfo, new JsonSerializerSettings + { + ReferenceLoopHandling = ReferenceLoopHandling.Ignore + })); return req; } diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 3ce71cccba..b91de93a4a 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -23,7 +23,7 @@ namespace osu.Game.Online.Leaderboards { private const double fade_duration = 300; - private readonly ScrollContainer scrollContainer; + private readonly OsuScrollContainer scrollContainer; private readonly Container placeholderContainer; private FillFlowContainer scrollFlow; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index d5fbcdfee3..f38eecef81 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -181,7 +181,7 @@ namespace osu.Game configSkin.ValueChanged += skinId => SkinManager.CurrentSkinInfo.Value = SkinManager.Query(s => s.ID == skinId.NewValue) ?? SkinInfo.Default; configSkin.TriggerChange(); - LocalConfig.BindWith(OsuSetting.VolumeInactive, inactiveVolumeAdjust); + LocalConfig.BindWith(OsuSetting.VolumeInactive, userInactiveVolume); IsActive.BindValueChanged(active => updateActiveState(active.NewValue), true); } @@ -686,16 +686,28 @@ namespace osu.Game return false; } - private readonly BindableDouble inactiveVolumeAdjust = new BindableDouble(); + #region Inactive audio dimming + + private readonly BindableDouble userInactiveVolume = new BindableDouble(); + + private readonly BindableDouble inactiveVolumeFade = new BindableDouble(); private void updateActiveState(bool isActive) { if (isActive) - Audio.RemoveAdjustment(AdjustableProperty.Volume, inactiveVolumeAdjust); + { + this.TransformBindableTo(inactiveVolumeFade, 1, 500, Easing.OutQuint) + .Finally(_ => Audio.RemoveAdjustment(AdjustableProperty.Volume, inactiveVolumeFade)); //wait for the transition to finish to remove the inactive audio adjustment + } else - Audio.AddAdjustment(AdjustableProperty.Volume, inactiveVolumeAdjust); + { + Audio.AddAdjustment(AdjustableProperty.Volume, inactiveVolumeFade); + this.TransformBindableTo(inactiveVolumeFade, userInactiveVolume.Value, 1500, Easing.OutSine); + } } + #endregion + public bool OnReleased(GlobalAction action) => false; private Container overlayContent; diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs index 8ed52dade5..6a583baf38 100644 --- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs +++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs @@ -50,7 +50,7 @@ namespace osu.Game.Overlays.BeatmapSet private void updateDisplay() { - bpm.Value = BeatmapSet?.OnlineInfo.BPM.ToString(@"0.##") ?? "-"; + bpm.Value = BeatmapSet?.OnlineInfo?.BPM.ToString(@"0.##") ?? "-"; if (beatmap == null) { diff --git a/osu.Game/Overlays/BeatmapSet/Details.cs b/osu.Game/Overlays/BeatmapSet/Details.cs index fad5c973b7..d76f6a43db 100644 --- a/osu.Game/Overlays/BeatmapSet/Details.cs +++ b/osu.Game/Overlays/BeatmapSet/Details.cs @@ -16,10 +16,11 @@ namespace osu.Game.Overlays.BeatmapSet { public class Details : FillFlowContainer { + protected readonly UserRatings Ratings; + private readonly PreviewButton preview; private readonly BasicStats basic; private readonly AdvancedStats advanced; - private readonly UserRatings ratings; private BeatmapSetInfo beatmapSet; @@ -33,6 +34,7 @@ namespace osu.Game.Overlays.BeatmapSet beatmapSet = value; basic.BeatmapSet = preview.BeatmapSet = BeatmapSet; + updateDisplay(); } } @@ -46,13 +48,12 @@ namespace osu.Game.Overlays.BeatmapSet if (value == beatmap) return; basic.Beatmap = advanced.Beatmap = beatmap = value; - updateDisplay(); } } private void updateDisplay() { - ratings.Metrics = Beatmap?.Metrics; + Ratings.Metrics = BeatmapSet?.Metrics; } public Details() @@ -87,7 +88,7 @@ namespace osu.Game.Overlays.BeatmapSet }, new DetailBox { - Child = ratings = new UserRatings + Child = Ratings = new UserRatings { RelativeSizeAxes = Axes.X, Height = 95, diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index c89bddca63..0258a0301a 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -14,11 +14,12 @@ namespace osu.Game.Overlays.BeatmapSet { public class SuccessRate : Container { + protected readonly FailRetryGraph Graph; + private readonly FillFlowContainer header; private readonly OsuSpriteText successRateLabel, successPercent, graphLabel; private readonly Bar successRate; private readonly Container percentContainer; - private readonly FailRetryGraph graph; private BeatmapInfo beatmap; @@ -37,15 +38,15 @@ namespace osu.Game.Overlays.BeatmapSet private void updateDisplay() { - int passCount = beatmap?.OnlineInfo.PassCount ?? 0; - int playCount = beatmap?.OnlineInfo.PlayCount ?? 0; + int passCount = beatmap?.OnlineInfo?.PassCount ?? 0; + int playCount = beatmap?.OnlineInfo?.PlayCount ?? 0; var rate = playCount != 0 ? (float)passCount / playCount : 0; successPercent.Text = rate.ToString("P0"); successRate.Length = rate; percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic); - graph.Metrics = beatmap?.Metrics; + Graph.Metrics = beatmap?.Metrics; } public SuccessRate() @@ -94,7 +95,7 @@ namespace osu.Game.Overlays.BeatmapSet }, }, }, - graph = new FailRetryGraph + Graph = new FailRetryGraph { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, @@ -117,7 +118,7 @@ namespace osu.Game.Overlays.BeatmapSet { base.UpdateAfterChildren(); - graph.Padding = new MarginPadding { Top = header.DrawHeight }; + Graph.Padding = new MarginPadding { Top = header.DrawHeight }; } } } diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index e0852a890c..1e687267a3 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -30,7 +30,7 @@ namespace osu.Game.Overlays private RulesetStore rulesets; - private readonly ScrollContainer scroll; + private readonly OsuScrollContainer scroll; private readonly Bindable beatmapSet = new Bindable(); @@ -49,7 +49,7 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(0.2f) }, - scroll = new ScrollContainer + scroll = new OsuScrollContainer { RelativeSizeAxes = Axes.Both, ScrollbarVisible = false, diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs index 67f195580e..7755c8a6a6 100644 --- a/osu.Game/Overlays/ChangelogOverlay.cs +++ b/osu.Game/Overlays/ChangelogOverlay.cs @@ -51,7 +51,7 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Both, Colour = colour.PurpleDarkAlternative, }, - new ScrollContainer + new OsuScrollContainer { RelativeSizeAxes = Axes.Both, ScrollbarVisible = false, diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index aec78b962f..7d28df3210 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Chat { public readonly Channel Channel; protected readonly ChatLineContainer ChatLineFlow; - private readonly ScrollContainer scroll; + private readonly OsuScrollContainer scroll; public DrawableChannel(Channel channel) { diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 85524e992c..8b9bac877b 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -464,12 +464,26 @@ namespace osu.Game.Overlays private class MusicIconButton : IconButton { + public MusicIconButton() + { + AutoSizeAxes = Axes.Both; + } + [BackgroundDependencyLoader] private void load(OsuColour colours) { HoverColour = colours.YellowDark.Opacity(0.6f); FlashColour = colours.Yellow; } + + protected override void LoadComplete() + { + base.LoadComplete(); + + // works with AutoSizeAxes above to make buttons autosize with the scale animation. + Content.AutoSizeAxes = Axes.None; + Content.Size = new Vector2(DEFAULT_BUTTON_SIZE); + } } private class Background : BufferedContainer diff --git a/osu.Game/Overlays/Settings/Sidebar.cs b/osu.Game/Overlays/Settings/Sidebar.cs index 3c18627f23..a80b7c1108 100644 --- a/osu.Game/Overlays/Settings/Sidebar.cs +++ b/osu.Game/Overlays/Settings/Sidebar.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Framework.Threading; +using osu.Game.Graphics.Containers; using osu.Game.Overlays.Toolbar; namespace osu.Game.Overlays.Settings @@ -76,7 +77,7 @@ namespace osu.Game.Overlays.Settings return base.OnMouseMove(e); } - private class SidebarScrollContainer : ScrollContainer + private class SidebarScrollContainer : OsuScrollContainer { public SidebarScrollContainer() { diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index ec7e6dc303..1cce5598e1 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -167,6 +167,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { OnRevertResult?.Invoke(this, Result); + Result.TimeOffset = 0; Result.Type = HitResult.None; State.Value = ArmedState.Idle; } @@ -243,6 +244,10 @@ namespace osu.Game.Rulesets.Objects.Drawables /// Whether a scoring result has occurred from this or any nested . protected bool UpdateResult(bool userTriggered) { + // It's possible for input to get into a bad state when rewinding gameplay, so results should not be processed + if (Time.Elapsed < 0) + return false; + judgementOccurred = false; if (AllJudged) diff --git a/osu.Game/Screens/Edit/Components/PlaybackControl.cs b/osu.Game/Screens/Edit/Components/PlaybackControl.cs index f5c9f74f62..8d4ad0efa9 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackControl.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackControl.cs @@ -36,12 +36,11 @@ namespace osu.Game.Screens.Edit.Components playButton = new IconButton { Anchor = Anchor.CentreLeft, - Origin = Anchor.Centre, + Origin = Anchor.CentreLeft, Scale = new Vector2(1.4f), IconScale = new Vector2(1.4f), Icon = FontAwesome.Regular.PlayCircle, Action = togglePause, - Padding = new MarginPadding { Left = 20 } }, new OsuSpriteText { diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index ebf8c9c309..c615656d60 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -171,7 +171,7 @@ namespace osu.Game.Screens.Edit.Compose.Components // Small offset to look a bit better centered along with the divisor text Y = 1; - ButtonSize = new Vector2(20); + Size = new Vector2(20); IconScale = new Vector2(0.6f); } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs index 49e97e698b..8865bf31ea 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs @@ -31,14 +31,14 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline InternalChild = button = new TimelineIconButton { Action = () => Action?.Invoke() }; button.Enabled.BindTo(Enabled); - Width = button.ButtonSize.X; + Width = button.Width; } protected override void Update() { base.Update(); - button.ButtonSize = new Vector2(button.ButtonSize.X, DrawHeight); + button.Size = new Vector2(button.Width, DrawHeight); } private class TimelineIconButton : IconButton diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs index 829437d599..cffb6bedf3 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs @@ -7,11 +7,12 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Transforms; using osu.Framework.Input.Events; using osu.Framework.MathUtils; +using osu.Game.Graphics.Containers; using osuTK; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class ZoomableScrollContainer : ScrollContainer + public class ZoomableScrollContainer : OsuScrollContainer { /// /// The time to zoom into/out of a point. diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs b/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs index d597e5bb0f..1a18f742a9 100644 --- a/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs +++ b/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Cursor; 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.Online.API; using osu.Game.Online.API.Requests; @@ -226,7 +227,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components { Padding = new MarginPadding { Horizontal = 10 }; - InternalChild = new ScrollContainer + InternalChild = new OsuScrollContainer { RelativeSizeAxes = Axes.Both, Child = fill = new FillFlowContainer diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs index 7cbae611ea..7f8e690516 100644 --- a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; 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.Overlays.SearchableList; @@ -43,7 +44,7 @@ namespace osu.Game.Screens.Multi.Lounge Width = 0.55f, Children = new Drawable[] { - new ScrollContainer + new OsuScrollContainer { RelativeSizeAxes = Axes.Both, ScrollbarOverlapsContent = false, diff --git a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs index 359b5824c0..410aaed788 100644 --- a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs +++ b/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs @@ -10,6 +10,7 @@ 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; @@ -91,7 +92,7 @@ namespace osu.Game.Screens.Multi.Match.Components { new Drawable[] { - new ScrollContainer + new OsuScrollContainer { Padding = new MarginPadding { diff --git a/osu.Game/Screens/Multi/Match/Components/Participants.cs b/osu.Game/Screens/Multi/Match/Components/Participants.cs index 09d25572ec..ad38ec6a99 100644 --- a/osu.Game/Screens/Multi/Match/Components/Participants.cs +++ b/osu.Game/Screens/Multi/Match/Components/Participants.cs @@ -5,6 +5,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Containers; using osu.Game.Overlays.SearchableList; using osu.Game.Screens.Multi.Components; using osu.Game.Users; @@ -25,7 +26,7 @@ namespace osu.Game.Screens.Multi.Match.Components Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING }, Children = new Drawable[] { - new ScrollContainer + new OsuScrollContainer { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Top = 10 }, diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 378b1b1dc6..23dd87d8ea 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -10,7 +10,6 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using System.Linq; using osu.Game.Online.API; -using osu.Game.Online.API.Requests; using osu.Framework.Threading; using osu.Framework.Graphics.Shapes; using osu.Framework.Extensions.Color4Extensions; @@ -18,6 +17,8 @@ using osu.Game.Screens.Select.Details; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Online.API.Requests; +using osu.Game.Rulesets; namespace osu.Game.Screens.Select { @@ -30,7 +31,7 @@ namespace osu.Game.Screens.Select private readonly AdvancedStats advanced; private readonly DetailBox ratingsContainer; private readonly UserRatings ratings; - private readonly ScrollContainer metadataScroll; + private readonly OsuScrollContainer metadataScroll; private readonly MetadataSection description, source, tags; private readonly Container failRetryContainer; private readonly FailRetryGraph failRetryGraph; @@ -40,6 +41,9 @@ namespace osu.Game.Screens.Select private ScheduledDelegate pendingBeatmapSwitch; + [Resolved] + private RulesetStore rulesets { get; set; } + private BeatmapInfo beatmap; public BeatmapInfo Beatmap @@ -107,7 +111,7 @@ namespace osu.Game.Screens.Select }, }, }, - metadataScroll = new ScrollContainer + metadataScroll = new OsuScrollContainer { RelativeSizeAxes = Axes.X, Width = 0.5f, @@ -181,57 +185,79 @@ namespace osu.Game.Screens.Select tags.Text = Beatmap?.Metadata?.Tags; // metrics may have been previously fetched - if (Beatmap?.Metrics != null) + if (Beatmap?.BeatmapSet?.Metrics != null && Beatmap?.Metrics != null) { - updateMetrics(Beatmap.Metrics); + updateMetrics(); return; } - // metrics may not be fetched but can be - if (Beatmap?.OnlineBeatmapID != null) + // for now, let's early abort if an OnlineBeatmapID is not present (should have been populated at import time). + if (Beatmap?.OnlineBeatmapID == null) { - var requestedBeatmap = Beatmap; - var lookup = new GetBeatmapDetailsRequest(requestedBeatmap); - lookup.Success += res => + updateMetrics(); + return; + } + + var requestedBeatmap = Beatmap; + + var lookup = new GetBeatmapRequest(requestedBeatmap); + + lookup.Success += res => + { + Schedule(() => { if (beatmap != requestedBeatmap) //the beatmap has been changed since we started the lookup. return; - requestedBeatmap.Metrics = res; - Schedule(() => updateMetrics(res)); - }; - lookup.Failure += e => Schedule(() => updateMetrics()); - api.Queue(lookup); - loading.Show(); - return; - } + var b = res.ToBeatmap(rulesets); - updateMetrics(); + if (requestedBeatmap.BeatmapSet == null) + requestedBeatmap.BeatmapSet = b.BeatmapSet; + else + requestedBeatmap.BeatmapSet.Metrics = b.BeatmapSet.Metrics; + + requestedBeatmap.Metrics = b.Metrics; + + updateMetrics(); + }); + }; + + lookup.Failure += e => + { + Schedule(() => + { + if (beatmap != requestedBeatmap) + //the beatmap has been changed since we started the lookup. + return; + + updateMetrics(); + }); + }; + + api.Queue(lookup); + loading.Show(); } - private void updateMetrics(BeatmapMetrics metrics = null) + private void updateMetrics() { - var hasRatings = metrics?.Ratings?.Any() ?? false; - var hasRetriesFails = (metrics?.Retries?.Any() ?? false) && (metrics.Fails?.Any() ?? false); + var hasRatings = beatmap?.BeatmapSet?.Metrics?.Ratings?.Any() ?? false; + var hasRetriesFails = (beatmap?.Metrics?.Retries?.Any() ?? false) && (beatmap?.Metrics.Fails?.Any() ?? false); if (hasRatings) { - ratings.Metrics = metrics; + ratings.Metrics = beatmap.BeatmapSet.Metrics; ratingsContainer.FadeIn(transition_duration); } else { - ratings.Metrics = new BeatmapMetrics - { - Ratings = new int[10], - }; + ratings.Metrics = new BeatmapSetMetrics { Ratings = new int[10] }; ratingsContainer.FadeTo(0.25f, transition_duration); } if (hasRetriesFails) { - failRetryGraph.Metrics = metrics; + failRetryGraph.Metrics = beatmap.Metrics; failRetryContainer.FadeIn(transition_duration); } else diff --git a/osu.Game/Screens/Select/Details/UserRatings.cs b/osu.Game/Screens/Select/Details/UserRatings.cs index b17a3f79e9..c1e01e3572 100644 --- a/osu.Game/Screens/Select/Details/UserRatings.cs +++ b/osu.Game/Screens/Select/Details/UserRatings.cs @@ -20,9 +20,9 @@ namespace osu.Game.Screens.Select.Details private readonly Container graphContainer; private readonly BarGraph graph; - private BeatmapMetrics metrics; + private BeatmapSetMetrics metrics; - public BeatmapMetrics Metrics + public BeatmapSetMetrics Metrics { get => metrics; set diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 75a464d0b8..957d365724 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -15,7 +15,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 5e151f916b..9b146fa490 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -105,8 +105,8 @@ - - + +