diff --git a/osu.Android.props b/osu.Android.props index 939d179b1d..24afbb86fb 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -54,6 +54,6 @@ - + diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs index 56e378d19e..20911b8d06 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs @@ -29,6 +29,12 @@ namespace osu.Game.Rulesets.Catch.Tests { } + [Test] + public void TestBananaShower() + { + AddUntilStep("player is done", () => !Player.ValidForResume); + } + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) { var beatmap = new Beatmap @@ -40,7 +46,7 @@ namespace osu.Game.Rulesets.Catch.Tests } }; - beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 5000, NewCombo = true }); + beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 3000, NewCombo = true }); return beatmap; } diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs new file mode 100644 index 0000000000..cbc87459e1 --- /dev/null +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs @@ -0,0 +1,56 @@ +// 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 NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Tests.Visual; +using osuTK; + +namespace osu.Game.Rulesets.Catch.Tests +{ + public class TestSceneJuiceStream : PlayerTestScene + { + public TestSceneJuiceStream() + : base(new CatchRuleset()) + { + } + + [Test] + public void TestJuiceStreamEndingCombo() + { + AddUntilStep("player is done", () => !Player.ValidForResume); + } + + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + BaseDifficulty = new BeatmapDifficulty { CircleSize = 5, SliderMultiplier = 2 }, + Ruleset = ruleset + }, + HitObjects = new List + { + new JuiceStream + { + X = 0.5f, + Path = new SliderPath(PathType.Linear, new[] + { + Vector2.Zero, + new Vector2(0, 100) + }), + StartTime = 200 + }, + new Banana + { + X = 0.5f, + StartTime = 1000, + NewCombo = true + } + } + }; + } +} diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs index 0c754412e5..c3488aec11 100644 --- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs +++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Rulesets.Catch.Objects @@ -11,6 +12,8 @@ namespace osu.Game.Rulesets.Catch.Objects public override bool LastInCombo => true; + public override Judgement CreateJudgement() => new IgnoreJudgement(); + protected override void CreateNestedHitObjects() { base.CreateNestedHitObjects(); diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 11e2466275..642ff0246e 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -7,6 +7,7 @@ using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; @@ -19,6 +20,8 @@ namespace osu.Game.Rulesets.Catch.Objects /// private const float base_scoring_distance = 100; + public override Judgement CreateJudgement() => new IgnoreJudgement(); + public int RepeatCount { get; set; } public double Velocity; diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index ff2471f8bf..0b3809150a 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -89,7 +89,7 @@ namespace osu.Game.Rulesets.Catch.UI if (fruit.HitObject.LastInCombo) { - if (((CatchJudgement)result.Judgement).ShouldExplodeFor(result)) + if (result.Judgement is CatchJudgement catchJudgement && catchJudgement.ShouldExplodeFor(result)) runAfterLoaded(() => MovableCatcher.Explode()); else MovableCatcher.Drop(); diff --git a/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs deleted file mode 100644 index e8b48768a1..0000000000 --- a/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs +++ /dev/null @@ -1,14 +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.Rulesets.Scoring; - -namespace osu.Game.Rulesets.Mania.Judgements -{ - public class HoldNoteJudgement : ManiaJudgement - { - public override bool AffectsCombo => false; - - protected override int NumericResultFor(HitResult result) => 0; - } -} diff --git a/osu.Game.Rulesets.Mania/Objects/BarLine.cs b/osu.Game.Rulesets.Mania/Objects/BarLine.cs index 0981b028b2..09a746042b 100644 --- a/osu.Game.Rulesets.Mania/Objects/BarLine.cs +++ b/osu.Game.Rulesets.Mania/Objects/BarLine.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Mania.Objects @@ -8,5 +9,7 @@ namespace osu.Game.Rulesets.Mania.Objects public class BarLine : ManiaHitObject, IBarLine { public bool Major { get; set; } + + public override Judgement CreateJudgement() => new IgnoreJudgement(); } } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs index 56bc797c7f..08b5b75f9c 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs @@ -71,8 +71,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables { } - protected override void UpdateStateTransforms(ArmedState state) - { - } + protected override void UpdateStateTransforms(ArmedState state) => this.FadeOut(150); } } diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 86d3d2b2b0..049bf55f90 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -4,7 +4,6 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Scoring; @@ -103,7 +102,7 @@ namespace osu.Game.Rulesets.Mania.Objects } } - public override Judgement CreateJudgement() => new HoldNoteJudgement(); + public override Judgement CreateJudgement() => new IgnoreJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; } diff --git a/osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.cs b/osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.cs deleted file mode 100644 index 5104d9494b..0000000000 --- a/osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.cs +++ /dev/null @@ -1,14 +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.Rulesets.Scoring; - -namespace osu.Game.Rulesets.Osu.Judgements -{ - public class OsuSliderTailJudgement : OsuJudgement - { - public override bool AffectsCombo => false; - - protected override int NumericResultFor(HitResult result) => 0; - } -} diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs index a5e89210f6..921b23cb13 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs @@ -20,6 +20,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections private const int spacing = 32; private const double preempt = 800; + public override bool RemoveWhenNotAlive => false; + /// /// The start time of . /// @@ -79,27 +81,31 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections drawableObject.HitObject.DefaultsApplied += scheduleRefresh; } - private void scheduleRefresh() => Scheduler.AddOnce(refresh); + private void scheduleRefresh() + { + Scheduler.AddOnce(refresh); + } private void refresh() { ClearInternal(); - if (End == null) - return; - OsuHitObject osuStart = Start.HitObject; - OsuHitObject osuEnd = End.HitObject; + double startTime = osuStart.GetEndTime(); - if (osuEnd.NewCombo) - return; + LifetimeStart = startTime; - if (osuStart is Spinner || osuEnd is Spinner) + OsuHitObject osuEnd = End?.HitObject; + + if (osuEnd == null || osuEnd.NewCombo || osuStart is Spinner || osuEnd is Spinner) + { + // ensure we always set a lifetime for full LifetimeManagementContainer benefits + LifetimeEnd = LifetimeStart; return; + } Vector2 startPosition = osuStart.EndPosition; Vector2 endPosition = osuEnd.Position; - double startTime = osuStart.GetEndTime(); double endTime = osuEnd.StartTime; Vector2 distanceVector = endPosition - startPosition; @@ -107,6 +113,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections float rotation = (float)(Math.Atan2(distanceVector.Y, distanceVector.X) * (180 / Math.PI)); double duration = endTime - startTime; + double? firstTransformStartTime = null; + double finalTransformEndTime = startTime; + for (int d = (int)(spacing * 1.5); d < distance - spacing; d += spacing) { float fraction = (float)d / distance; @@ -125,16 +134,23 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections Scale = new Vector2(1.5f * osuEnd.Scale), }); + if (firstTransformStartTime == null) + firstTransformStartTime = fadeInTime; + using (fp.BeginAbsoluteSequence(fadeInTime)) { fp.FadeIn(osuEnd.TimeFadeIn); fp.ScaleTo(osuEnd.Scale, osuEnd.TimeFadeIn, Easing.Out); fp.MoveTo(pointEndPosition, osuEnd.TimeFadeIn, Easing.Out); fp.Delay(fadeOutTime - fadeInTime).FadeOut(osuEnd.TimeFadeIn); - } - fp.Expire(true); + finalTransformEndTime = fadeOutTime + osuEnd.TimeFadeIn; + } } + + // todo: use Expire() on FollowPoints and take lifetime from them when https://github.com/ppy/osu-framework/issues/3300 is fixed. + LifetimeStart = firstTransformStartTime ?? startTime; + LifetimeEnd = finalTransformEndTime; } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs index be192080f9..4d73e711bb 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections /// /// Visualises connections between s. /// - public class FollowPointRenderer : CompositeDrawable + public class FollowPointRenderer : LifetimeManagementContainer { /// /// All the s contained by this . @@ -45,8 +45,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections /// The index of in . private void addConnection(FollowPointConnection connection) { - AddInternal(connection); - // Groups are sorted by their start time when added such that the index can be used to post-process other surrounding connections int index = connections.AddInPlace(connection, Comparer.Create((g1, g2) => g1.StartTime.Value.CompareTo(g2.StartTime.Value))); @@ -74,6 +72,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections FollowPointConnection previousConnection = connections[index - 1]; previousConnection.End = connection.Start; } + + AddInternal(connection); } /// diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs index c17d2275b8..127c36fcc0 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs @@ -4,7 +4,6 @@ using osu.Framework.Bindables; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu.Objects @@ -23,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects pathVersion.BindValueChanged(_ => Position = slider.EndPosition); } - public override Judgement CreateJudgement() => new OsuSliderTailJudgement(); + public override Judgement CreateJudgement() => new IgnoreJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; } diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs index f27e329e8e..ccacc50de1 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs @@ -8,7 +8,6 @@ using osu.Framework.Allocation; using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.Taiko.Judgements; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Screens.Play; using osu.Game.Tests.Visual; @@ -28,7 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Tests public void TestZeroTickTimeOffsets() { AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted); - AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.Judgement is TaikoSwellTickJudgement).All(r => r.TimeOffset == 0)); + AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.HitObject is SwellTick).All(r => r.TimeOffset == 0)); } protected override bool Autoplay => true; diff --git a/osu.Game.Rulesets.Taiko/Objects/BarLine.cs b/osu.Game.Rulesets.Taiko/Objects/BarLine.cs index 2afbbc737c..6306195704 100644 --- a/osu.Game.Rulesets.Taiko/Objects/BarLine.cs +++ b/osu.Game.Rulesets.Taiko/Objects/BarLine.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Taiko.Objects @@ -8,5 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Objects public class BarLine : TaikoHitObject, IBarLine { public bool Major { get; set; } + + public override Judgement CreateJudgement() => new IgnoreJudgement(); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs index 1a5a797f28..e9caabbcc8 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs @@ -54,5 +54,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables Alpha = 0.75f }); } + + protected override void UpdateStateTransforms(ArmedState state) => this.FadeOut(150); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs index 91f4d3dbe7..bdc0478195 100644 --- a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs @@ -3,13 +3,12 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.Taiko.Judgements; namespace osu.Game.Rulesets.Taiko.Objects { public class SwellTick : TaikoHitObject { - public override Judgement CreateJudgement() => new TaikoSwellTickJudgement(); + public override Judgement CreateJudgement() => new IgnoreJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; } diff --git a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs index 244e37f017..885abb61b5 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs @@ -154,6 +154,7 @@ namespace osu.Game.Tests.Gameplay private class JudgeableHitObject : HitObject { public override Judgement CreateJudgement() => new Judgement(); + protected override HitWindows CreateHitWindows() => new HitWindows(); } } } diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs index 17dc27543d..7a89642e11 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs @@ -11,8 +11,8 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; using osu.Framework.Testing; using osu.Game.Audio; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Objects.Types; using osu.Game.Skinning; using osu.Game.Tests.Visual; @@ -78,7 +78,7 @@ namespace osu.Game.Tests.Gameplay } } - private class TestHitObjectWithCombo : HitObject, IHasComboInformation + private class TestHitObjectWithCombo : ConvertHitObject, IHasComboInformation { public bool NewCombo { get; } = false; public int ComboOffset { get; } = 0; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs index 46f62b9541..b25b81c9af 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs @@ -20,6 +20,7 @@ using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.UI; @@ -289,7 +290,7 @@ namespace osu.Game.Tests.Visual.Gameplay #region HitObject - private class TestHitObject : HitObject, IHasEndTime + private class TestHitObject : ConvertHitObject, IHasEndTime { public double EndTime { get; set; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs index 8904b54b0d..1527cba6fc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs @@ -2,16 +2,17 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; -using osu.Game.Rulesets.Objects; using System; using System.Collections.Generic; using osu.Game.Rulesets.Judgements; using osu.Framework.Utils; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Threading; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Catch.Scoring; using osu.Game.Rulesets.Mania.Scoring; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Scoring; @@ -43,6 +44,22 @@ namespace osu.Game.Tests.Visual.Gameplay AddRepeatStep("New max negative", () => newJudgement(-hitWindows.WindowFor(HitResult.Meh)), 20); AddRepeatStep("New max positive", () => newJudgement(hitWindows.WindowFor(HitResult.Meh)), 20); AddStep("New fixed judgement (50ms)", () => newJudgement(50)); + + AddStep("Judgement barrage", () => + { + int runCount = 0; + + ScheduledDelegate del = null; + + del = Scheduler.AddDelayed(() => + { + newJudgement(runCount++ / 10f); + + if (runCount == 500) + // ReSharper disable once AccessToModifiedClosure + del?.Cancel(); + }, 10, true); + }); } [Test] diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs index 0ed8864860..a28a0107a1 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs @@ -13,6 +13,8 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using osuTK; +using JetBrains.Annotations; +using NUnit.Framework; namespace osu.Game.Tests.Visual.Online { @@ -30,6 +32,8 @@ namespace osu.Game.Tests.Visual.Online private readonly BindableBool showDeleted = new BindableBool(); private readonly Container content; + private TestCommentsPage commentsPage; + public TestSceneCommentsPage() { Add(new FillFlowContainer @@ -57,15 +61,29 @@ namespace osu.Game.Tests.Visual.Online } } }); + } - AddStep("load comments", () => createPage(getCommentBundle())); - AddStep("load empty comments", () => createPage(getEmptyCommentBundle())); + [Test] + public void TestAppendDuplicatedComment() + { + AddStep("Create page", () => createPage(getCommentBundle())); + AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10); + AddStep("Append existing comment", () => commentsPage?.AppendComments(getCommentSubBundle())); + AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10); + } + + [Test] + public void TestEmptyBundle() + { + AddStep("Create page", () => createPage(getEmptyCommentBundle())); + AddAssert("Dictionary length is 0", () => commentsPage?.DictionaryLength == 0); } private void createPage(CommentBundle commentBundle) { + commentsPage = null; content.Clear(); - content.Add(new CommentsPage(commentBundle) + content.Add(commentsPage = new TestCommentsPage(commentBundle) { ShowDeleted = { BindTarget = showDeleted } }); @@ -182,5 +200,33 @@ namespace osu.Game.Tests.Visual.Online } }, }; + + private CommentBundle getCommentSubBundle() => new CommentBundle + { + Comments = new List + { + new Comment + { + Id = 1, + Message = "Simple test comment", + LegacyName = "TestUser1", + CreatedAt = DateTimeOffset.Now, + VotesCount = 5 + }, + }, + IncludedComments = new List(), + }; + + private class TestCommentsPage : CommentsPage + { + public TestCommentsPage(CommentBundle commentBundle) + : base(commentBundle) + { + } + + public new void AppendComments([NotNull] CommentBundle bundle) => base.AppendComments(bundle); + + public int DictionaryLength => CommentDictionary.Count; + } } } diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs index f49d7a14a6..e02ebf3be1 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Taiko; @@ -194,7 +195,7 @@ namespace osu.Game.Tests.Visual.SongSelect public new BufferedWedgeInfo Info => base.Info; } - private class TestHitObject : HitObject, IHasPosition + private class TestHitObject : ConvertHitObject, IHasPosition { public float X { get; } = 0; public float Y { get; } = 0; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs new file mode 100644 index 0000000000..02b8839922 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs @@ -0,0 +1,57 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; +using osu.Game.Overlays.Home.Friends; +using osuTK; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneUserListToolbar : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(UserSortTabControl), + typeof(OverlaySortTabControl<>), + typeof(OverlayPanelDisplayStyleControl), + typeof(UserListToolbar), + }; + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + + public TestSceneUserListToolbar() + { + UserListToolbar toolbar; + OsuSpriteText sort; + OsuSpriteText displayStyle; + + Add(toolbar = new UserListToolbar + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + + Add(new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 5), + Children = new Drawable[] + { + sort = new OsuSpriteText(), + displayStyle = new OsuSpriteText() + } + }); + + toolbar.SortCriteria.BindValueChanged(criteria => sort.Text = $"Criteria: {criteria.NewValue}", true); + toolbar.DisplayStyle.BindValueChanged(style => displayStyle.Text = $"Style: {style.NewValue}", true); + } + } +} diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index 25a62acaba..35b33c3d03 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -64,7 +64,7 @@ namespace osu.Game.Graphics.UserInterface protected override void Update() { base.Update(); - MainContents.Size = new Vector2(Math.Min(100, Math.Min(DrawWidth, DrawHeight) * 0.25f)); + MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 30, 100)); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs index b5a235f9d8..36d429b8c1 100644 --- a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs +++ b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs @@ -93,7 +93,7 @@ namespace osu.Game.Graphics.UserInterface private void rotate() { - spinner.Spin(spin_duration * 4, RotationDirection.Clockwise); + spinner.Spin(spin_duration * 3.5f, RotationDirection.Clockwise); MainContents.RotateTo(0).Then() .RotateTo(90, spin_duration, Easing.InOutQuart).Then() diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs new file mode 100644 index 0000000000..e6d433f7bc --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs @@ -0,0 +1,29 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Overlays.BeatmapSet +{ + public class BeatmapSetLayoutSection : Container + { + public BeatmapSetLayoutSection() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Masking = true; + EdgeEffect = new EdgeEffectParameters + { + Colour = Color4.Black.Opacity(0.25f), + Type = EdgeEffectType.Shadow, + Radius = 3, + Offset = new Vector2(0f, 1f), + }; + } + } +} diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 0f2d6a9e35..bac658b76e 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -3,17 +3,14 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osuTK; -using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapSet { @@ -43,14 +40,6 @@ namespace osu.Game.Overlays.BeatmapSet RelativeSizeAxes = Axes.X; Height = base_height; - Masking = true; - EdgeEffect = new EdgeEffectParameters - { - Colour = Color4.Black.Opacity(0.25f), - Type = EdgeEffectType.Shadow, - Radius = 3, - Offset = new Vector2(0f, 1f), - }; Children = new Drawable[] { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index e831c8ce42..7607eac1f8 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -19,7 +19,7 @@ using osu.Game.Users; namespace osu.Game.Overlays.BeatmapSet.Scores { - public class ScoresContainer : CompositeDrawable + public class ScoresContainer : BeatmapSetLayoutSection { private const int spacing = 15; @@ -34,7 +34,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private readonly LoadingLayer loading; private readonly LeaderboardModSelector modSelector; private readonly NoScoresPlaceholder noScoresPlaceholder; - private readonly FillFlowContainer content; private readonly NotSupporterPlaceholder notSupporterPlaceholder; [Resolved] @@ -76,15 +75,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores public ScoresContainer() { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - InternalChildren = new Drawable[] + AddRange(new Drawable[] { background = new Box { RelativeSizeAxes = Axes.Both, }, - content = new FillFlowContainer + new FillFlowContainer { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, @@ -164,8 +161,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } } } - }, - }; + } + }); } [BackgroundDependencyLoader] @@ -223,7 +220,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores if (Beatmap.Value?.OnlineBeatmapID.HasValue != true || Beatmap.Value.Status <= BeatmapSetOnlineStatus.Pending) { Scores = null; - content.Hide(); + Hide(); return; } @@ -237,7 +234,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores notSupporterPlaceholder.Hide(); - content.Show(); + Show(); loading.Show(); getScoresRequest = new GetScoresRequest(Beatmap.Value, Beatmap.Value.Ruleset, scope.Value, modSelector.SelectedMods); diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index d29997f7e5..0d16c4842d 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -13,6 +13,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests; using osu.Game.Overlays.BeatmapSet; using osu.Game.Overlays.BeatmapSet.Scores; +using osu.Game.Overlays.Comments; using osu.Game.Rulesets; using osuTK; @@ -40,6 +41,7 @@ namespace osu.Game.Overlays { OsuScrollContainer scroll; Info info; + CommentsSection comments; Children = new Drawable[] { @@ -51,29 +53,33 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.Both, ScrollbarVisible = false, - Child = new ReverseChildIDFillFlowContainer + Child = new ReverseChildIDFillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, Spacing = new Vector2(0, 20), - Children = new Drawable[] + Children = new[] { - new ReverseChildIDFillFlowContainer + new BeatmapSetLayoutSection { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, - Children = new Drawable[] + Child = new ReverseChildIDFillFlowContainer { - Header = new Header(), - info = new Info() - } + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + Header = new Header(), + info = new Info() + } + }, }, new ScoresContainer { Beatmap = { BindTarget = Header.Picker.Beatmap } - } + }, + comments = new CommentsSection() }, }, }, @@ -81,6 +87,7 @@ namespace osu.Game.Overlays Header.BeatmapSet.BindTo(beatmapSet); info.BeatmapSet.BindTo(beatmapSet); + comments.BeatmapSet.BindTo(beatmapSet); Header.Picker.Beatmap.ValueChanged += b => { @@ -143,5 +150,30 @@ namespace osu.Game.Overlays beatmapSet.Value = set; Show(); } + + private class CommentsSection : BeatmapSetLayoutSection + { + public readonly Bindable BeatmapSet = new Bindable(); + + public CommentsSection() + { + CommentsContainer comments; + + Add(comments = new CommentsContainer()); + + BeatmapSet.BindValueChanged(beatmapSet => + { + if (beatmapSet.NewValue?.OnlineBeatmapSetID is int onlineBeatmapSetID) + { + Show(); + comments.ShowComments(CommentableType.Beatmapset, onlineBeatmapSetID); + } + else + { + Hide(); + } + }, true); + } + } } } diff --git a/osu.Game/Overlays/Changelog/ChangelogBuild.cs b/osu.Game/Overlays/Changelog/ChangelogBuild.cs index 5a3ce6291e..8aee76cb08 100644 --- a/osu.Game/Overlays/Changelog/ChangelogBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogBuild.cs @@ -16,6 +16,7 @@ using osuTK.Graphics; using osu.Framework.Allocation; using System.Net; using osuTK; +using osu.Framework.Extensions.Color4Extensions; namespace osu.Game.Overlays.Changelog { @@ -51,28 +52,27 @@ namespace osu.Game.Overlays.Changelog } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, OverlayColourProvider colourProvider) { foreach (var categoryEntries in Build.ChangelogEntries.GroupBy(b => b.Category).OrderBy(c => c.Key)) { ChangelogEntries.Add(new OsuSpriteText { Text = categoryEntries.Key, - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 24), + Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 18), Margin = new MarginPadding { Top = 35, Bottom = 15 }, }); - var fontLarge = OsuFont.GetFont(size: 18); - var fontMedium = OsuFont.GetFont(size: 14); - var fontSmall = OsuFont.GetFont(size: 12); + var fontLarge = OsuFont.GetFont(size: 16); + var fontMedium = OsuFont.GetFont(size: 12); - foreach (APIChangelogEntry entry in categoryEntries) + foreach (var entry in categoryEntries) { var entryColour = entry.Major ? colours.YellowLight : Color4.White; LinkFlowContainer title; - Container titleContainer = new Container + var titleContainer = new Container { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, @@ -83,9 +83,9 @@ namespace osu.Game.Overlays.Changelog { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreRight, - Size = new Vector2(fontSmall.Size), + Size = new Vector2(10), Icon = entry.Type == ChangelogEntryType.Fix ? FontAwesome.Solid.Check : FontAwesome.Solid.Plus, - Colour = entryColour, + Colour = entryColour.Opacity(0.5f), Margin = new MarginPadding { Right = 5 }, }, title = new LinkFlowContainer @@ -123,10 +123,11 @@ namespace osu.Game.Overlays.Changelog }); } - title.AddText(" by ", t => + title.AddText("by ", t => { - t.Font = fontMedium; + t.Font = fontMedium.With(italics: true); t.Colour = entryColour; + t.Padding = new MarginPadding { Left = 10 }; }); if (entry.GithubUser.UserId != null) @@ -137,7 +138,7 @@ namespace osu.Game.Overlays.Changelog Id = entry.GithubUser.UserId.Value }, t => { - t.Font = fontMedium; + t.Font = fontMedium.With(italics: true); t.Colour = entryColour; }); } @@ -145,7 +146,7 @@ namespace osu.Game.Overlays.Changelog { title.AddLink(entry.GithubUser.DisplayName, entry.GithubUser.GithubUrl, t => { - t.Font = fontMedium; + t.Font = fontMedium.With(italics: true); t.Colour = entryColour; }); } @@ -153,7 +154,7 @@ namespace osu.Game.Overlays.Changelog { title.AddText(entry.GithubUser.DisplayName, t => { - t.Font = fontSmall; + t.Font = fontMedium.With(italics: true); t.Colour = entryColour; }); } @@ -162,7 +163,7 @@ namespace osu.Game.Overlays.Changelog if (!string.IsNullOrEmpty(entry.MessageHtml)) { - TextFlowContainer message = new TextFlowContainer + var message = new TextFlowContainer { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, @@ -171,8 +172,8 @@ namespace osu.Game.Overlays.Changelog // todo: use markdown parsing once API returns markdown message.AddText(WebUtility.HtmlDecode(Regex.Replace(entry.MessageHtml, @"<(.|\n)*?>", string.Empty)), t => { - t.Font = fontSmall; - t.Colour = new Color4(235, 184, 254, 255); + t.Font = fontMedium; + t.Colour = colourProvider.Foreground1; }); ChangelogEntries.Add(message); diff --git a/osu.Game/Overlays/Changelog/ChangelogContent.cs b/osu.Game/Overlays/Changelog/ChangelogContent.cs index 2f6c1ae902..49dd9bb835 100644 --- a/osu.Game/Overlays/Changelog/ChangelogContent.cs +++ b/osu.Game/Overlays/Changelog/ChangelogContent.cs @@ -19,7 +19,6 @@ namespace osu.Game.Overlays.Changelog RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Direction = FillDirection.Vertical; - Padding = new MarginPadding { Bottom = 50 }; } } } diff --git a/osu.Game/Overlays/Changelog/ChangelogListing.cs b/osu.Game/Overlays/Changelog/ChangelogListing.cs index 41d8228475..9b74a8da6d 100644 --- a/osu.Game/Overlays/Changelog/ChangelogListing.cs +++ b/osu.Game/Overlays/Changelog/ChangelogListing.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; -using osuTK.Graphics; namespace osu.Game.Overlays.Changelog { @@ -24,13 +23,13 @@ namespace osu.Game.Overlays.Changelog } [BackgroundDependencyLoader] - private void load() + private void load(OverlayColourProvider colourProvider) { - DateTime currentDate = DateTime.MinValue; + var currentDate = DateTime.MinValue; if (entries == null) return; - foreach (APIChangelogBuild build in entries) + foreach (var build in entries) { if (build.CreatedAt.Date != currentDate) { @@ -40,7 +39,7 @@ namespace osu.Game.Overlays.Changelog { RelativeSizeAxes = Axes.X, Height = 2, - Colour = new Color4(17, 17, 17, 255), + Colour = colourProvider.Background6, Margin = new MarginPadding { Top = 30 }, }); } @@ -49,10 +48,9 @@ namespace osu.Game.Overlays.Changelog { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Margin = new MarginPadding { Top = 15 }, - Text = build.CreatedAt.Date.ToString("dd MMM yyyy"), + Margin = new MarginPadding { Top = 20 }, + Text = build.CreatedAt.Date.ToString("dd MMMM yyyy"), Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 24), - Colour = OsuColour.FromHex(@"FD5"), }); currentDate = build.CreatedAt.Date; @@ -68,7 +66,7 @@ namespace osu.Game.Overlays.Changelog Child = new Box { RelativeSizeAxes = Axes.Both, - Colour = new Color4(32, 24, 35, 255), + Colour = colourProvider.Background6, } }); } diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index 73f9466179..8b89d63aab 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -31,7 +32,7 @@ namespace osu.Game.Overlays.Changelog } [BackgroundDependencyLoader] - private void load(CancellationToken? cancellation, IAPIProvider api) + private void load(CancellationToken? cancellation, IAPIProvider api, OverlayColourProvider colourProvider) { bool complete = false; @@ -63,10 +64,14 @@ namespace osu.Game.Overlays.Changelog Children = new Drawable[] { new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild }, - comments = new CommentsContainer + new Box { - Margin = new MarginPadding { Top = 10 } - } + RelativeSizeAxes = Axes.X, + Height = 2, + Colour = colourProvider.Background6, + Margin = new MarginPadding { Top = 30 }, + }, + comments = new CommentsContainer() }; comments.ShowComments(CommentableType.Build, build.Id); @@ -80,6 +85,8 @@ namespace osu.Game.Overlays.Changelog { } + private OsuSpriteText date; + protected override FillFlowContainer CreateHeader() { var fill = base.CreateHeader(); @@ -89,11 +96,10 @@ namespace osu.Game.Overlays.Changelog existing.Scale = new Vector2(1.25f); existing.Action = null; - existing.Add(new OsuSpriteText + existing.Add(date = new OsuSpriteText { - Text = Build.CreatedAt.Date.ToString("dd MMM yyyy"), + Text = Build.CreatedAt.Date.ToString("dd MMMM yyyy"), Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 14), - Colour = OsuColour.FromHex(@"FD5"), Anchor = Anchor.BottomCentre, Origin = Anchor.TopCentre, Margin = new MarginPadding { Top = 5 }, @@ -113,6 +119,12 @@ namespace osu.Game.Overlays.Changelog return fill; } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + date.Colour = colourProvider.Light1; + } } private class NavigationIconButton : IconButton diff --git a/osu.Game/Overlays/Changelog/UpdateStreamBadge.cs b/osu.Game/Overlays/Changelog/UpdateStreamBadge.cs index 52b77604d9..10aca31441 100644 --- a/osu.Game/Overlays/Changelog/UpdateStreamBadge.cs +++ b/osu.Game/Overlays/Changelog/UpdateStreamBadge.cs @@ -3,8 +3,6 @@ using Humanizer; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -16,99 +14,90 @@ using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osuTK; -using osuTK.Graphics; namespace osu.Game.Overlays.Changelog { public class UpdateStreamBadge : TabItem { - private const float badge_height = 66.5f; private const float badge_width = 100; private const float transition_duration = 100; - private readonly ExpandingBar expandingBar; - private SampleChannel sampleClick; - private SampleChannel sampleHover; - - private readonly FillFlowContainer text; - public readonly Bindable SelectedTab = new Bindable(); - private readonly Container fadeContainer; + private readonly APIUpdateStream stream; + + private Container fadeContainer; + private FillFlowContainer text; + private ExpandingBar expandingBar; public UpdateStreamBadge(APIUpdateStream stream) : base(stream) { - Size = new Vector2(stream.IsFeatured ? badge_width * 2 : badge_width, badge_height); - Padding = new MarginPadding(5); - - Child = fadeContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - text = new FillFlowContainer - { - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new[] - { - new OsuSpriteText - { - Text = stream.DisplayName, - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 12), - Margin = new MarginPadding { Top = 6 }, - }, - new OsuSpriteText - { - Text = stream.LatestBuild.DisplayVersion, - Font = OsuFont.GetFont(weight: FontWeight.Light, size: 16), - }, - new OsuSpriteText - { - Text = stream.LatestBuild.Users > 0 ? $"{stream.LatestBuild.Users:N0} {"user".Pluralize(stream.LatestBuild.Users == 1)} online" : null, - Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 10), - Colour = new Color4(203, 164, 218, 255), - }, - } - }, - expandingBar = new ExpandingBar - { - Anchor = Anchor.TopCentre, - Colour = stream.Colour, - ExpandedSize = 4, - CollapsedSize = 2, - IsCollapsed = true - }, - } - }; - - SelectedTab.BindValueChanged(_ => updateState(), true); + this.stream = stream; } [BackgroundDependencyLoader] - private void load(AudioManager audio) + private void load(OverlayColourProvider colourProvider) { - sampleClick = audio.Samples.Get(@"UI/generic-select-soft"); - sampleHover = audio.Samples.Get(@"UI/generic-hover-soft"); + Size = new Vector2(stream.IsFeatured ? badge_width * 2 : badge_width, 60); + Padding = new MarginPadding(5); + + AddRange(new Drawable[] + { + fadeContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + text = new FillFlowContainer + { + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Margin = new MarginPadding { Top = 6 }, + Children = new[] + { + new OsuSpriteText + { + Text = stream.DisplayName, + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black), + }, + new OsuSpriteText + { + Text = stream.LatestBuild.DisplayVersion, + Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular), + }, + new OsuSpriteText + { + Text = stream.LatestBuild.Users > 0 ? $"{"user".ToQuantity(stream.LatestBuild.Users, "N0")} online" : null, + Font = OsuFont.GetFont(size: 10), + Colour = colourProvider.Foreground1 + }, + } + }, + expandingBar = new ExpandingBar + { + Anchor = Anchor.TopCentre, + Colour = stream.Colour, + ExpandedSize = 4, + CollapsedSize = 2, + IsCollapsed = true + }, + } + }, + new HoverClickSounds() + }); + + SelectedTab.BindValueChanged(_ => updateState(), true); } protected override void OnActivated() => updateState(); protected override void OnDeactivated() => updateState(); - protected override bool OnClick(ClickEvent e) - { - sampleClick?.Play(); - return base.OnClick(e); - } - protected override bool OnHover(HoverEvent e) { - sampleHover?.Play(); updateState(); - return base.OnHover(e); } diff --git a/osu.Game/Overlays/Changelog/UpdateStreamBadgeArea.cs b/osu.Game/Overlays/Changelog/UpdateStreamBadgeArea.cs index ca57ba24e2..639c0d9780 100644 --- a/osu.Game/Overlays/Changelog/UpdateStreamBadgeArea.cs +++ b/osu.Game/Overlays/Changelog/UpdateStreamBadgeArea.cs @@ -8,34 +8,34 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; -using osuTK.Graphics; +using osu.Framework.Allocation; namespace osu.Game.Overlays.Changelog { public class UpdateStreamBadgeArea : TabControl { - public UpdateStreamBadgeArea() + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; AddInternal(new Box { - Colour = Color4.Black, - Alpha = 0.12f, RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background5, }); } public void Populate(List streams) { - foreach (APIUpdateStream updateStream in streams) + foreach (var updateStream in streams) AddItem(updateStream); } protected override bool OnHover(HoverEvent e) { - foreach (UpdateStreamBadge streamBadge in TabContainer.Children.OfType()) + foreach (var streamBadge in TabContainer.Children.OfType()) streamBadge.EnableDim(); return base.OnHover(e); @@ -43,7 +43,7 @@ namespace osu.Game.Overlays.Changelog protected override void OnHoverLost(HoverLostEvent e) { - foreach (UpdateStreamBadge streamBadge in TabContainer.Children.OfType()) + foreach (var streamBadge in TabContainer.Children.OfType()) streamBadge.DisableDim(); base.OnHoverLost(e); diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs index 6a8cb29d3e..d13ac5c2de 100644 --- a/osu.Game/Overlays/ChangelogOverlay.cs +++ b/osu.Game/Overlays/ChangelogOverlay.cs @@ -13,7 +13,6 @@ using osu.Framework.Bindables; 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.Input.Bindings; using osu.Game.Online.API.Requests; @@ -42,14 +41,14 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(AudioManager audio, OsuColour colour) + private void load(AudioManager audio) { Children = new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, - Colour = colour.PurpleDarkAlternative, + Colour = ColourProvider.Background4, }, new OsuScrollContainer { diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs index 1aa40201f1..83f44ccd80 100644 --- a/osu.Game/Overlays/Comments/CommentsHeader.cs +++ b/osu.Game/Overlays/Comments/CommentsHeader.cs @@ -109,6 +109,7 @@ namespace osu.Game.Overlays.Comments public enum CommentsSortCriteria { + [System.ComponentModel.Description(@"Recent")] New, Old, Top diff --git a/osu.Game/Overlays/Comments/CommentsPage.cs b/osu.Game/Overlays/Comments/CommentsPage.cs index 4f82ee5a19..9b146b0a7d 100644 --- a/osu.Game/Overlays/Comments/CommentsPage.cs +++ b/osu.Game/Overlays/Comments/CommentsPage.cs @@ -61,15 +61,15 @@ namespace osu.Game.Overlays.Comments return; } - appendComments(commentBundle); + AppendComments(commentBundle); } private DrawableComment getDrawableComment(Comment comment) { - if (commentDictionary.TryGetValue(comment.Id, out var existing)) + if (CommentDictionary.TryGetValue(comment.Id, out var existing)) return existing; - return commentDictionary[comment.Id] = new DrawableComment(comment) + return CommentDictionary[comment.Id] = new DrawableComment(comment) { ShowDeleted = { BindTarget = ShowDeleted }, Sort = { BindTarget = Sort }, @@ -81,31 +81,28 @@ namespace osu.Game.Overlays.Comments { var request = new GetCommentsRequest(CommentableId.Value, Type.Value, Sort.Value, page, drawableComment.Comment.Id); - request.Success += response => Schedule(() => appendComments(response)); + request.Success += response => Schedule(() => AppendComments(response)); api.PerformAsync(request); } - private readonly Dictionary commentDictionary = new Dictionary(); + protected readonly Dictionary CommentDictionary = new Dictionary(); /// /// Appends retrieved comments to the subtree rooted of comments in this page. /// /// The bundle of comments to add. - private void appendComments([NotNull] CommentBundle bundle) + protected void AppendComments([NotNull] CommentBundle bundle) { var orphaned = new List(); - foreach (var topLevel in bundle.Comments) - addNewComment(topLevel); - - foreach (var child in bundle.IncludedComments) + foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments)) { - // Included comments can contain the parent comment, which already exists in the hierarchy. - if (commentDictionary.ContainsKey(child.Id)) + // Exclude possible duplicated comments. + if (CommentDictionary.ContainsKey(comment.Id)) continue; - addNewComment(child); + addNewComment(comment); } // Comments whose parents were seen later than themselves can now be added. @@ -121,7 +118,7 @@ namespace osu.Game.Overlays.Comments // Comments that have no parent are added as top-level comments to the flow. flow.Add(drawableComment); } - else if (commentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable)) + else if (CommentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable)) { // The comment's parent has already been seen, so the parent<-> child links can be added. comment.ParentComment = parentDrawable.Comment; diff --git a/osu.Game/Overlays/Home/Friends/UserListToolbar.cs b/osu.Game/Overlays/Home/Friends/UserListToolbar.cs new file mode 100644 index 0000000000..f7c5e9f4fd --- /dev/null +++ b/osu.Game/Overlays/Home/Friends/UserListToolbar.cs @@ -0,0 +1,45 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osuTK; +using osu.Framework.Bindables; + +namespace osu.Game.Overlays.Home.Friends +{ + public class UserListToolbar : CompositeDrawable + { + public Bindable SortCriteria => sortControl.Current; + + public Bindable DisplayStyle => styleControl.Current; + + private readonly UserSortTabControl sortControl; + private readonly OverlayPanelDisplayStyleControl styleControl; + + public UserListToolbar() + { + AutoSizeAxes = Axes.Both; + + AddInternal(new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + sortControl = new UserSortTabControl + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + styleControl = new OverlayPanelDisplayStyleControl + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + } + }); + } + } +} diff --git a/osu.Game/Overlays/Home/Friends/UserSortTabControl.cs b/osu.Game/Overlays/Home/Friends/UserSortTabControl.cs new file mode 100644 index 0000000000..2479fa4638 --- /dev/null +++ b/osu.Game/Overlays/Home/Friends/UserSortTabControl.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.ComponentModel; + +namespace osu.Game.Overlays.Home.Friends +{ + public class UserSortTabControl : OverlaySortTabControl + { + } + + public enum UserSortCriteria + { + [Description(@"Recently Active")] + LastVisit, + Rank, + Username + } +} diff --git a/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs b/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs new file mode 100644 index 0000000000..7269007b41 --- /dev/null +++ b/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs @@ -0,0 +1,101 @@ +// 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.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osuTK; +using osu.Framework.Input.Events; +using osu.Game.Graphics.UserInterface; +using osu.Framework.Allocation; +using osuTK.Graphics; +using osu.Framework.Graphics.Cursor; + +namespace osu.Game.Overlays +{ + public class OverlayPanelDisplayStyleControl : OsuTabControl + { + protected override Dropdown CreateDropdown() => null; + + protected override TabItem CreateTabItem(OverlayPanelDisplayStyle value) => new PanelDisplayTabItem(value); + + protected override bool AddEnumEntriesAutomatically => false; + + public OverlayPanelDisplayStyleControl() + { + AutoSizeAxes = Axes.Both; + + AddTabItem(new PanelDisplayTabItem(OverlayPanelDisplayStyle.Card) + { + Icon = FontAwesome.Solid.Square + }); + AddTabItem(new PanelDisplayTabItem(OverlayPanelDisplayStyle.List) + { + Icon = FontAwesome.Solid.Bars + }); + } + + protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal + }; + + private class PanelDisplayTabItem : TabItem, IHasTooltip + { + public IconUsage Icon + { + set => icon.Icon = value; + } + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + + public string TooltipText => $@"{Value} view"; + + private readonly SpriteIcon icon; + + public PanelDisplayTabItem(OverlayPanelDisplayStyle value) + : base(value) + { + Size = new Vector2(11); + AddRange(new Drawable[] + { + icon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit + }, + new HoverClickSounds() + }); + } + + protected override void OnActivated() => updateState(); + + protected override void OnDeactivated() => updateState(); + + protected override bool OnHover(HoverEvent e) + { + updateState(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateState(); + base.OnHoverLost(e); + } + + private void updateState() => icon.Colour = Active.Value || IsHovered ? colourProvider.Light1 : Color4.White; + } + } + + public enum OverlayPanelDisplayStyle + { + Card, + List + } +} diff --git a/osu.Game/Overlays/OverlaySortTabControl.cs b/osu.Game/Overlays/OverlaySortTabControl.cs index 5a713ab08e..395f3aec4c 100644 --- a/osu.Game/Overlays/OverlaySortTabControl.cs +++ b/osu.Game/Overlays/OverlaySortTabControl.cs @@ -15,6 +15,8 @@ using osu.Game.Graphics.Sprites; using osuTK.Graphics; using osu.Game.Overlays.Comments; using JetBrains.Annotations; +using System; +using osu.Framework.Extensions; namespace osu.Game.Overlays { @@ -132,7 +134,7 @@ namespace osu.Game.Overlays Anchor = Anchor.Centre, Origin = Anchor.Centre, Font = OsuFont.GetFont(size: 12), - Text = value.ToString() + Text = (value as Enum)?.GetDescription() ?? value.ToString() } } }); diff --git a/osu.Game/Overlays/RankingsOverlay.cs b/osu.Game/Overlays/RankingsOverlay.cs index 3304c6ebec..afb23883ac 100644 --- a/osu.Game/Overlays/RankingsOverlay.cs +++ b/osu.Game/Overlays/RankingsOverlay.cs @@ -138,6 +138,12 @@ namespace osu.Game.Overlays Country.Value = requested; } + public void ShowSpotlights() + { + Scope.Value = RankingsScope.Spotlights; + Show(); + } + private void loadNewContent() { loading.Show(); diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs b/osu.Game/Rulesets/Judgements/IgnoreJudgement.cs similarity index 63% rename from osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs rename to osu.Game/Rulesets/Judgements/IgnoreJudgement.cs index b28b6a0d17..1871249c94 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs +++ b/osu.Game/Rulesets/Judgements/IgnoreJudgement.cs @@ -1,11 +1,11 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Scoring; -namespace osu.Game.Rulesets.Taiko.Judgements +namespace osu.Game.Rulesets.Judgements { - public class TaikoSwellTickJudgement : TaikoJudgement + public class IgnoreJudgement : Judgement { public override bool AffectsCombo => false; diff --git a/osu.Game/Rulesets/Judgements/Judgement.cs b/osu.Game/Rulesets/Judgements/Judgement.cs index 599135ba54..9105b920ca 100644 --- a/osu.Game/Rulesets/Judgements/Judgement.cs +++ b/osu.Game/Rulesets/Judgements/Judgement.cs @@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Judgements return -DEFAULT_MAX_HEALTH_INCREASE * 0.01; case HitResult.Good: - return DEFAULT_MAX_HEALTH_INCREASE * 0.3; + return DEFAULT_MAX_HEALTH_INCREASE * 0.5; case HitResult.Great: return DEFAULT_MAX_HEALTH_INCREASE; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 67fe18e8dd..9a5e25c8ac 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -99,12 +99,9 @@ namespace osu.Game.Rulesets.Objects.Drawables { var judgement = HitObject.CreateJudgement(); - if (judgement != null) - { - Result = CreateResult(judgement); - if (Result == null) - throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}."); - } + Result = CreateResult(judgement); + if (Result == null) + throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}."); loadSamples(); } @@ -265,7 +262,7 @@ namespace osu.Game.Rulesets.Objects.Drawables } } - if (state.Value != ArmedState.Idle && LifetimeEnd == double.MaxValue) + if (state.Value != ArmedState.Idle && LifetimeEnd == double.MaxValue || HitObject.HitWindows == null) Expire(); } else diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index c09844e0c6..9a8efdde84 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -144,9 +144,9 @@ namespace osu.Game.Rulesets.Objects /// /// Creates the that represents the scoring information for this . - /// May be null. /// - public virtual Judgement CreateJudgement() => null; + [NotNull] + public virtual Judgement CreateJudgement() => new Judgement(); /// /// Creates the for this . diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs index febfd3696c..19722fb796 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch /// /// Legacy osu!catch Hit-type, used for parsing Beatmaps. /// - internal sealed class ConvertHit : HitObject, IHasCombo, IHasXPosition + internal sealed class ConvertHit : ConvertHitObject, IHasCombo, IHasXPosition { public float X { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs index 0089d1eb88..9de311c9d7 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch /// /// Legacy osu!catch Spinner-type, used for parsing Beatmaps. /// - internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasXPosition, IHasCombo + internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasXPosition, IHasCombo { public double EndTime { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs new file mode 100644 index 0000000000..e3b0d8a498 --- /dev/null +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs @@ -0,0 +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.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Rulesets.Objects.Legacy +{ + /// + /// A hit object only used for conversion, not actual gameplay. + /// + internal abstract class ConvertHitObject : HitObject + { + public override Judgement CreateJudgement() => new IgnoreJudgement(); + + protected override HitWindows CreateHitWindows() => HitWindows.Empty; + } +} diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index 53cdf457c4..924182b265 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -9,7 +9,7 @@ using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Rulesets.Objects.Legacy { - internal abstract class ConvertSlider : HitObject, IHasCurve, IHasLegacyLastTickOffset + internal abstract class ConvertSlider : ConvertHitObject, IHasCurve, IHasLegacyLastTickOffset { /// /// Scoring distance with a speed-adjusted beat length of 1 second. diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs index 883ef55df0..0b69817c13 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs @@ -2,17 +2,14 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Objects.Legacy.Mania { /// /// Legacy osu!mania Hit-type, used for parsing Beatmaps. /// - internal sealed class ConvertHit : HitObject, IHasXPosition + internal sealed class ConvertHit : ConvertHitObject, IHasXPosition { public float X { get; set; } - - protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs index 69e6f8379d..1d92d638dd 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs @@ -2,18 +2,15 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Objects.Legacy.Mania { - internal sealed class ConvertHold : HitObject, IHasXPosition, IHasEndTime + internal sealed class ConvertHold : ConvertHitObject, IHasXPosition, IHasEndTime { public float X { get; set; } public double EndTime { get; set; } public double Duration => EndTime - StartTime; - - protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs index 4486c5d906..84cde5fa95 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Objects.Legacy.Mania { @@ -12,7 +11,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasXPosition { public float X { get; set; } - - protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs index c6d1f1922c..7dc13e27cd 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs @@ -2,21 +2,18 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Objects.Legacy.Mania { /// /// Legacy osu!mania Spinner-type, used for parsing Beatmaps. /// - internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasXPosition + internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasXPosition { public double EndTime { get; set; } public double Duration => EndTime - StartTime; public float X { get; set; } - - protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs index e40b5b4505..069366bad3 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Scoring; using osuTK; namespace osu.Game.Rulesets.Objects.Legacy.Osu @@ -10,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu /// /// Legacy osu! Hit-type, used for parsing Beatmaps. /// - internal sealed class ConvertHit : HitObject, IHasPosition, IHasCombo + internal sealed class ConvertHit : ConvertHitObject, IHasPosition, IHasCombo { public Vector2 Position { get; set; } @@ -21,7 +20,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu public bool NewCombo { get; set; } public int ComboOffset { get; set; } - - protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs index a163329d47..e947690668 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Scoring; using osuTK; namespace osu.Game.Rulesets.Objects.Legacy.Osu @@ -21,7 +20,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu public bool NewCombo { get; set; } public int ComboOffset { get; set; } - - protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs index 5d96a61633..8b21aab411 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Scoring; using osuTK; namespace osu.Game.Rulesets.Objects.Legacy.Osu @@ -10,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu /// /// Legacy osu! Spinner-type, used for parsing Beatmaps. /// - internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasPosition, IHasCombo + internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasPosition, IHasCombo { public double EndTime { get; set; } @@ -22,8 +21,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu public float Y => Position.Y; - protected override HitWindows CreateHitWindows() => HitWindows.Empty; - public bool NewCombo { get; set; } public int ComboOffset { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs index efb9810927..cb5178ce48 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs @@ -1,15 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Rulesets.Scoring; - namespace osu.Game.Rulesets.Objects.Legacy.Taiko { /// /// Legacy osu!taiko Hit-type, used for parsing Beatmaps. /// - internal sealed class ConvertHit : HitObject + internal sealed class ConvertHit : ConvertHitObject { - protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs index b365fd34ae..821554f7ee 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Rulesets.Scoring; - namespace osu.Game.Rulesets.Objects.Legacy.Taiko { /// @@ -10,6 +8,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko /// internal sealed class ConvertSlider : Legacy.ConvertSlider { - protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs index 840ba51ac2..8e28487f2f 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs @@ -2,19 +2,16 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Objects.Legacy.Taiko { /// /// Legacy osu!taiko Spinner-type, used for parsing Beatmaps. /// - internal sealed class ConvertSpinner : HitObject, IHasEndTime + internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime { public double EndTime { get; set; } public double Duration => EndTime - StartTime; - - protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs index 3016007f98..334b95f808 100644 --- a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs +++ b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs @@ -125,8 +125,6 @@ namespace osu.Game.Rulesets.Scoring simulate(nested); var judgement = obj.CreateJudgement(); - if (judgement == null) - return; var result = CreateResult(obj, judgement); if (result == null) diff --git a/osu.Game/Screens/Charts/ChartInfo.cs b/osu.Game/Screens/Charts/ChartInfo.cs deleted file mode 100644 index d9a9ad5eeb..0000000000 --- a/osu.Game/Screens/Charts/ChartInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -namespace osu.Game.Screens.Charts -{ - public class ChartInfo : ScreenWhiteBox - { - } -} diff --git a/osu.Game/Screens/Charts/ChartListing.cs b/osu.Game/Screens/Charts/ChartListing.cs deleted file mode 100644 index 18bba6433f..0000000000 --- a/osu.Game/Screens/Charts/ChartListing.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Collections.Generic; - -namespace osu.Game.Screens.Charts -{ - public class ChartListing : ScreenWhiteBox - { - protected override IEnumerable PossibleChildren => new[] - { - typeof(ChartInfo) - }; - } -} diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 3bec4b8f6f..3a6f02f811 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -93,15 +93,15 @@ namespace osu.Game.Screens.Edit EditorMenuBar menuBar; - var fileMenuItems = new List(); + var fileMenuItems = new List + { + new EditorMenuItem("Save", MenuItemType.Standard, saveBeatmap) + }; if (RuntimeInfo.IsDesktop) - { - fileMenuItems.Add(new EditorMenuItem("Save", MenuItemType.Standard, saveBeatmap)); fileMenuItems.Add(new EditorMenuItem("Export package", MenuItemType.Standard, exportBeatmap)); - fileMenuItems.Add(new EditorMenuItemSpacer()); - } + fileMenuItems.Add(new EditorMenuItemSpacer()); fileMenuItems.Add(new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit)); AddInternal(new OsuContextMenuContainer diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index c70fbb67a4..127270f521 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -18,7 +18,6 @@ using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Overlays.Dialog; using osu.Game.Screens.Backgrounds; -using osu.Game.Screens.Charts; using osu.Game.Screens.Edit; using osu.Game.Screens.Multi; using osu.Game.Screens.Select; @@ -73,7 +72,7 @@ namespace osu.Game.Screens.Menu private SongTicker songTicker; [BackgroundDependencyLoader(true)] - private void load(DirectOverlay direct, SettingsOverlay settings, OsuConfigManager config, SessionStatics statics) + private void load(DirectOverlay direct, SettingsOverlay settings, RankingsOverlay rankings, OsuConfigManager config, SessionStatics statics) { holdDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); loginDisplayed = statics.GetBindable(Static.LoginOverlayDisplayed); @@ -101,7 +100,6 @@ namespace osu.Game.Screens.Menu { buttons = new ButtonSystem { - OnChart = delegate { this.Push(new ChartListing()); }, OnEdit = delegate { this.Push(new Editor()); }, OnSolo = onSolo, OnMulti = delegate { this.Push(new Multiplayer()); }, @@ -136,6 +134,7 @@ namespace osu.Game.Screens.Menu buttons.OnSettings = () => settings?.ToggleVisibility(); buttons.OnDirect = () => direct?.ToggleVisibility(); + buttons.OnChart = () => rankings?.ShowSpotlights(); LoadComponentAsync(background = new BackgroundScreenDefault()); preloadSongSelect(); diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs index 77ee52f23e..a84a85ea47 100644 --- a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -15,7 +15,6 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Play.HUD; using osuTK; -using osuTK.Graphics; namespace osu.Game.Screens.Play { @@ -63,15 +62,9 @@ namespace osu.Game.Screens.Play set { if (value) - { loading.Show(); - backgroundSprite.FadeColour(OsuColour.Gray(0.5f), 400, Easing.OutQuint); - } else - { loading.Hide(); - backgroundSprite.FadeColour(Color4.White, 400, Easing.OutQuint); - } } } @@ -138,7 +131,7 @@ namespace osu.Game.Screens.Play Anchor = Anchor.Centre, FillMode = FillMode.Fill, }, - loading = new LoadingSpinner { Scale = new Vector2(1.3f) } + loading = new LoadingLayer(backgroundSprite) } }, new OsuSpriteText diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 208bdd17ad..9edbddc0b1 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -207,11 +207,27 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private double floatingAverage; private Container colourBars; + private const int max_concurrent_judgements = 50; + public override void OnNewJudgement(JudgementResult judgement) { if (!judgement.IsHit) return; + if (judgementsContainer.Count > max_concurrent_judgements) + { + const double quick_fade_time = 100; + + // check with a bit of lenience to avoid precision error in comparison. + var old = judgementsContainer.FirstOrDefault(j => j.LifetimeEnd > Clock.CurrentTime + quick_fade_time * 1.1); + + if (old != null) + { + old.ClearTransforms(); + old.FadeOut(quick_fade_time).Expire(); + } + } + judgementsContainer.Add(new JudgementLine { Y = getRelativeJudgementPosition(judgement.TimeOffset), @@ -228,7 +244,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private class JudgementLine : CompositeDrawable { - private const int judgement_fade_duration = 10000; + private const int judgement_fade_duration = 5000; public JudgementLine() { @@ -255,7 +271,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Width = 0; this.ResizeWidthTo(1, 200, Easing.OutElasticHalf); - this.FadeTo(0.8f, 150).Then().FadeOut(judgement_fade_duration, Easing.OutQuint).Expire(); + this.FadeTo(0.8f, 150).Then().FadeOut(judgement_fade_duration).Expire(); } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 24ee25c4de..c5ebf0f712 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,7 +23,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 3743138c1a..9574b8cba9 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -74,7 +74,7 @@ - + @@ -82,7 +82,7 @@ - +