diff --git a/osu.Android.props b/osu.Android.props index 7e6f1469f5..0ac766926c 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs index a692c0b697..0c56f7bcf4 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs @@ -1,23 +1,27 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Pooling; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.UI; -using osu.Game.Skinning; +using osu.Game.Rulesets.Objects; using osuTK; -using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Tests.Skinning { [TestFixture] public class TestSceneHitExplosion : ManiaSkinnableTestScene { + private readonly List> hitExplosionPools = new List>(); + public TestSceneHitExplosion() { int runcount = 0; @@ -29,28 +33,40 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning if (runcount % 15 > 12) return; - CreatedDrawables.OfType().ForEach(c => + int poolIndex = 0; + + foreach (var c in CreatedDrawables.OfType()) { - c.Add(new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitExplosion, 0), - _ => new DefaultHitExplosion((runcount / 15) % 2 == 0 ? new Color4(94, 0, 57, 255) : new Color4(6, 84, 0, 255), runcount % 6 != 0) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - })); - }); + c.Add(hitExplosionPools[poolIndex].Get(e => + { + e.Apply(new JudgementResult(new HitObject(), runcount % 6 == 0 ? new HoldNoteTickJudgement() : new ManiaJudgement())); + + e.Anchor = Anchor.Centre; + e.Origin = Anchor.Centre; + })); + + poolIndex++; + } }, 100); } [BackgroundDependencyLoader] private void load() { - SetContents(() => new ColumnTestContainer(0, ManiaAction.Key1) + SetContents(() => { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativePositionAxes = Axes.Y, - Y = -0.25f, - Size = new Vector2(Column.COLUMN_WIDTH, DefaultNotePiece.NOTE_HEIGHT), + var pool = new DrawablePool(5); + hitExplosionPools.Add(pool); + + return new ColumnTestContainer(0, ManiaAction.Key1) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativePositionAxes = Axes.Y, + Y = -0.25f, + Size = new Vector2(Column.COLUMN_WIDTH, DefaultNotePiece.NOTE_HEIGHT), + Child = pool + }; }); } } diff --git a/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs index 53db676a54..53967ffa05 100644 --- a/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs +++ b/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.Judgements return 300; case HitResult.Perfect: - return 320; + return 350; } } } diff --git a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs index ba84c21845..4b2f643333 100644 --- a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs +++ b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs @@ -7,9 +7,9 @@ namespace osu.Game.Rulesets.Mania.Scoring { internal class ManiaScoreProcessor : ScoreProcessor { - protected override double DefaultAccuracyPortion => 0.8; + protected override double DefaultAccuracyPortion => 0.95; - protected override double DefaultComboPortion => 0.2; + protected override double DefaultComboPortion => 0.05; public override HitWindows CreateHitWindows() => new ManiaHitWindows(); } diff --git a/osu.Game.Rulesets.Mania/Skinning/LegacyHitExplosion.cs b/osu.Game.Rulesets.Mania/Skinning/LegacyHitExplosion.cs index bc93bb2615..12747924de 100644 --- a/osu.Game.Rulesets.Mania/Skinning/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Mania/Skinning/LegacyHitExplosion.cs @@ -6,13 +6,15 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; namespace osu.Game.Rulesets.Mania.Skinning { - public class LegacyHitExplosion : LegacyManiaColumnElement + public class LegacyHitExplosion : LegacyManiaColumnElement, IHitExplosion { private readonly IBindable direction = new Bindable(); @@ -62,9 +64,9 @@ namespace osu.Game.Rulesets.Mania.Skinning explosion.Anchor = direction.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; } - protected override void LoadComplete() + public void Animate(JudgementResult result) { - base.LoadComplete(); + (explosion as IFramedAnimation)?.GotoFrame(0); explosion?.FadeInFromZero(80) .Then().FadeOut(120); diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 642353bd0b..255ce4c064 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -9,9 +9,9 @@ using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics.Pooling; using osu.Framework.Input.Bindings; using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; @@ -34,8 +34,8 @@ namespace osu.Game.Rulesets.Mania.UI public readonly Bindable Action = new Bindable(); public readonly ColumnHitObjectArea HitObjectArea; - internal readonly Container TopLevelContainer; + private readonly DrawablePool hitExplosionPool; public Container UnderlayElements => HitObjectArea.UnderlayElements; @@ -53,6 +53,7 @@ namespace osu.Game.Rulesets.Mania.UI InternalChildren = new[] { + hitExplosionPool = new DrawablePool(5), // For input purposes, the background is added at the highest depth, but is then proxied back below all other elements background.CreateProxy(), HitObjectArea = new ColumnHitObjectArea(Index, HitObjectContainer) { RelativeSizeAxes = Axes.Both }, @@ -108,15 +109,7 @@ namespace osu.Game.Rulesets.Mania.UI if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements.Value) return; - var explosion = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitExplosion, Index), _ => - new DefaultHitExplosion(judgedObject.AccentColour.Value, judgedObject is DrawableHoldNoteTick)) - { - RelativeSizeAxes = Axes.Both - }; - - HitObjectArea.Explosions.Add(explosion); - - explosion.Delay(200).Expire(true); + HitObjectArea.Explosions.Add(hitExplosionPool.Get(e => e.Apply(result))); } public bool OnPressed(ManiaAction action) diff --git a/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs b/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs index 7a047ed121..225269cf48 100644 --- a/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs @@ -8,6 +8,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Utils; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.UI.Scrolling; using osuTK; @@ -15,35 +17,36 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.UI { - public class DefaultHitExplosion : CompositeDrawable + public class DefaultHitExplosion : CompositeDrawable, IHitExplosion { + private const float default_large_faint_size = 0.8f; + public override bool RemoveWhenNotAlive => true; + [Resolved] + private Column column { get; set; } + private readonly IBindable direction = new Bindable(); - private readonly CircularContainer largeFaint; - private readonly CircularContainer mainGlow1; + private CircularContainer largeFaint; + private CircularContainer mainGlow1; - public DefaultHitExplosion(Color4 objectColour, bool isSmall = false) + public DefaultHitExplosion() { Origin = Anchor.Centre; RelativeSizeAxes = Axes.X; Height = DefaultNotePiece.NOTE_HEIGHT; + } - // scale roughly in-line with visual appearance of notes - Scale = new Vector2(1f, 0.6f); - - if (isSmall) - Scale *= 0.5f; - + [BackgroundDependencyLoader] + private void load(IScrollingInfo scrollingInfo) + { const float angle_variangle = 15; // should be less than 45 - const float roundness = 80; - const float initial_height = 10; - var colour = Interpolation.ValueAt(0.4f, objectColour, Color4.White, 0, 1); + var colour = Interpolation.ValueAt(0.4f, column.AccentColour, Color4.White, 0, 1); InternalChildren = new Drawable[] { @@ -54,12 +57,12 @@ namespace osu.Game.Rulesets.Mania.UI RelativeSizeAxes = Axes.Both, Masking = true, // we want our size to be very small so the glow dominates it. - Size = new Vector2(0.8f), + Size = new Vector2(default_large_faint_size), Blending = BlendingParameters.Additive, EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow, - Colour = Interpolation.ValueAt(0.1f, objectColour, Color4.White, 0, 1).Opacity(0.3f), + Colour = Interpolation.ValueAt(0.1f, column.AccentColour, Color4.White, 0, 1).Opacity(0.3f), Roundness = 160, Radius = 200, }, @@ -74,7 +77,7 @@ namespace osu.Game.Rulesets.Mania.UI EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow, - Colour = Interpolation.ValueAt(0.6f, objectColour, Color4.White, 0, 1), + Colour = Interpolation.ValueAt(0.6f, column.AccentColour, Color4.White, 0, 1), Roundness = 20, Radius = 50, }, @@ -114,30 +117,11 @@ namespace osu.Game.Rulesets.Mania.UI }, } }; - } - [BackgroundDependencyLoader] - private void load(IScrollingInfo scrollingInfo) - { direction.BindTo(scrollingInfo.Direction); direction.BindValueChanged(onDirectionChanged, true); } - protected override void LoadComplete() - { - const double duration = 200; - - base.LoadComplete(); - - largeFaint - .ResizeTo(largeFaint.Size * new Vector2(5, 1), duration, Easing.OutQuint) - .FadeOut(duration * 2); - - mainGlow1.ScaleTo(1.4f, duration, Easing.OutQuint); - - this.FadeOut(duration, Easing.Out); - } - private void onDirectionChanged(ValueChangedEvent direction) { if (direction.NewValue == ScrollingDirection.Up) @@ -151,5 +135,29 @@ namespace osu.Game.Rulesets.Mania.UI Y = -DefaultNotePiece.NOTE_HEIGHT / 2; } } + + public void Animate(JudgementResult result) + { + // scale roughly in-line with visual appearance of notes + Vector2 scale = new Vector2(1, 0.6f); + + if (result.Judgement is HoldNoteTickJudgement) + scale *= 0.5f; + + this.ScaleTo(scale); + + largeFaint + .ResizeTo(default_large_faint_size) + .Then() + .ResizeTo(default_large_faint_size * new Vector2(5, 1), PoolableHitExplosion.DURATION, Easing.OutQuint) + .FadeOut(PoolableHitExplosion.DURATION * 2); + + mainGlow1 + .ScaleTo(1) + .Then() + .ScaleTo(1.4f, PoolableHitExplosion.DURATION, Easing.OutQuint); + + this.FadeOutFromOne(PoolableHitExplosion.DURATION, Easing.Out); + } } } diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs index 8797f014df..d99f6cb8d3 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs @@ -15,6 +15,10 @@ namespace osu.Game.Rulesets.Mania.UI { } + public DrawableManiaJudgement() + { + } + [BackgroundDependencyLoader] private void load() { diff --git a/osu.Game.Rulesets.Mania/UI/IHitExplosion.cs b/osu.Game.Rulesets.Mania/UI/IHitExplosion.cs new file mode 100644 index 0000000000..3252dcc276 --- /dev/null +++ b/osu.Game.Rulesets.Mania/UI/IHitExplosion.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Judgements; + +namespace osu.Game.Rulesets.Mania.UI +{ + /// + /// Common interface for all hit explosion bodies. + /// + public interface IHitExplosion + { + /// + /// Begins animating this . + /// + /// The type of that caused this explosion. + void Animate(JudgementResult result); + } +} diff --git a/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs b/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs new file mode 100644 index 0000000000..64b7d7d550 --- /dev/null +++ b/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs @@ -0,0 +1,51 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Pooling; +using osu.Game.Rulesets.Judgements; +using osu.Game.Skinning; + +namespace osu.Game.Rulesets.Mania.UI +{ + public class PoolableHitExplosion : PoolableDrawable + { + public const double DURATION = 200; + + public JudgementResult Result { get; private set; } + + [Resolved] + private Column column { get; set; } + + private SkinnableDrawable skinnableExplosion; + + public PoolableHitExplosion() + { + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = skinnableExplosion = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitExplosion, column.Index), _ => new DefaultHitExplosion()) + { + RelativeSizeAxes = Axes.Both + }; + } + + public void Apply(JudgementResult result) + { + Result = result; + } + + protected override void PrepareForUse() + { + base.PrepareForUse(); + + (skinnableExplosion?.Drawable as IHitExplosion)?.Animate(Result); + + this.Delay(DURATION).Then().Expire(); + } + } +} diff --git a/osu.Game.Rulesets.Mania/UI/Stage.cs b/osu.Game.Rulesets.Mania/UI/Stage.cs index faa04dea97..36780b0f80 100644 --- a/osu.Game.Rulesets.Mania/UI/Stage.cs +++ b/osu.Game.Rulesets.Mania/UI/Stage.cs @@ -6,6 +6,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Pooling; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; @@ -33,8 +34,8 @@ namespace osu.Game.Rulesets.Mania.UI public IReadOnlyList Columns => columnFlow.Children; private readonly FillFlowContainer columnFlow; - public Container Judgements => judgements; private readonly JudgementContainer judgements; + private readonly DrawablePool judgementPool; private readonly Drawable barLineContainer; private readonly Container topLevelContainer; @@ -63,6 +64,7 @@ namespace osu.Game.Rulesets.Mania.UI InternalChildren = new Drawable[] { + judgementPool = new DrawablePool(2), new Container { Anchor = Anchor.TopCentre, @@ -208,12 +210,14 @@ namespace osu.Game.Rulesets.Mania.UI if (!judgedObject.DisplayResult || !DisplayJudgements.Value) return; - judgements.Clear(); - judgements.Add(new DrawableManiaJudgement(result, judgedObject) + judgements.Clear(false); + judgements.Add(judgementPool.Get(j => { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }); + j.Apply(result, judgedObject); + + j.Anchor = Anchor.Centre; + j.Origin = Anchor.Centre; + })); } protected override void Update() diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs index 73cb483ef0..ee6a7815e2 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs @@ -1,7 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Game.Configuration; namespace osu.Game.Rulesets.Osu.Mods { @@ -15,6 +17,14 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Description => "Hit them at the right size!"; - protected override float StartScale => 2f; + [SettingSource("Starting Size", "The initial size multiplier applied to all objects.")] + public override BindableNumber StartScale { get; } = new BindableFloat + { + MinValue = 1f, + MaxValue = 25f, + Default = 2f, + Value = 2f, + Precision = 0.1f, + }; } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs index f08d4e8f5e..182d6eeb4b 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs @@ -1,7 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Game.Configuration; namespace osu.Game.Rulesets.Osu.Mods { @@ -15,6 +17,14 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Description => "Hit them at the right size!"; - protected override float StartScale => 0.5f; + [SettingSource("Starting Size", "The initial size multiplier applied to all objects.")] + public override BindableNumber StartScale { get; } = new BindableFloat + { + MinValue = 0f, + MaxValue = 0.99f, + Default = 0.5f, + Value = 0.5f, + Precision = 0.01f, + }; } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs b/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs index 42ddddc4dd..06ba4cde4a 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1; - protected virtual float StartScale => 1; + public abstract BindableNumber StartScale { get; } protected virtual float EndScale => 1; @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Mods case DrawableHitCircle _: { using (drawable.BeginAbsoluteSequence(h.StartTime - h.TimePreempt)) - drawable.ScaleTo(StartScale).Then().ScaleTo(EndScale, h.TimePreempt, Easing.OutSine); + drawable.ScaleTo(StartScale.Value).Then().ScaleTo(EndScale, h.TimePreempt, Easing.OutSine); break; } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs b/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs index 273f593c32..18ac415126 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs @@ -4,19 +4,22 @@ using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; using osu.Framework.Allocation; -using osu.Game.Graphics; +using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Online { public class TestSceneShowMoreButton : OsuTestScene { + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); + public TestSceneShowMoreButton() { - TestButton button = null; + ShowMoreButton button = null; int fireCount = 0; - Add(button = new TestButton + Add(button = new ShowMoreButton { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -46,16 +49,5 @@ namespace osu.Game.Tests.Visual.Online AddAssert("action fired twice", () => fireCount == 2); AddAssert("is in loading state", () => button.IsLoading); } - - private class TestButton : ShowMoreButton - { - [BackgroundDependencyLoader] - private void load(OsuColour colors) - { - IdleColour = colors.YellowDark; - HoverColour = colors.Yellow; - ChevronIconColour = colors.Red; - } - } } } diff --git a/osu.Game/Beatmaps/BeatmapDifficultyManager.cs b/osu.Game/Beatmaps/BeatmapDifficultyManager.cs index 5e644fbf1c..b80b4e45ed 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyManager.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyManager.cs @@ -109,25 +109,58 @@ namespace osu.Game.Beatmaps } private CancellationTokenSource trackedUpdateCancellationSource; + private readonly List linkedCancellationSources = new List(); /// /// Updates all tracked using the current ruleset and mods. /// private void updateTrackedBindables() { - trackedUpdateCancellationSource?.Cancel(); + cancelTrackedBindableUpdate(); trackedUpdateCancellationSource = new CancellationTokenSource(); foreach (var b in trackedBindables) { - if (trackedUpdateCancellationSource.IsCancellationRequested) - break; + var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(trackedUpdateCancellationSource.Token, b.CancellationToken); + linkedCancellationSources.Add(linkedSource); - using (var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(trackedUpdateCancellationSource.Token, b.CancellationToken)) - updateBindable(b, currentRuleset.Value, currentMods.Value, linkedSource.Token); + updateBindable(b, currentRuleset.Value, currentMods.Value, linkedSource.Token); } } + /// + /// Cancels the existing update of all tracked via . + /// + private void cancelTrackedBindableUpdate() + { + trackedUpdateCancellationSource?.Cancel(); + trackedUpdateCancellationSource = null; + + if (linkedCancellationSources != null) + { + foreach (var c in linkedCancellationSources) + c.Dispose(); + + linkedCancellationSources.Clear(); + } + } + + /// + /// Creates a new and triggers an initial value update. + /// + /// The that star difficulty should correspond to. + /// The initial to get the difficulty with. + /// The initial s to get the difficulty with. + /// An optional which stops updating the star difficulty for the given . + /// The . + private BindableStarDifficulty createBindable([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo initialRulesetInfo, [CanBeNull] IEnumerable initialMods, + CancellationToken cancellationToken) + { + var bindable = new BindableStarDifficulty(beatmapInfo, cancellationToken); + updateBindable(bindable, initialRulesetInfo, initialMods, cancellationToken); + return bindable; + } + /// /// Updates the value of a with a given ruleset + mods. /// @@ -148,22 +181,6 @@ namespace osu.Game.Beatmaps }, cancellationToken); } - /// - /// Creates a new and triggers an initial value update. - /// - /// The that star difficulty should correspond to. - /// The initial to get the difficulty with. - /// The initial s to get the difficulty with. - /// An optional which stops updating the star difficulty for the given . - /// The . - private BindableStarDifficulty createBindable([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo initialRulesetInfo, [CanBeNull] IEnumerable initialMods, - CancellationToken cancellationToken) - { - var bindable = new BindableStarDifficulty(beatmapInfo, cancellationToken); - updateBindable(bindable, initialRulesetInfo, initialMods, cancellationToken); - return bindable; - } - /// /// Computes the difficulty defined by a key, and stores it to the timed cache. /// @@ -220,6 +237,14 @@ namespace osu.Game.Beatmaps return difficultyCache.TryGetValue(key, out existingDifficulty); } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + cancelTrackedBindableUpdate(); + updateScheduler?.Dispose(); + } + private readonly struct DifficultyCacheLookup : IEquatable { public readonly int BeatmapId; diff --git a/osu.Game/Graphics/UserInterface/ShowMoreButton.cs b/osu.Game/Graphics/UserInterface/ShowMoreButton.cs index c9cd9f1158..924c7913f3 100644 --- a/osu.Game/Graphics/UserInterface/ShowMoreButton.cs +++ b/osu.Game/Graphics/UserInterface/ShowMoreButton.cs @@ -1,13 +1,15 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; using osuTK; -using osuTK.Graphics; using System.Collections.Generic; namespace osu.Game.Graphics.UserInterface @@ -16,14 +18,6 @@ namespace osu.Game.Graphics.UserInterface { private const int duration = 200; - private Color4 chevronIconColour; - - protected Color4 ChevronIconColour - { - get => chevronIconColour; - set => chevronIconColour = leftChevron.Colour = rightChevron.Colour = value; - } - public string Text { get => text.Text; @@ -32,22 +26,28 @@ namespace osu.Game.Graphics.UserInterface protected override IEnumerable EffectTargets => new[] { background }; - private ChevronIcon leftChevron; - private ChevronIcon rightChevron; + private ChevronIcon leftIcon; + private ChevronIcon rightIcon; private SpriteText text; private Box background; private FillFlowContainer textContainer; public ShowMoreButton() { - Height = 30; - Width = 140; + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + IdleColour = colourProvider.Background2; + HoverColour = colourProvider.Background1; } protected override Drawable CreateContent() => new CircularContainer { Masking = true, - RelativeSizeAxes = Axes.Both, + AutoSizeAxes = Axes.Both, Children = new Drawable[] { background = new Box @@ -56,22 +56,36 @@ namespace osu.Game.Graphics.UserInterface }, textContainer = new FillFlowContainer { + AlwaysPresent = true, Anchor = Anchor.Centre, Origin = Anchor.Centre, AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, - Spacing = new Vector2(7), + Spacing = new Vector2(10), + Margin = new MarginPadding + { + Horizontal = 20, + Vertical = 5 + }, Children = new Drawable[] { - leftChevron = new ChevronIcon(), + leftIcon = new ChevronIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, text = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), + Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold), Text = "show more".ToUpper(), }, - rightChevron = new ChevronIcon(), + rightIcon = new ChevronIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } } } } @@ -81,17 +95,40 @@ namespace osu.Game.Graphics.UserInterface protected override void OnLoadFinished() => textContainer.FadeIn(duration, Easing.OutQuint); - private class ChevronIcon : SpriteIcon + protected override bool OnHover(HoverEvent e) { - private const int icon_size = 8; + base.OnHover(e); + leftIcon.SetHoveredState(true); + rightIcon.SetHoveredState(true); + return true; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + base.OnHoverLost(e); + leftIcon.SetHoveredState(false); + rightIcon.SetHoveredState(false); + } + + public class ChevronIcon : SpriteIcon + { + [Resolved] + private OverlayColourProvider colourProvider { get; set; } public ChevronIcon() { - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - Size = new Vector2(icon_size); + Size = new Vector2(7.5f); Icon = FontAwesome.Solid.ChevronDown; } + + [BackgroundDependencyLoader] + private void load() + { + Colour = colourProvider.Foreground1; + } + + public void SetHoveredState(bool hovered) => + this.FadeColour(hovered ? colourProvider.Light1 : colourProvider.Foreground1, 200, Easing.OutQuint); } } } diff --git a/osu.Game/Overlays/Comments/Buttons/CommentRepliesButton.cs b/osu.Game/Overlays/Comments/Buttons/CommentRepliesButton.cs index 53438ca421..57bf2af4d2 100644 --- a/osu.Game/Overlays/Comments/Buttons/CommentRepliesButton.cs +++ b/osu.Game/Overlays/Comments/Buttons/CommentRepliesButton.cs @@ -5,12 +5,12 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osuTK; +using static osu.Game.Graphics.UserInterface.ShowMoreButton; namespace osu.Game.Overlays.Comments.Buttons { @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Comments.Buttons [Resolved] private OverlayColourProvider colourProvider { get; set; } - private readonly SpriteIcon icon; + private readonly ChevronIcon icon; private readonly Box background; private readonly OsuSpriteText text; @@ -68,12 +68,10 @@ namespace osu.Game.Overlays.Comments.Buttons AlwaysPresent = true, Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold) }, - icon = new SpriteIcon + icon = new ChevronIcon { Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Size = new Vector2(7.5f), - Icon = FontAwesome.Solid.ChevronDown + Origin = Anchor.CentreLeft } } } @@ -88,7 +86,6 @@ namespace osu.Game.Overlays.Comments.Buttons private void load() { background.Colour = colourProvider.Background2; - icon.Colour = colourProvider.Foreground1; } protected void SetIconDirection(bool upwards) => icon.ScaleTo(new Vector2(1, upwards ? -1 : 1)); @@ -99,7 +96,7 @@ namespace osu.Game.Overlays.Comments.Buttons { base.OnHover(e); background.FadeColour(colourProvider.Background1, 200, Easing.OutQuint); - icon.FadeColour(colourProvider.Light1, 200, Easing.OutQuint); + icon.SetHoveredState(true); return true; } @@ -107,7 +104,7 @@ namespace osu.Game.Overlays.Comments.Buttons { base.OnHoverLost(e); background.FadeColour(colourProvider.Background2, 200, Easing.OutQuint); - icon.FadeColour(colourProvider.Foreground1, 200, Easing.OutQuint); + icon.SetHoveredState(false); } } } diff --git a/osu.Game/Overlays/Comments/Buttons/ShowMoreButton.cs b/osu.Game/Overlays/Comments/Buttons/ShowMoreRepliesButton.cs similarity index 93% rename from osu.Game/Overlays/Comments/Buttons/ShowMoreButton.cs rename to osu.Game/Overlays/Comments/Buttons/ShowMoreRepliesButton.cs index 2c363564d2..c115a8bb8f 100644 --- a/osu.Game/Overlays/Comments/Buttons/ShowMoreButton.cs +++ b/osu.Game/Overlays/Comments/Buttons/ShowMoreRepliesButton.cs @@ -12,13 +12,13 @@ using osu.Framework.Allocation; namespace osu.Game.Overlays.Comments.Buttons { - public class ShowMoreButton : LoadingButton + public class ShowMoreRepliesButton : LoadingButton { protected override IEnumerable EffectTargets => new[] { text }; private OsuSpriteText text; - public ShowMoreButton() + public ShowMoreRepliesButton() { AutoSizeAxes = Axes.Both; LoadingAnimationSize = new Vector2(8); diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index f71808ba89..2a78748be6 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -78,21 +78,22 @@ namespace osu.Game.Overlays.Comments AutoSizeAxes = Axes.Y, Children = new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background4 - }, new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, + Margin = new MarginPadding { Bottom = 20 }, Children = new Drawable[] { deletedCommentsCounter = new DeletedCommentsCounter { - ShowDeleted = { BindTarget = ShowDeleted } + ShowDeleted = { BindTarget = ShowDeleted }, + Margin = new MarginPadding + { + Horizontal = 70, + Vertical = 10 + } }, new Container { @@ -102,7 +103,10 @@ namespace osu.Game.Overlays.Comments { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Margin = new MarginPadding(5), + Margin = new MarginPadding + { + Vertical = 10 + }, Action = getComments, IsLoading = true, } diff --git a/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs b/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs index d2ff7ecb1f..adf64eabb1 100644 --- a/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs +++ b/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Graphics.UserInterface; @@ -11,16 +10,6 @@ namespace osu.Game.Overlays.Comments { public readonly BindableInt Current = new BindableInt(); - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) - { - Height = 20; - - IdleColour = colourProvider.Background2; - HoverColour = colourProvider.Background1; - ChevronIconColour = colourProvider.Foreground1; - } - protected override void LoadComplete() { Current.BindValueChanged(onCurrentChanged, true); diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 9c0a48ec29..31aa41e967 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Comments private FillFlowContainer childCommentsVisibilityContainer; private FillFlowContainer childCommentsContainer; private LoadRepliesButton loadRepliesButton; - private ShowMoreButton showMoreButton; + private ShowMoreRepliesButton showMoreButton; private ShowRepliesButton showRepliesButton; private ChevronButton chevronButton; private DeletedCommentsCounter deletedCommentsCounter; @@ -213,7 +213,7 @@ namespace osu.Game.Overlays.Comments Top = 10 } }, - showMoreButton = new ShowMoreButton + showMoreButton = new ShowMoreRepliesButton { Action = () => RepliesRequested(this, ++currentPage) } diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index a30ff786fb..9720469548 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -14,12 +14,13 @@ using osu.Game.Users; using System.Collections.Generic; using System.Linq; using System.Threading; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Profile.Sections { public abstract class PaginatedContainer : FillFlowContainer { - private readonly ProfileShowMoreButton moreButton; + private readonly ShowMoreButton moreButton; private readonly OsuSpriteText missingText; private APIRequest> retrievalRequest; private CancellationTokenSource loadCancellation; @@ -74,7 +75,7 @@ namespace osu.Game.Overlays.Profile.Sections RelativeSizeAxes = Axes.X, Spacing = new Vector2(0, 2), }, - moreButton = new ProfileShowMoreButton + moreButton = new ShowMoreButton { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, diff --git a/osu.Game/Overlays/Profile/Sections/ProfileShowMoreButton.cs b/osu.Game/Overlays/Profile/Sections/ProfileShowMoreButton.cs deleted file mode 100644 index 426ebeebe6..0000000000 --- a/osu.Game/Overlays/Profile/Sections/ProfileShowMoreButton.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Game.Graphics.UserInterface; - -namespace osu.Game.Overlays.Profile.Sections -{ - public class ProfileShowMoreButton : ShowMoreButton - { - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) - { - IdleColour = colourProvider.Background2; - HoverColour = colourProvider.Background1; - ChevronIconColour = colourProvider.Foreground1; - } - } -} diff --git a/osu.Game/Screens/Play/HUD/FailingLayer.cs b/osu.Game/Screens/Play/HUD/FailingLayer.cs index 84dbb35f68..847b8a53cf 100644 --- a/osu.Game/Screens/Play/HUD/FailingLayer.cs +++ b/osu.Game/Screens/Play/HUD/FailingLayer.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Play.HUD private const float max_alpha = 0.4f; private const int fade_time = 400; - private const float gradient_size = 0.3f; + private const float gradient_size = 0.2f; /// /// The threshold under which the current player life should be considered low and the layer should start fading in. @@ -56,16 +56,16 @@ namespace osu.Game.Screens.Play.HUD new Box { RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(Color4.White, Color4.White.Opacity(0)), - Height = gradient_size, + Colour = ColourInfo.GradientHorizontal(Color4.White, Color4.White.Opacity(0)), + Width = gradient_size, }, new Box { RelativeSizeAxes = Axes.Both, - Height = gradient_size, - Colour = ColourInfo.GradientVertical(Color4.White.Opacity(0), Color4.White), - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, + Width = gradient_size, + Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(0), Color4.White), + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, }, } }, diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 5ac54a853f..1ececa448c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -24,7 +24,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 8b2d1346be..ef5ba10d17 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -80,7 +80,7 @@ - +