diff --git a/osu-framework b/osu-framework index 6915954abd..59004b46f2 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 6915954abdba64e72f698aa58698b00159f3678d +Subproject commit 59004b46f2c96ac02fec712e66f9f96fe252f2fa diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs index 8a03f5a785..b8ae09c4a0 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs @@ -3,13 +3,14 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.Mania.UI { internal class DrawableManiaJudgement : DrawableJudgement { - public DrawableManiaJudgement(Judgement judgement) - : base(judgement) + public DrawableManiaJudgement(Judgement judgement, DrawableHitObject judgedObject) + : base(judgement, judgedObject) { JudgementText.TextSize = 25; } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs index 2b8039f5df..d4ca704829 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs @@ -15,6 +15,7 @@ using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; using OpenTK; using OpenTK.Graphics; @@ -40,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.UI private readonly Container content; public Container Judgements => judgements; - private readonly Container judgements; + private readonly JudgementContainer judgements; private readonly Container topLevelContainer; @@ -114,7 +115,7 @@ namespace osu.Game.Rulesets.Mania.UI Padding = new MarginPadding { Top = HIT_TARGET_POSITION } } }, - judgements = new Container + judgements = new JudgementContainer { Anchor = Anchor.TopCentre, Origin = Anchor.Centre, @@ -171,7 +172,7 @@ namespace osu.Game.Rulesets.Mania.UI internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) { judgements.Clear(); - judgements.Add(new DrawableManiaJudgement(judgement) + judgements.Add(new DrawableManiaJudgement(judgement, judgedObject) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs index 716f4b629b..0b1df4bdf5 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs @@ -2,17 +2,17 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Graphics; -using osu.Game.Rulesets.Osu.Judgements; using OpenTK; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu.Objects.Drawables { public class DrawableOsuJudgement : DrawableJudgement { - public DrawableOsuJudgement(OsuJudgement judgement) - : base(judgement) + public DrawableOsuJudgement(Judgement judgement, DrawableHitObject judgedObject) + : base(judgement, judgedObject) { } diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 7f8cbce78e..98a8096678 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.UI public class OsuPlayfield : Playfield { private readonly Container approachCircles; - private readonly Container judgementLayer; + private readonly JudgementContainer judgementLayer; private readonly ConnectionRenderer connectionLayer; // Todo: This should not be a thing, but is currently required for the editor @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.UI RelativeSizeAxes = Axes.Both, Depth = 2, }, - judgementLayer = new Container + judgementLayer = new JudgementContainer { RelativeSizeAxes = Axes.Both, Depth = 1, @@ -75,16 +75,13 @@ namespace osu.Game.Rulesets.Osu.UI private void onJudgement(DrawableHitObject judgedObject, Judgement judgement) { - var osuJudgement = (OsuJudgement)judgement; - var osuObject = (OsuHitObject)judgedObject.HitObject; - if (!judgedObject.DisplayJudgement) return; - DrawableOsuJudgement explosion = new DrawableOsuJudgement(osuJudgement) + DrawableOsuJudgement explosion = new DrawableOsuJudgement(judgement, judgedObject) { Origin = Anchor.Centre, - Position = osuObject.StackedEndPosition + osuJudgement.PositionOffset + Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition + ((OsuJudgement)judgement).PositionOffset }; judgementLayer.Add(explosion); diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs index c0e8bd1b5a..6274232ffd 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs @@ -15,17 +15,14 @@ namespace osu.Game.Rulesets.Taiko.UI /// public class DrawableTaikoJudgement : DrawableJudgement { - public readonly DrawableHitObject JudgedObject; - /// /// Creates a new judgement text. /// /// The object which is being judged. /// The judgement to visualise. - public DrawableTaikoJudgement(DrawableHitObject judgedObject, Judgement judgement) - : base(judgement) + public DrawableTaikoJudgement(Judgement judgement, DrawableHitObject judgedObject) + : base(judgement, judgedObject) { - JudgedObject = judgedObject; } [BackgroundDependencyLoader] diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 49c87f7480..75aaceaecb 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -16,6 +16,7 @@ using System.Linq; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Taiko.UI @@ -41,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Container hitExplosionContainer; private readonly Container kiaiExplosionContainer; - private readonly Container judgementContainer; + private readonly JudgementContainer judgementContainer; protected override Container Content => content; private readonly Container content; @@ -131,7 +132,7 @@ namespace osu.Game.Rulesets.Taiko.UI Margin = new MarginPadding { Left = HIT_TARGET_OFFSET }, Blending = BlendingMode.Additive }, - judgementContainer = new Container + judgementContainer = new JudgementContainer { Name = "Judgements", RelativeSizeAxes = Axes.Y, @@ -227,7 +228,7 @@ namespace osu.Game.Rulesets.Taiko.UI { if (judgedObject.DisplayJudgement && judgementContainer.FirstOrDefault(j => j.JudgedObject == judgedObject) == null) { - judgementContainer.Add(new DrawableTaikoJudgement(judgedObject, judgement) + judgementContainer.Add(new DrawableTaikoJudgement(judgement, judgedObject) { Anchor = judgement.IsHit ? Anchor.TopLeft : Anchor.CentreLeft, Origin = judgement.IsHit ? Anchor.BottomCentre : Anchor.Centre, diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs index fe26366362..c68e548f44 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs @@ -12,6 +12,7 @@ using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Rulesets; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Carousel; using osu.Game.Screens.Select.Filter; @@ -22,6 +23,7 @@ namespace osu.Game.Tests.Visual public class TestCaseBeatmapCarousel : OsuTestCase { private TestBeatmapCarousel carousel; + private RulesetStore rulesets; public override IReadOnlyList RequiredTypes => new[] { @@ -46,8 +48,10 @@ namespace osu.Game.Tests.Visual private const int set_count = 5; [BackgroundDependencyLoader] - private void load() + private void load(RulesetStore rulesets) { + this.rulesets = rulesets; + Add(carousel = new TestBeatmapCarousel { RelativeSizeAxes = Axes.Both, @@ -75,6 +79,7 @@ namespace osu.Game.Tests.Visual testRemoveAll(); testEmptyTraversal(); testHiding(); + testSelectingFilteredRuleset(); } private void ensureRandomFetchSuccess() => @@ -363,6 +368,41 @@ namespace osu.Game.Tests.Visual } } + private void testSelectingFilteredRuleset() + { + var testMixed = createTestBeatmapSet(set_count + 1); + AddStep("add mixed ruleset beatmapset", () => + { + for (int i = 0; i <= 2; i++) + { + testMixed.Beatmaps[i].Ruleset = rulesets.AvailableRulesets.ElementAt(i); + testMixed.Beatmaps[i].RulesetID = i; + } + + carousel.UpdateBeatmapSet(testMixed); + }); + AddStep("filter to ruleset 0", () => + carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) }, false)); + AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testMixed.Beatmaps[1], false)); + AddAssert("unfiltered beatmap selected", () => carousel.SelectedBeatmap.Equals(testMixed.Beatmaps[0])); + + AddStep("remove mixed set", () => + { + carousel.RemoveBeatmapSet(testMixed); + testMixed = null; + }); + var testSingle = createTestBeatmapSet(set_count + 2); + testSingle.Beatmaps.ForEach(b => + { + b.Ruleset = rulesets.AvailableRulesets.ElementAt(1); + b.RulesetID = b.Ruleset.ID ?? 1; + }); + AddStep("add single ruleset beatmapset", () => carousel.UpdateBeatmapSet(testSingle)); + AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testSingle.Beatmaps[0], false)); + checkNoSelection(); + AddStep("remove single ruleset set", () => carousel.RemoveBeatmapSet(testSingle)); + } + private BeatmapSetInfo createTestBeatmapSet(int id) { return new BeatmapSetInfo diff --git a/osu.Game.Tests/Visual/TestCaseBreakOverlay.cs b/osu.Game.Tests/Visual/TestCaseBreakOverlay.cs index ae24d86325..51b8c61963 100644 --- a/osu.Game.Tests/Visual/TestCaseBreakOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseBreakOverlay.cs @@ -3,9 +3,9 @@ using osu.Framework.Timing; using osu.Game.Beatmaps.Timing; -using osu.Game.Screens.Play.BreaksOverlay; using System.Collections.Generic; using NUnit.Framework; +using osu.Game.Screens.Play; namespace osu.Game.Tests.Visual { diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index febe52d775..97d6225534 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -66,8 +66,10 @@ namespace osu.Game.Graphics.Containers { Vector2 offset = (input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2) * ParallaxAmount; - content.Position = Interpolation.ValueAt(MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000), content.Position, offset, 0, 1000, Easing.OutQuint); - content.Scale = new Vector2(1 + ParallaxAmount); + double elapsed = MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000); + + content.Position = Interpolation.ValueAt(elapsed, content.Position, offset, 0, 1000, Easing.OutQuint); + content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + ParallaxAmount), 0, 1000, Easing.OutQuint); } firstUpdate = false; diff --git a/osu.Game/Graphics/DrawableDate.cs b/osu.Game/Graphics/DrawableDate.cs new file mode 100644 index 0000000000..a912f989e0 --- /dev/null +++ b/osu.Game/Graphics/DrawableDate.cs @@ -0,0 +1,66 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using Humanizer; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Threading; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Graphics +{ + public class DrawableDate : OsuSpriteText, IHasTooltip + { + private readonly DateTimeOffset date; + private ScheduledDelegate updateTask; + + public DrawableDate(DateTimeOffset date) + { + AutoSizeAxes = Axes.Both; + Font = "Exo2.0-RegularItalic"; + + this.date = date.ToLocalTime(); + } + + [BackgroundDependencyLoader] + private void load() + { + updateTime(); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + Scheduler.Add(updateTimeWithReschedule); + } + + private void updateTimeWithReschedule() + { + updateTime(); + + var diffToNow = DateTimeOffset.Now.Subtract(date); + + double timeUntilNextUpdate = 1000; + if (diffToNow.TotalSeconds > 60) + { + timeUntilNextUpdate *= 60; + if (diffToNow.TotalMinutes > 60) + { + timeUntilNextUpdate *= 60; + + if (diffToNow.TotalHours > 24) + timeUntilNextUpdate *= 24; + } + } + + Scheduler.AddDelayed(updateTimeWithReschedule, timeUntilNextUpdate); + } + + public override bool HandleMouseInput => true; + + private void updateTime() => Text = date.Humanize(); + public string TooltipText => date.ToString(); + } +} diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index d085800f41..f4b363cd91 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -130,11 +130,7 @@ namespace osu.Game.Overlays.Profile } } }, - infoTextLeft = new OsuTextFlowContainer(t => - { - t.TextSize = 14; - t.Alpha = 0.8f; - }) + infoTextLeft = new OsuTextFlowContainer(t => t.TextSize = 14) { X = UserProfileOverlay.CONTENT_X_MARGIN, Y = cover_height + 20, @@ -318,11 +314,23 @@ namespace osu.Game.Overlays.Profile colourBar.Show(); } - void boldItalic(SpriteText t) + void boldItalic(SpriteText t) => t.Font = @"Exo2.0-BoldItalic"; + void lightText(SpriteText t) => t.Alpha = 0.8f; + + OsuSpriteText createScoreText(string text) => new OsuSpriteText { - t.Font = @"Exo2.0-BoldItalic"; - t.Alpha = 1; - } + TextSize = 14, + Text = text + }; + + OsuSpriteText createScoreNumberText(string text) => new OsuSpriteText + { + TextSize = 14, + Font = @"Exo2.0-Bold", + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Text = text + }; if (user.Age != null) { @@ -331,7 +339,7 @@ namespace osu.Game.Overlays.Profile if (user.Country != null) { - infoTextLeft.AddText("from "); + infoTextLeft.AddText("from ", lightText); infoTextLeft.AddText(user.Country.FullName, boldItalic); countryFlag.Country = user.Country; } @@ -344,18 +352,18 @@ namespace osu.Game.Overlays.Profile } else { - infoTextLeft.AddText("Joined "); - infoTextLeft.AddText(user.JoinDate.LocalDateTime.ToShortDateString(), boldItalic); + infoTextLeft.AddText("Joined ", lightText); + infoTextLeft.AddText(new DrawableDate(user.JoinDate), boldItalic); } infoTextLeft.NewLine(); - infoTextLeft.AddText("Last seen "); - infoTextLeft.AddText(user.LastVisit.LocalDateTime.ToShortDateString(), boldItalic); + infoTextLeft.AddText("Last seen ", lightText); + infoTextLeft.AddText(new DrawableDate(user.LastVisit), boldItalic); infoTextLeft.NewParagraph(); if (user.PlayStyle?.Length > 0) { - infoTextLeft.AddText("Plays with "); + infoTextLeft.AddText("Plays with ", lightText); infoTextLeft.AddText(string.Join(", ", user.PlayStyle), boldItalic); } @@ -411,23 +419,6 @@ namespace osu.Game.Overlays.Profile } } - // These could be local functions when C# 7 enabled - - private OsuSpriteText createScoreText(string text) => new OsuSpriteText - { - TextSize = 14, - Text = text - }; - - private OsuSpriteText createScoreNumberText(string text) => new OsuSpriteText - { - TextSize = 14, - Font = @"Exo2.0-Bold", - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Text = text - }; - private void tryAddInfoRightLine(FontAwesome icon, string str, string url = null) { if (string.IsNullOrEmpty(str)) return; @@ -436,10 +427,12 @@ namespace osu.Game.Overlays.Profile if (url != null) { infoTextRight.AddLink(" " + str, url); - } else + } + else { infoTextRight.AddText(" " + str); } + infoTextRight.NewLine(); } diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs index bb1a409f2e..509356ae04 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs @@ -54,12 +54,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks RightFlowContainer.SetLayoutPosition(text, 1); LeftFlowContainer.Add(new BeatmapMetadataContainer(Score.Beatmap)); - LeftFlowContainer.Add(new OsuSpriteText - { - Text = Score.Date.LocalDateTime.ToShortDateString(), - TextSize = 11, - Colour = OsuColour.Gray(0xAA), - }); + LeftFlowContainer.Add(new DrawableDate(Score.Date)); foreach (Mod mod in Score.Mods) modsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.5f) }); diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 2dde8a3d54..e8be8d1e44 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; 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; using osu.Game.Online.Chat; @@ -40,14 +39,12 @@ namespace osu.Game.Overlays.Profile.Sections.Recent RelativeSizeAxes = Axes.X, }); - RightFlowContainer.Add(new OsuSpriteText + RightFlowContainer.Add(new DrawableDate(activity.CreatedAt) { - Text = activity.CreatedAt.LocalDateTime.ToShortDateString(), + TextSize = 13, + Colour = OsuColour.Gray(0xAA), Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Font = "Exo2.0-RegularItalic", - TextSize = 12, - Colour = OsuColour.Gray(0xAA), }); var formatted = createMessage(); diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index c1bf55b214..a3811654f2 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Judgements @@ -20,15 +21,18 @@ namespace osu.Game.Rulesets.Judgements { protected readonly Judgement Judgement; + public readonly DrawableHitObject JudgedObject; + protected readonly SpriteText JudgementText; /// /// Creates a drawable which visualises a . /// /// The judgement to visualise. - public DrawableJudgement(Judgement judgement) + public DrawableJudgement(Judgement judgement, DrawableHitObject judgedObject) { Judgement = judgement; + JudgedObject = judgedObject; AutoSizeAxes = Axes.Both; diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 92fbf25f04..e621c3cf2b 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, (RulesetInfo)null)).ToList(); //add all legacy modes in correct order - foreach (var r in instances.Where(r => r.LegacyID >= 0).OrderBy(r => r.LegacyID)) + foreach (var r in instances.Where(r => r.LegacyID != null).OrderBy(r => r.LegacyID)) { if (context.RulesetInfo.SingleOrDefault(rsi => rsi.ID == r.RulesetInfo.ID) == null) context.RulesetInfo.Add(r.RulesetInfo); @@ -72,7 +72,7 @@ namespace osu.Game.Rulesets context.SaveChanges(); //add any other modes - foreach (var r in instances.Where(r => r.LegacyID < 0)) + foreach (var r in instances.Where(r => r.LegacyID == null)) if (context.RulesetInfo.FirstOrDefault(ri => ri.InstantiationInfo == r.RulesetInfo.InstantiationInfo) == null) context.RulesetInfo.Add(r.RulesetInfo); diff --git a/osu.Game/Rulesets/UI/JudgementContainer.cs b/osu.Game/Rulesets/UI/JudgementContainer.cs new file mode 100644 index 0000000000..1291b9fc98 --- /dev/null +++ b/osu.Game/Rulesets/UI/JudgementContainer.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Judgements; + +namespace osu.Game.Rulesets.UI +{ + public class JudgementContainer : Container + where T : DrawableJudgement + { + public override void Add(T judgement) + { + if (judgement == null) throw new ArgumentNullException(nameof(judgement)); + + // remove any existing judgements for the judged object. + // this can be the case when rewinding. + RemoveAll(c => c.JudgedObject == judgement.JudgedObject); + + base.Add(judgement); + } + } +} diff --git a/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs b/osu.Game/Screens/Play/Break/BlurredIcon.cs similarity index 92% rename from osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs rename to osu.Game/Screens/Play/Break/BlurredIcon.cs index 5395d7688e..6f47c97f89 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs +++ b/osu.Game/Screens/Play/Break/BlurredIcon.cs @@ -1,13 +1,13 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics; -using osu.Game.Graphics; using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using OpenTK; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play.Break { public class BlurredIcon : BufferedContainer { diff --git a/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs b/osu.Game/Screens/Play/Break/BreakArrows.cs similarity index 78% rename from osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs rename to osu.Game/Screens/Play/Break/BreakArrows.cs index 9fdf90bd28..f2a60cdddf 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs +++ b/osu.Game/Screens/Play/Break/BreakArrows.cs @@ -1,18 +1,15 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; -using OpenTK; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers; -using osu.Game.Beatmaps.Timing; +using OpenTK; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play.Break { - public class ArrowsOverlay : VisibilityContainer + public class BreakArrows : CompositeDrawable { - private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; - private const int glow_icon_size = 60; private const int glow_icon_blur_sigma = 10; private const float glow_icon_final_offset = 0.22f; @@ -29,10 +26,10 @@ namespace osu.Game.Screens.Play.BreaksOverlay private readonly BlurredIcon leftBlurredIcon; private readonly BlurredIcon rightBlurredIcon; - public ArrowsOverlay() + public BreakArrows() { RelativeSizeAxes = Axes.Both; - Children = new Drawable[] + InternalChildren = new Drawable[] { leftGlowIcon = new GlowIcon { @@ -82,22 +79,22 @@ namespace osu.Game.Screens.Play.BreaksOverlay }; } - protected override void PopIn() + public void Show(double duration) { - leftGlowIcon.MoveToX(-glow_icon_final_offset, fade_duration, Easing.OutQuint); - rightGlowIcon.MoveToX(glow_icon_final_offset, fade_duration, Easing.OutQuint); + leftGlowIcon.MoveToX(-glow_icon_final_offset, duration, Easing.OutQuint); + rightGlowIcon.MoveToX(glow_icon_final_offset, duration, Easing.OutQuint); - leftBlurredIcon.MoveToX(-blurred_icon_final_offset, fade_duration, Easing.OutQuint); - rightBlurredIcon.MoveToX(blurred_icon_final_offset, fade_duration, Easing.OutQuint); + leftBlurredIcon.MoveToX(-blurred_icon_final_offset, duration, Easing.OutQuint); + rightBlurredIcon.MoveToX(blurred_icon_final_offset, duration, Easing.OutQuint); } - protected override void PopOut() + public void Hide(double duration) { - leftGlowIcon.MoveToX(-glow_icon_offscreen_offset, fade_duration, Easing.OutQuint); - rightGlowIcon.MoveToX(glow_icon_offscreen_offset, fade_duration, Easing.OutQuint); + leftGlowIcon.MoveToX(-glow_icon_offscreen_offset, duration, Easing.OutQuint); + rightGlowIcon.MoveToX(glow_icon_offscreen_offset, duration, Easing.OutQuint); - leftBlurredIcon.MoveToX(-blurred_icon_offscreen_offset, fade_duration, Easing.OutQuint); - rightBlurredIcon.MoveToX(blurred_icon_offscreen_offset, fade_duration, Easing.OutQuint); + leftBlurredIcon.MoveToX(-blurred_icon_offscreen_offset, duration, Easing.OutQuint); + rightBlurredIcon.MoveToX(blurred_icon_offscreen_offset, duration, Easing.OutQuint); } } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs b/osu.Game/Screens/Play/Break/BreakInfo.cs similarity index 62% rename from osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs rename to osu.Game/Screens/Play/Break/BreakInfo.cs index d7ab4ff2e5..5e011903fe 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs +++ b/osu.Game/Screens/Play/Break/BreakInfo.cs @@ -1,24 +1,21 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Scoring; -using osu.Game.Beatmaps.Timing; +using OpenTK; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play.Break { - public class InfoContainer : VisibilityContainer + public class BreakInfo : Container { - private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; + public PercentageBreakInfoLine AccuracyDisplay; + public BreakInfoLine RankDisplay; + public BreakInfoLine GradeDisplay; - public PercentageInfoLine AccuracyDisplay; - public InfoLine RankDisplay; - public InfoLine GradeDisplay; - - public InfoContainer() + public BreakInfo() { AutoSizeAxes = Axes.Both; Child = new FillFlowContainer @@ -43,16 +40,13 @@ namespace osu.Game.Screens.Play.BreaksOverlay Direction = FillDirection.Vertical, Children = new Drawable[] { - AccuracyDisplay = new PercentageInfoLine("Accuracy"), - RankDisplay = new InfoLine("Rank"), - GradeDisplay = new InfoLine("Grade"), + AccuracyDisplay = new PercentageBreakInfoLine("Accuracy"), + RankDisplay = new BreakInfoLine("Rank"), + GradeDisplay = new BreakInfoLine("Grade"), }, } }, }; } - - protected override void PopIn() => this.FadeIn(fade_duration); - protected override void PopOut() => this.FadeOut(fade_duration); } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs b/osu.Game/Screens/Play/Break/BreakInfoLine.cs similarity index 84% rename from osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs rename to osu.Game/Screens/Play/Break/BreakInfoLine.cs index b39eaf1c22..3d96bca1fa 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs +++ b/osu.Game/Screens/Play/Break/BreakInfoLine.cs @@ -8,9 +8,9 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play.Break { - public class InfoLine : Container + public class BreakInfoLine : Container where T : struct { private const int margin = 2; @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay private readonly string prefix; - public InfoLine(string name, string prefix = @"") + public BreakInfoLine(string name, string prefix = @"") { this.prefix = prefix; @@ -71,9 +71,9 @@ namespace osu.Game.Screens.Play.BreaksOverlay } } - public class PercentageInfoLine : InfoLine + public class PercentageBreakInfoLine : BreakInfoLine { - public PercentageInfoLine(string name, string prefix = "") : base(name, prefix) + public PercentageBreakInfoLine(string name, string prefix = "") : base(name, prefix) { } diff --git a/osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs b/osu.Game/Screens/Play/Break/GlowIcon.cs similarity index 93% rename from osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs rename to osu.Game/Screens/Play/Break/GlowIcon.cs index bad9df2093..79b39a873a 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs +++ b/osu.Game/Screens/Play/Break/GlowIcon.cs @@ -1,13 +1,13 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Graphics.Containers; +using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using OpenTK; -using osu.Framework.Allocation; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play.Break { public class GlowIcon : Container { @@ -16,24 +16,24 @@ namespace osu.Game.Screens.Play.BreaksOverlay public override Vector2 Size { + get { return base.Size; } set { blurredIcon.Size = spriteIcon.Size = value; blurredIcon.ForceRedraw(); } - get { return base.Size; } } public Vector2 BlurSigma { - set { blurredIcon.BlurSigma = value; } get { return blurredIcon.BlurSigma; } + set { blurredIcon.BlurSigma = value; } } public FontAwesome Icon { - set { spriteIcon.Icon = blurredIcon.Icon = value; } get { return spriteIcon.Icon; } + set { spriteIcon.Icon = blurredIcon.Icon = value; } } public GlowIcon() diff --git a/osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs b/osu.Game/Screens/Play/Break/LetterboxOverlay.cs similarity index 77% rename from osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs rename to osu.Game/Screens/Play/Break/LetterboxOverlay.cs index f4c9362fff..21eb5ebea0 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs +++ b/osu.Game/Screens/Play/Break/LetterboxOverlay.cs @@ -1,18 +1,16 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK.Graphics; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Game.Beatmaps.Timing; +using OpenTK.Graphics; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play.Break { - public class LetterboxOverlay : VisibilityContainer + public class LetterboxOverlay : CompositeDrawable { - private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; private const int height = 350; private static readonly Color4 transparent_black = new Color4(0, 0, 0, 0); @@ -20,7 +18,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay public LetterboxOverlay() { RelativeSizeAxes = Axes.Both; - Children = new Drawable[] + InternalChildren = new Drawable[] { new Container { @@ -48,8 +46,5 @@ namespace osu.Game.Screens.Play.BreaksOverlay } }; } - - protected override void PopIn() => this.FadeIn(fade_duration); - protected override void PopOut() => this.FadeOut(fade_duration); } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs b/osu.Game/Screens/Play/Break/RemainingTimeCounter.cs similarity index 70% rename from osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs rename to osu.Game/Screens/Play/Break/RemainingTimeCounter.cs index 015fefb423..f6e683f519 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs +++ b/osu.Game/Screens/Play/Break/RemainingTimeCounter.cs @@ -1,18 +1,15 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Game.Graphics.Sprites; -using osu.Framework.Graphics; using System; -using osu.Game.Beatmaps.Timing; +using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.Sprites; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play.Break { public class RemainingTimeCounter : Counter { - private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; - private readonly OsuSpriteText counter; public RemainingTimeCounter() @@ -25,13 +22,8 @@ namespace osu.Game.Screens.Play.BreaksOverlay TextSize = 33, Font = "Venera", }; - - Alpha = 0; } protected override void OnCountChanged(double count) => counter.Text = ((int)Math.Ceiling(count / 1000)).ToString(); - - public override void Show() => this.FadeIn(fade_duration); - public override void Hide() => this.FadeOut(fade_duration); } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreakOverlay.cs similarity index 51% rename from osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs rename to osu.Game/Screens/Play/BreakOverlay.cs index af7c1ef5aa..6c7ee596a1 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreakOverlay.cs @@ -1,15 +1,16 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Scoring; -using System.Collections.Generic; -using osu.Framework.Graphics.UserInterface; +using osu.Game.Screens.Play.Break; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play { public class BreakOverlay : Container { @@ -18,28 +19,26 @@ namespace osu.Game.Screens.Play.BreaksOverlay private const int vertical_margin = 25; private List breaks; + + private readonly Container fadeContainer; + public List Breaks { + get => breaks; set { breaks = value; initializeBreaks(); } - get - { - return breaks; - } } public override bool RemoveCompletedTransforms => false; - private readonly bool letterboxing; - private readonly LetterboxOverlay letterboxOverlay; private readonly Container remainingTimeAdjustmentBox; private readonly Container remainingTimeBox; private readonly RemainingTimeCounter remainingTimeCounter; - private readonly InfoContainer info; - private readonly ArrowsOverlay arrowsOverlay; + private readonly BreakInfo info; + private readonly BreakArrows breakArrows; public BreakOverlay(bool letterboxing, ScoreProcessor scoreProcessor) : this(letterboxing) @@ -49,61 +48,72 @@ namespace osu.Game.Screens.Play.BreaksOverlay public BreakOverlay(bool letterboxing) { - this.letterboxing = letterboxing; - RelativeSizeAxes = Axes.Both; - Children = new Drawable[] + Child = fadeContainer = new Container { - letterboxOverlay = new LetterboxOverlay + Alpha = 0, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - remainingTimeAdjustmentBox = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Width = 0, - Child = remainingTimeBox = new Container + new LetterboxOverlay + { + Alpha = letterboxing ? 1 : 0, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + remainingTimeAdjustmentBox = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, + AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, - Height = 8, - CornerRadius = 4, - Masking = true, - Child = new Box { RelativeSizeAxes = Axes.Both } + Width = 0, + Child = remainingTimeBox = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + Height = 8, + CornerRadius = 4, + Masking = true, + Child = new Box { RelativeSizeAxes = Axes.Both } + } + }, + remainingTimeCounter = new RemainingTimeCounter + { + Anchor = Anchor.Centre, + Origin = Anchor.BottomCentre, + Margin = new MarginPadding { Bottom = vertical_margin }, + }, + info = new BreakInfo + { + Anchor = Anchor.Centre, + Origin = Anchor.TopCentre, + Margin = new MarginPadding { Top = vertical_margin }, + }, + breakArrows = new BreakArrows + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, } - }, - remainingTimeCounter = new RemainingTimeCounter - { - Anchor = Anchor.Centre, - Origin = Anchor.BottomCentre, - Margin = new MarginPadding { Bottom = vertical_margin }, - }, - info = new InfoContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.TopCentre, - Margin = new MarginPadding { Top = vertical_margin }, - }, - arrowsOverlay = new ArrowsOverlay - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, } }; } + protected override void LoadComplete() + { + base.LoadComplete(); + initializeBreaks(); + } + private void initializeBreaks() { + if (!IsLoaded) return; // we need a clock. + FinishTransforms(true); Scheduler.CancelDelayedTasks(); - if (breaks == null) - return; + if (breaks == null) return; //we need breaks. foreach (var b in breaks) { @@ -112,6 +122,9 @@ namespace osu.Game.Screens.Play.BreaksOverlay using (BeginAbsoluteSequence(b.StartTime, true)) { + fadeContainer.FadeIn(fade_duration); + breakArrows.Show(fade_duration); + remainingTimeAdjustmentBox .ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint) .Delay(b.Duration - fade_duration) @@ -123,37 +136,16 @@ namespace osu.Game.Screens.Play.BreaksOverlay .ResizeWidthTo(1); remainingTimeCounter.CountTo(b.Duration).CountTo(0, b.Duration); - } - using (BeginAbsoluteSequence(b.StartTime)) - { - Schedule(showBreak); - using (BeginDelayedSequence(b.Duration - fade_duration)) - Schedule(hideBreak); + using (BeginDelayedSequence(b.Duration - fade_duration, true)) + { + fadeContainer.FadeOut(fade_duration); + breakArrows.Hide(fade_duration); + } } } } - private void showBreak() - { - if (letterboxing) - letterboxOverlay.Show(); - - remainingTimeCounter.Show(); - info.Show(); - arrowsOverlay.Show(); - } - - private void hideBreak() - { - if (letterboxing) - letterboxOverlay.Hide(); - - remainingTimeCounter.Hide(); - info.Hide(); - arrowsOverlay.Hide(); - } - private void bindProcessor(ScoreProcessor processor) { info.AccuracyDisplay.Current.BindTo(processor.Accuracy); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index d24ed53518..c8ff261a93 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -25,7 +25,6 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; -using osu.Game.Screens.Play.BreaksOverlay; using osu.Game.Screens.Ranking; using osu.Game.Storyboards.Drawables; diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 9793440348..c2bb155753 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -169,20 +169,43 @@ namespace osu.Game.Screens.Select }); } - public void SelectBeatmap(BeatmapInfo beatmap) + /// + /// Selects a given beatmap on the carousel. + /// + /// If bypassFilters is false, we will try to select another unfiltered beatmap in the same set. If the + /// entire set is filtered, no selection is made. + /// + /// The beatmap to select. + /// Whether to select the beatmap even if it is filtered (i.e., not visible on carousel). + /// True if a selection was made, False if it wasn't. + public bool SelectBeatmap(BeatmapInfo beatmap, bool bypassFilters = true) { if (beatmap?.Hidden != false) - return; + return false; - foreach (CarouselBeatmapSet group in beatmapSets) + foreach (CarouselBeatmapSet set in beatmapSets) { - var item = group.Beatmaps.FirstOrDefault(p => p.Beatmap.Equals(beatmap)); + if (!bypassFilters && set.Filtered) + continue; + + var item = set.Beatmaps.FirstOrDefault(p => p.Beatmap.Equals(beatmap)); + + if (item == null) + // The beatmap that needs to be selected doesn't exist in this set + continue; + + if (!bypassFilters && item.Filtered) + // The beatmap exists in this set but is filtered, so look for the first unfiltered map in the set + item = set.Beatmaps.FirstOrDefault(b => !b.Filtered); + if (item != null) { select(item); - return; + return true; } } + + return false; } /// diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 43d7cb637a..ca8a1cae41 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -214,11 +214,7 @@ namespace osu.Game.Screens.Select Beatmap.DisabledChanged += disabled => Carousel.AllowSelection = !disabled; Beatmap.TriggerChange(); - Beatmap.ValueChanged += b => - { - if (IsCurrentScreen) - Carousel.SelectBeatmap(b?.BeatmapInfo); - }; + Beatmap.ValueChanged += workingBeatmapChanged; } public void Edit(BeatmapInfo beatmap) @@ -261,6 +257,17 @@ namespace osu.Game.Screens.Select // We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds. private BeatmapInfo beatmapNoDebounce; + private void workingBeatmapChanged(WorkingBeatmap beatmap) + { + if (IsCurrentScreen && !Carousel.SelectBeatmap(beatmap?.BeatmapInfo, false)) + // If selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch + if (beatmap?.BeatmapInfo?.Ruleset != null && beatmap.BeatmapInfo.Ruleset != Ruleset.Value) + { + Ruleset.Value = beatmap.BeatmapInfo.Ruleset; + Carousel.SelectBeatmap(beatmap.BeatmapInfo); + } + } + /// /// selection has been changed as the result of interaction with the carousel. /// @@ -450,16 +457,14 @@ namespace osu.Game.Screens.Select private void carouselBeatmapsLoaded() { - if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false) + if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false && Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false)) + return; + + if (Carousel.SelectedBeatmapSet == null && !Carousel.SelectNextRandom()) { - Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo); - } - else if (Carousel.SelectedBeatmapSet == null) - { - if (!Carousel.SelectNextRandom()) - // in the case random selection failed, we want to trigger selectionChanged - // to show the dummy beatmap (we have nothing else to display). - carouselSelectionChanged(null); + // in the case random selection failed, we want to trigger selectionChanged + // to show the dummy beatmap (we have nothing else to display). + carouselSelectionChanged(null); } } diff --git a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs index 5b32433467..7ca69c14b8 100644 --- a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs +++ b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs @@ -128,7 +128,7 @@ namespace osu.Game.Tests.Visual private void load(BeatmapManager beatmaps) { var sets = beatmaps.GetAllUsableBeatmapSets(); - var allBeatmaps = sets.SelectMany(s => s.Beatmaps).Where(b => ruleset.LegacyID < 0 || b.RulesetID == ruleset.LegacyID); + var allBeatmaps = sets.SelectMany(s => s.Beatmaps).Where(b => ruleset.LegacyID == null || b.RulesetID == ruleset.LegacyID); allBeatmaps.ForEach(b => beatmapDisplays.Add(new BeatmapDisplay(b))); } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index d10f0085cc..1d3baa6c0d 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -287,6 +287,7 @@ + @@ -378,6 +379,7 @@ + @@ -409,14 +411,14 @@ - - - - - - - - + + + + + + + +