From 8a1fc7c340070e1f04d5ffca1488cfde70a054be Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Sat, 26 Aug 2023 01:20:41 +0300 Subject: [PATCH 01/29] Basic stuff (not working for now) --- osu.Game/Overlays/Mods/ModMapInfoDisplay.cs | 203 ++++++++++++++++++ osu.Game/Overlays/Mods/ModSelectOverlay.cs | 18 ++ osu.Game/Screens/Select/BeatmapDetails.cs | 6 + .../Screens/Select/Details/AdvancedStats.cs | 21 ++ osu.Game/Screens/Select/SongSelect.cs | 3 + 5 files changed, 251 insertions(+) create mode 100644 osu.Game/Overlays/Mods/ModMapInfoDisplay.cs diff --git a/osu.Game/Overlays/Mods/ModMapInfoDisplay.cs b/osu.Game/Overlays/Mods/ModMapInfoDisplay.cs new file mode 100644 index 0000000000..20666391d6 --- /dev/null +++ b/osu.Game/Overlays/Mods/ModMapInfoDisplay.cs @@ -0,0 +1,203 @@ +// 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.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Screens.Select.Details; +using osu.Game.Localisation; +using osuTK; + + +namespace osu.Game.Overlays.Mods +{ + public partial class ModMapInfoDisplay : Container, IHasCurrentValue + { + public const float HEIGHT = 42; + private const float transition_duration = 200; + + private readonly Box contentBackground; + private readonly Box labelBackground; + private readonly FillFlowContainer content; + + public Bindable Current + { + get => current.Current; + set => current.Current = value; + } + private readonly BindableWithCurrent current = new BindableWithCurrent(); + + [Resolved] + private OsuColour colours { get; set; } = null!; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + /// + /// Text to display in the left area of the display. + /// + //protected abstract LocalisableString Label { get; } + protected LocalisableString Label => CommonStrings.Finish; + //protected string Label { get; } + + protected virtual float ValueAreaWidth => 56; + + protected virtual string CounterFormat => @"N0"; + + protected override Container Content => content; + + protected readonly RollingCounter Counter; + + public ModMapInfoDisplay() + { + Height = HEIGHT; + AutoSizeAxes = Axes.X; + + InternalChild = new InputBlockingContainer + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Masking = true, + CornerRadius = ModSelectPanel.CORNER_RADIUS, + Shear = new Vector2(ShearedOverlayContainer.SHEAR, 0), + Children = new Drawable[] + { + contentBackground = new Box + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Y, + Width = ValueAreaWidth + ModSelectPanel.CORNER_RADIUS + }, + new GridContainer + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, ValueAreaWidth) + }, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Masking = true, + CornerRadius = ModSelectPanel.CORNER_RADIUS, + Children = new Drawable[] + { + labelBackground = new Box + { + RelativeSizeAxes = Axes.Both + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Horizontal = 18 }, + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), + Text = Label, + Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold) + } + } + }, + content = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Direction = FillDirection.Horizontal, + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), + Spacing = new Vector2(2, 0), + Child = Counter = new EffectCounter(CounterFormat) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Current = { BindTarget = Current.Value.StarRating } + } + } + } + } + } + } + }; + } + + [BackgroundDependencyLoader] + private void load() + { + labelBackground.Colour = colourProvider.Background4; + } + + protected override void LoadComplete() + { + Current.BindValueChanged(e => + { + //var effect = CalculateEffectForComparison(e.NewValue.CompareTo(Current.Default)); + setColours(e.NewValue.StarRating.Value); + }, true); + } + + /// + /// Fades colours of text and its background according to displayed value. + /// + /// random number. + private void setColours(double stars) + { + contentBackground.FadeColour(colours.ForStarDifficulty(stars), transition_duration, Easing.OutQuint); + } + + /// + /// Converts signed integer into . Negative values are counted as difficulty reduction, positive as increase. + /// + /// Value to convert. Will arrive from comparison between bindable once it changes and it's . + /// Effect of the value. + protected virtual ModEffect CalculateEffectForComparison(int comparison) + { + if (comparison == 0) + return ModEffect.NotChanged; + if (comparison < 0) + return ModEffect.DifficultyReduction; + + return ModEffect.DifficultyIncrease; + } + + protected enum ModEffect + { + NotChanged, + DifficultyReduction, + DifficultyIncrease + } + + private partial class EffectCounter : RollingCounter + { + private readonly string? format; + + public EffectCounter(string? format) + { + this.format = format; + } + + protected override double RollingDuration => 500; + + protected override LocalisableString FormatCount(double count) => count.ToLocalisableString(format); + + protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText + { + Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold) + }; + } + } +} diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 9e92e9d959..ef5f6cf323 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -25,6 +25,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Localisation; using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Select.Details; using osu.Game.Utils; using osuTK; using osuTK.Input; @@ -123,6 +124,7 @@ namespace osu.Game.Overlays.Mods private Container aboveColumnsContent = null!; private DifficultyMultiplierDisplay? multiplierDisplay; + private ModMapInfoDisplay mapInfoDisplay = null!; protected ShearedButton BackButton { get; private set; } = null!; protected ShearedToggleButton? CustomisationButton { get; private set; } @@ -219,6 +221,12 @@ namespace osu.Game.Overlays.Mods }); } + aboveColumnsContent.Add(mapInfoDisplay = new ModMapInfoDisplay + { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft + }); + FooterContent.Child = footerButtonFlow = new FillFlowContainer { RelativeSizeAxes = Axes.X, @@ -244,6 +252,10 @@ namespace osu.Game.Overlays.Mods globalAvailableMods.BindTo(game.AvailableMods); } + public void SetBindedMapStats(Bindable stats) + { + mapInfoDisplay.Current = stats; + } public override void Hide() { base.Hide(); @@ -399,6 +411,12 @@ namespace osu.Game.Overlays.Mods multiplierDisplay.Current.Value = multiplier; } + private void updateMapInfo() + { + if (mapInfoDisplay == null) + return; + } + private void updateCustomisation() { if (CustomisationButton == null) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 712b610515..c56411bef5 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -3,6 +3,7 @@ using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -273,6 +274,11 @@ namespace osu.Game.Screens.Select loading.Hide(); } + public Bindable GetBindedAdjustedMapStats() + { + return advanced.AdjustedMapStats.GetBoundCopy(); + } + private partial class DetailBox : Container { private readonly Container content; diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index a383298faa..016e4ff2df 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -113,6 +113,8 @@ namespace osu.Game.Screens.Select.Details updateStatistics(); } + public Bindable AdjustedMapStats = new Bindable(); + private void updateStatistics() { IBeatmapDifficultyInfo baseDifficulty = BeatmapInfo?.Difficulty; @@ -146,6 +148,14 @@ namespace osu.Game.Screens.Select.Details ApproachRate.Value = (baseDifficulty?.ApproachRate ?? 0, adjustedDifficulty?.ApproachRate); updateStarDifficulty(); + + var temp = AdjustedMapStats.Value; + temp.CS.Value = FirstValue.Value.adjustedValue ?? 0; + temp.HP.Value = HpDrain.Value.adjustedValue ?? 0; + temp.OD.Value = Accuracy.Value.adjustedValue ?? 0; + temp.AR.Value = ApproachRate.Value.adjustedValue ?? 5; + AdjustedMapStats.Value = temp; + } private CancellationTokenSource starDifficultyCancellationSource; @@ -178,6 +188,11 @@ namespace osu.Game.Screens.Select.Details return; starDifficulty.Value = ((float)normalDifficulty.Value.Stars, (float)moddedDifficulty.Value.Stars); + + var temp = AdjustedMapStats.Value; + temp.StarRating.Value = moddedDifficulty.Value.Stars; + AdjustedMapStats.Value = temp; + }), starDifficultyCancellationSource.Token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Current); }); @@ -296,4 +311,10 @@ namespace osu.Game.Screens.Select.Details } } } + public struct MapStats + { + public Bindable StarRating; + public Bindable MinBPM, MaxBPM, AvgBPM; + public Bindable CS, HP, AR, OD; + } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 58755878d0..17b1b1f870 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -305,6 +305,9 @@ namespace osu.Game.Screens.Select // therein it will be registered at the `OsuGame` level to properly function as a blocking overlay. LoadComponent(ModSelect = CreateModSelectOverlay()); + var bindedStats = BeatmapDetails.Details.GetBindedAdjustedMapStats(); + ModSelect.SetBindedMapStats(bindedStats); + if (Footer != null) { foreach (var (button, overlay) in CreateFooterButtons()) From 50235cc2459c43802099b7b803396fbacf208af6 Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Mon, 28 Aug 2023 23:16:33 +0300 Subject: [PATCH 02/29] somewhat working prototype --- osu.Game/Overlays/Mods/ModMapInfoContainer.cs | 58 ++++++++++++++++ osu.Game/Overlays/Mods/ModMapInfoDisplay.cs | 66 +++++++------------ osu.Game/Overlays/Mods/ModSelectOverlay.cs | 17 +++-- osu.Game/Screens/Select/BeatmapDetailArea.cs | 4 ++ osu.Game/Screens/Select/BeatmapDetails.cs | 5 -- .../Screens/Select/Details/AdvancedStats.cs | 40 +++++------ osu.Game/Screens/Select/SongSelect.cs | 8 ++- 7 files changed, 121 insertions(+), 77 deletions(-) create mode 100644 osu.Game/Overlays/Mods/ModMapInfoContainer.cs diff --git a/osu.Game/Overlays/Mods/ModMapInfoContainer.cs b/osu.Game/Overlays/Mods/ModMapInfoContainer.cs new file mode 100644 index 0000000000..eb5291b0a8 --- /dev/null +++ b/osu.Game/Overlays/Mods/ModMapInfoContainer.cs @@ -0,0 +1,58 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +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.Shapes; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Overlays.BeatmapSet; +using osu.Game.Resources.Localisation.Web; +using osu.Game.Screens.Select.Details; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Mods +{ + public partial class ModMapInfoContainer : Container + { + private ModMapInfoDisplay starRatingDisplay = null!; + + [Resolved] + private OsuColour colours { get; set; } = null!; + + [Resolved] + private Bindable adjustedInfo { get; set; } = null!; + private Bindable starRatingValue = new Bindable(); + + //public ModMapInfoContainer() + //{ + // + //} + + protected override void LoadComplete() + { + starRatingDisplay = new ModMapInfoDisplay("Star Rating", colours.ForStarDifficulty); + starRatingDisplay.Current.BindTo(starRatingValue); + + Content.Add(starRatingDisplay); + + adjustedInfo.BindValueChanged(e => { updateValues(); }, true); + } + + private void updateValues() + { + starRatingValue.Value = adjustedInfo.Value.StarRating; + } + } +} diff --git a/osu.Game/Overlays/Mods/ModMapInfoDisplay.cs b/osu.Game/Overlays/Mods/ModMapInfoDisplay.cs index 20666391d6..ca815984ce 100644 --- a/osu.Game/Overlays/Mods/ModMapInfoDisplay.cs +++ b/osu.Game/Overlays/Mods/ModMapInfoDisplay.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 System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.LocalisationExtensions; @@ -12,14 +13,13 @@ using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Select.Details; using osu.Game.Localisation; using osuTK; namespace osu.Game.Overlays.Mods { - public partial class ModMapInfoDisplay : Container, IHasCurrentValue + public partial class ModMapInfoDisplay : Container, IHasCurrentValue { public const float HEIGHT = 42; private const float transition_duration = 200; @@ -28,36 +28,40 @@ namespace osu.Game.Overlays.Mods private readonly Box labelBackground; private readonly FillFlowContainer content; - public Bindable Current - { - get => current.Current; - set => current.Current = value; - } - private readonly BindableWithCurrent current = new BindableWithCurrent(); + //public Bindable Current + //{ + // get => current.Current; + // set => current.Current = value; + //} + //private readonly BindableWithCurrent current = new BindableWithCurrent(); - [Resolved] - private OsuColour colours { get; set; } = null!; + public Bindable Current { get; set; } = new BindableWithCurrent(); + + //[Resolved] + //private OsuColour colours { get; set; } = null!; [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; + protected Func GetColor; + /// /// Text to display in the left area of the display. /// - //protected abstract LocalisableString Label { get; } - protected LocalisableString Label => CommonStrings.Finish; - //protected string Label { get; } + protected LocalisableString Label; protected virtual float ValueAreaWidth => 56; - protected virtual string CounterFormat => @"N0"; + protected virtual string CounterFormat => @"0.00"; protected override Container Content => content; protected readonly RollingCounter Counter; - public ModMapInfoDisplay() + public ModMapInfoDisplay(LocalisableString label, Func colorFunc) { + Label = label; + GetColor = colorFunc; Height = HEIGHT; AutoSizeAxes = Axes.X; @@ -125,7 +129,7 @@ namespace osu.Game.Overlays.Mods { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Current = { BindTarget = Current.Value.StarRating } + Current = { BindTarget = Current } } } } @@ -146,39 +150,17 @@ namespace osu.Game.Overlays.Mods Current.BindValueChanged(e => { //var effect = CalculateEffectForComparison(e.NewValue.CompareTo(Current.Default)); - setColours(e.NewValue.StarRating.Value); + setColours(e.NewValue); }, true); } /// /// Fades colours of text and its background according to displayed value. /// - /// random number. - private void setColours(double stars) + /// value + private void setColours(double value) { - contentBackground.FadeColour(colours.ForStarDifficulty(stars), transition_duration, Easing.OutQuint); - } - - /// - /// Converts signed integer into . Negative values are counted as difficulty reduction, positive as increase. - /// - /// Value to convert. Will arrive from comparison between bindable once it changes and it's . - /// Effect of the value. - protected virtual ModEffect CalculateEffectForComparison(int comparison) - { - if (comparison == 0) - return ModEffect.NotChanged; - if (comparison < 0) - return ModEffect.DifficultyReduction; - - return ModEffect.DifficultyIncrease; - } - - protected enum ModEffect - { - NotChanged, - DifficultyReduction, - DifficultyIncrease + contentBackground.FadeColour(GetColor(value), transition_duration, Easing.OutQuint); } private partial class EffectCounter : RollingCounter diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index ef5f6cf323..a178f2e9dc 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -25,9 +25,9 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Localisation; using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Select.Details; using osu.Game.Utils; using osuTK; +using osuTK.Graphics; using osuTK.Input; namespace osu.Game.Overlays.Mods @@ -124,7 +124,8 @@ namespace osu.Game.Overlays.Mods private Container aboveColumnsContent = null!; private DifficultyMultiplierDisplay? multiplierDisplay; - private ModMapInfoDisplay mapInfoDisplay = null!; + + private ModMapInfoContainer mapInfoContainer = null!; protected ShearedButton BackButton { get; private set; } = null!; protected ShearedToggleButton? CustomisationButton { get; private set; } @@ -221,7 +222,7 @@ namespace osu.Game.Overlays.Mods }); } - aboveColumnsContent.Add(mapInfoDisplay = new ModMapInfoDisplay + aboveColumnsContent.Add(mapInfoContainer = new ModMapInfoContainer { Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft @@ -251,11 +252,6 @@ namespace osu.Game.Overlays.Mods globalAvailableMods.BindTo(game.AvailableMods); } - - public void SetBindedMapStats(Bindable stats) - { - mapInfoDisplay.Current = stats; - } public override void Hide() { base.Hide(); @@ -282,6 +278,7 @@ namespace osu.Game.Overlays.Mods SelectedMods.BindValueChanged(_ => { + updateMapInfo(); updateMultiplier(); updateFromExternalSelection(); updateCustomisation(); @@ -413,8 +410,10 @@ namespace osu.Game.Overlays.Mods private void updateMapInfo() { - if (mapInfoDisplay == null) + if (mapInfoContainer == null) return; + + //mapInfoDisplay.Current.Value = 5; } private void updateCustomisation() diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs index 595b86924b..d43831e576 100644 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -30,6 +31,9 @@ namespace osu.Game.Screens.Select public readonly BeatmapDetails Details; + //[Cached] + //public Bindable AdjustedInfo { get; private set; } = new Bindable(); + protected Bindable CurrentTab => tabControl.Current; protected Bindable CurrentModsFilter => tabControl.CurrentModsFilter; diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index c56411bef5..6ebdca1b8d 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -274,11 +274,6 @@ namespace osu.Game.Screens.Select loading.Hide(); } - public Bindable GetBindedAdjustedMapStats() - { - return advanced.AdjustedMapStats.GetBoundCopy(); - } - private partial class DetailBox : Container { private readonly Container content; diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index 016e4ff2df..8f609888df 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -46,6 +46,11 @@ namespace osu.Game.Screens.Select.Details private IBeatmapInfo beatmapInfo; +#nullable enable + [Resolved] + private Bindable? adjustedInfo { get; set; } = null; +#nullable disable + public IBeatmapInfo BeatmapInfo { get => beatmapInfo; @@ -99,6 +104,21 @@ namespace osu.Game.Screens.Select.Details private ModSettingChangeTracker modSettingChangeTracker; private ScheduledDelegate debouncedStatisticsUpdate; + private void updateBindedInfo() + { + if (adjustedInfo == null) return; + + BeatmapInfo adjusted = (BeatmapInfo)beatmapInfo; + adjusted.Difficulty.CircleSize = FirstValue.Value.adjustedValue ?? 0; + adjusted.Difficulty.DrainRate = HpDrain.Value.adjustedValue ?? 0; + adjusted.Difficulty.ApproachRate = ApproachRate.Value.adjustedValue ?? 5; + adjusted.Difficulty.OverallDifficulty = Accuracy.Value.adjustedValue ?? 0; + adjusted.StarRating = starDifficulty.Value.adjustedValue ?? 0; + + adjustedInfo.Value = adjusted; + adjustedInfo.TriggerChange(); + } + private void modsChanged(ValueChangedEvent> mods) { modSettingChangeTracker?.Dispose(); @@ -113,8 +133,6 @@ namespace osu.Game.Screens.Select.Details updateStatistics(); } - public Bindable AdjustedMapStats = new Bindable(); - private void updateStatistics() { IBeatmapDifficultyInfo baseDifficulty = BeatmapInfo?.Difficulty; @@ -149,13 +167,6 @@ namespace osu.Game.Screens.Select.Details updateStarDifficulty(); - var temp = AdjustedMapStats.Value; - temp.CS.Value = FirstValue.Value.adjustedValue ?? 0; - temp.HP.Value = HpDrain.Value.adjustedValue ?? 0; - temp.OD.Value = Accuracy.Value.adjustedValue ?? 0; - temp.AR.Value = ApproachRate.Value.adjustedValue ?? 5; - AdjustedMapStats.Value = temp; - } private CancellationTokenSource starDifficultyCancellationSource; @@ -188,10 +199,7 @@ namespace osu.Game.Screens.Select.Details return; starDifficulty.Value = ((float)normalDifficulty.Value.Stars, (float)moddedDifficulty.Value.Stars); - - var temp = AdjustedMapStats.Value; - temp.StarRating.Value = moddedDifficulty.Value.Stars; - AdjustedMapStats.Value = temp; + updateBindedInfo(); }), starDifficultyCancellationSource.Token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Current); }); @@ -311,10 +319,4 @@ namespace osu.Game.Screens.Select.Details } } } - public struct MapStats - { - public Bindable StarRating; - public Bindable MinBPM, MaxBPM, AvgBPM; - public Bindable CS, HP, AR, OD; - } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 17b1b1f870..4567869e8e 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -99,6 +99,9 @@ namespace osu.Game.Screens.Select [Resolved] private Bindable> selectedMods { get; set; } = null!; + [Cached] + private Bindable adjustedInfo { get; set; } = new Bindable(); + protected BeatmapCarousel Carousel { get; private set; } = null!; private ParallaxContainer wedgeBackground = null!; @@ -305,8 +308,8 @@ namespace osu.Game.Screens.Select // therein it will be registered at the `OsuGame` level to properly function as a blocking overlay. LoadComponent(ModSelect = CreateModSelectOverlay()); - var bindedStats = BeatmapDetails.Details.GetBindedAdjustedMapStats(); - ModSelect.SetBindedMapStats(bindedStats); + //var bindedStats = BeatmapDetails.Details.GetBindedAdjustedMapStats(); + //ModSelect.SetBindedMapStats(bindedStats); if (Footer != null) { @@ -583,6 +586,7 @@ namespace osu.Game.Screens.Select FilterControl.Activate(); ModSelect.SelectedMods.BindTo(selectedMods); + //BeatmapDetails.AdjustedInfo.BindTo(adjustedInfo); beginLooping(); } From b0398b62595bbf099ce957cafe9af3ea9769f16a Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Sun, 3 Sep 2023 02:09:01 +0300 Subject: [PATCH 03/29] functionality is done --- osu.Game/Beatmaps/BeatmapShortInfo.cs | 29 +++ osu.Game/Overlays/Mods/ModMapInfoContainer.cs | 171 +++++++++++++--- osu.Game/Overlays/Mods/ModMapInfoDisplay.cs | 185 ------------------ osu.Game/Overlays/Mods/ModSelectOverlay.cs | 17 +- .../Overlays/Mods/VerticalAttributeDisplay.cs | 76 +++++++ osu.Game/Screens/Select/BeatmapDetailArea.cs | 4 - .../Screens/Select/Details/AdvancedStats.cs | 33 ++-- osu.Game/Screens/Select/SongSelect.cs | 2 +- 8 files changed, 287 insertions(+), 230 deletions(-) create mode 100644 osu.Game/Beatmaps/BeatmapShortInfo.cs delete mode 100644 osu.Game/Overlays/Mods/ModMapInfoDisplay.cs create mode 100644 osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs diff --git a/osu.Game/Beatmaps/BeatmapShortInfo.cs b/osu.Game/Beatmaps/BeatmapShortInfo.cs new file mode 100644 index 0000000000..633e12d1b2 --- /dev/null +++ b/osu.Game/Beatmaps/BeatmapShortInfo.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 System; + +namespace osu.Game.Beatmaps +{ + public class BeatmapShortInfo : IEquatable + { + public StarDifficulty StarDifficulty; + public float CircleSize; + public float DrainRate; + public float ApproachRate; + public float OverallDifficulty; + public double BPM; + public bool Equals(BeatmapShortInfo? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + + return StarDifficulty.Stars == other.StarDifficulty.Stars && + CircleSize.Equals(other.CircleSize) && + DrainRate.Equals(other.DrainRate) && + ApproachRate.Equals(other.ApproachRate) && + OverallDifficulty.Equals(other.OverallDifficulty) && + BPM.Equals(other.BPM); + } + } +} diff --git a/osu.Game/Overlays/Mods/ModMapInfoContainer.cs b/osu.Game/Overlays/Mods/ModMapInfoContainer.cs index eb5291b0a8..378e6f6057 100644 --- a/osu.Game/Overlays/Mods/ModMapInfoContainer.cs +++ b/osu.Game/Overlays/Mods/ModMapInfoContainer.cs @@ -1,24 +1,21 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; +#nullable disable + using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Online; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests; -using osu.Game.Overlays.BeatmapSet; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Screens.Select.Details; using osuTK; using osuTK.Graphics; @@ -26,33 +23,161 @@ namespace osu.Game.Overlays.Mods { public partial class ModMapInfoContainer : Container { - private ModMapInfoDisplay starRatingDisplay = null!; + private Container content; + private Container innerContent; + + private Box background; + private Box innerBackground; + + private StarRatingDisplay starRatingDisplay; + private BPMDisplay bpmDisplay; + + private VerticalAttributeDisplay circleSizeDisplay; + private VerticalAttributeDisplay drainRateDisplay; + private VerticalAttributeDisplay approachRateDisplay; + private VerticalAttributeDisplay overallDifficultyDisplay; [Resolved] - private OsuColour colours { get; set; } = null!; + private OverlayColourProvider colourProvider { get; set; } [Resolved] - private Bindable adjustedInfo { get; set; } = null!; - private Bindable starRatingValue = new Bindable(); + private Bindable adjustedInfo { get; set; } - //public ModMapInfoContainer() - //{ - // - //} + public ModMapInfoContainer() + { + // values as ModSelectOverlay footer buttons + const float shear = ShearedOverlayContainer.SHEAR; + const float corner_radius = 7; + const float border_thickness = 2; + InternalChild = content = new InputBlockingContainer + { + Origin = Anchor.BottomRight, + Anchor = Anchor.BottomRight, + AutoSizeAxes = Axes.X, + Height = 50, // as ModSelectOverlay footer buttons + Shear = new Vector2(shear, 0), + CornerRadius = corner_radius, + BorderThickness = border_thickness, + Masking = true, + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both + }, + new FillFlowContainer // divide inner and outer content + { + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + innerContent = new Container + { + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + BorderThickness = border_thickness, + CornerRadius = corner_radius, + Masking = true, + Children = new Drawable[] + { + innerBackground = new Box + { + RelativeSizeAxes = Axes.Both + }, + new FillFlowContainer // actual inner content + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + AutoSizeAxes = Axes.X, + Direction = FillDirection.Horizontal, + Margin = new MarginPadding { Horizontal = 15 }, + Children = new Drawable[] + { + new Container // wrap to reserve space for StarRatingDisplay + { + Width = 70, // can be up to 70px on extra high SR + Child = starRatingDisplay = new StarRatingDisplay(default, animated: true) + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Shear = new Vector2(-shear, 0), + } + }, + new Container // wrap to reserve space for BPM + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Width = 70, + Child = bpmDisplay = new BPMDisplay + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Shear = new Vector2(-shear, 0), + } + } + } + } + } + }, + new FillFlowContainer // outer content + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Children = new[] + { + circleSizeDisplay = new VerticalAttributeDisplay("CS"), + drainRateDisplay = new VerticalAttributeDisplay("HP"), + approachRateDisplay = new VerticalAttributeDisplay("AR"), + overallDifficultyDisplay = new VerticalAttributeDisplay("OD"), + } + } + } + } + } + }; + } protected override void LoadComplete() { - starRatingDisplay = new ModMapInfoDisplay("Star Rating", colours.ForStarDifficulty); - starRatingDisplay.Current.BindTo(starRatingValue); + adjustedInfo.BindValueChanged(e => { UpdateValues(); }, true); - Content.Add(starRatingDisplay); + background.Colour = colourProvider.Background4; + innerBackground.Colour = colourProvider.Background3; + Color4 glow_colour = colourProvider.Background1; - adjustedInfo.BindValueChanged(e => { updateValues(); }, true); + content.BorderColour = ColourInfo.GradientVertical(background.Colour, glow_colour); + innerContent.BorderColour = ColourInfo.GradientVertical(innerBackground.Colour, glow_colour); } - private void updateValues() + public void UpdateValues() { - starRatingValue.Value = adjustedInfo.Value.StarRating; + if (adjustedInfo.Value == null) return; + + starRatingDisplay.Current.Value = adjustedInfo.Value.StarDifficulty; + bpmDisplay.Current.Value = adjustedInfo.Value.BPM; + + circleSizeDisplay.Current.Value = adjustedInfo.Value.CircleSize; + drainRateDisplay.Current.Value = adjustedInfo.Value.DrainRate; + approachRateDisplay.Current.Value = adjustedInfo.Value.ApproachRate; + overallDifficultyDisplay.Current.Value = adjustedInfo.Value.OverallDifficulty; + } + + private partial class BPMDisplay : RollingCounter + { + protected override double RollingDuration => 500; + + protected override LocalisableString FormatCount(double count) => count.ToLocalisableString("0 BPM"); + + protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText + { + Font = OsuFont.Default.With(size: 20, weight: FontWeight.SemiBold) + }; } } } diff --git a/osu.Game/Overlays/Mods/ModMapInfoDisplay.cs b/osu.Game/Overlays/Mods/ModMapInfoDisplay.cs deleted file mode 100644 index ca815984ce..0000000000 --- a/osu.Game/Overlays/Mods/ModMapInfoDisplay.cs +++ /dev/null @@ -1,185 +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 osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.LocalisationExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Localisation; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; -using osuTK; - - -namespace osu.Game.Overlays.Mods -{ - public partial class ModMapInfoDisplay : Container, IHasCurrentValue - { - public const float HEIGHT = 42; - private const float transition_duration = 200; - - private readonly Box contentBackground; - private readonly Box labelBackground; - private readonly FillFlowContainer content; - - //public Bindable Current - //{ - // get => current.Current; - // set => current.Current = value; - //} - //private readonly BindableWithCurrent current = new BindableWithCurrent(); - - public Bindable Current { get; set; } = new BindableWithCurrent(); - - //[Resolved] - //private OsuColour colours { get; set; } = null!; - - [Resolved] - private OverlayColourProvider colourProvider { get; set; } = null!; - - protected Func GetColor; - - /// - /// Text to display in the left area of the display. - /// - protected LocalisableString Label; - - protected virtual float ValueAreaWidth => 56; - - protected virtual string CounterFormat => @"0.00"; - - protected override Container Content => content; - - protected readonly RollingCounter Counter; - - public ModMapInfoDisplay(LocalisableString label, Func colorFunc) - { - Label = label; - GetColor = colorFunc; - Height = HEIGHT; - AutoSizeAxes = Axes.X; - - InternalChild = new InputBlockingContainer - { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Masking = true, - CornerRadius = ModSelectPanel.CORNER_RADIUS, - Shear = new Vector2(ShearedOverlayContainer.SHEAR, 0), - Children = new Drawable[] - { - contentBackground = new Box - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.Y, - Width = ValueAreaWidth + ModSelectPanel.CORNER_RADIUS - }, - new GridContainer - { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.Absolute, ValueAreaWidth) - }, - Content = new[] - { - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Masking = true, - CornerRadius = ModSelectPanel.CORNER_RADIUS, - Children = new Drawable[] - { - labelBackground = new Box - { - RelativeSizeAxes = Axes.Both - }, - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Margin = new MarginPadding { Horizontal = 18 }, - Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), - Text = Label, - Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold) - } - } - }, - content = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Direction = FillDirection.Horizontal, - Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), - Spacing = new Vector2(2, 0), - Child = Counter = new EffectCounter(CounterFormat) - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Current = { BindTarget = Current } - } - } - } - } - } - } - }; - } - - [BackgroundDependencyLoader] - private void load() - { - labelBackground.Colour = colourProvider.Background4; - } - - protected override void LoadComplete() - { - Current.BindValueChanged(e => - { - //var effect = CalculateEffectForComparison(e.NewValue.CompareTo(Current.Default)); - setColours(e.NewValue); - }, true); - } - - /// - /// Fades colours of text and its background according to displayed value. - /// - /// value - private void setColours(double value) - { - contentBackground.FadeColour(GetColor(value), transition_duration, Easing.OutQuint); - } - - private partial class EffectCounter : RollingCounter - { - private readonly string? format; - - public EffectCounter(string? format) - { - this.format = format; - } - - protected override double RollingDuration => 500; - - protected override LocalisableString FormatCount(double count) => count.ToLocalisableString(format); - - protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText - { - Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold) - }; - } - } -} diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index a178f2e9dc..426c424541 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -222,13 +222,18 @@ namespace osu.Game.Overlays.Mods }); } - aboveColumnsContent.Add(mapInfoContainer = new ModMapInfoContainer + FooterContent.Add(mapInfoContainer = new ModMapInfoContainer { - Anchor = Anchor.TopLeft, - Origin = Anchor.TopLeft + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Padding = new MarginPadding + { + Vertical = PADDING, + Horizontal = 70 + }, }); - FooterContent.Child = footerButtonFlow = new FillFlowContainer + FooterContent.Add(footerButtonFlow = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -248,7 +253,7 @@ namespace osu.Game.Overlays.Mods DarkerColour = colours.Pink2, LighterColour = colours.Pink1 }) - }; + }); globalAvailableMods.BindTo(game.AvailableMods); } @@ -413,7 +418,7 @@ namespace osu.Game.Overlays.Mods if (mapInfoContainer == null) return; - //mapInfoDisplay.Current.Value = 5; + mapInfoContainer.UpdateValues(); } private void updateCustomisation() diff --git a/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs b/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs new file mode 100644 index 0000000000..2ad420657c --- /dev/null +++ b/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs @@ -0,0 +1,76 @@ +// 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.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osuTK; + + +namespace osu.Game.Overlays.Mods +{ + public partial class VerticalAttributeDisplay : Container, IHasCurrentValue + { + public Bindable Current + { + get => current.Current; + set => current.Current = value; + } + private readonly BindableWithCurrent current = new BindableWithCurrent(); + + /// + /// Text to display in the top area of the display. + /// + public LocalisableString Label { get; protected set; } + + public VerticalAttributeDisplay(LocalisableString label) + { + Label = label; + AutoSizeAxes = Axes.X; + Origin = Anchor = Anchor.CentreLeft; + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0); + InternalChild = new FillFlowContainer + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new OsuSpriteText + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Text = Label, + Margin = new MarginPadding { Horizontal = 15 }, // to reserve space for 0.XX value + Font = OsuFont.Default.With(size: 20, weight: FontWeight.Bold) + }, + new EffectCounter() + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Current = { BindTarget = Current } + } + } + }; + } + + private partial class EffectCounter : RollingCounter + { + protected override double RollingDuration => 500; + + protected override LocalisableString FormatCount(double count) => count.ToLocalisableString("0.##"); + + protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText + { + Font = OsuFont.Default.With(size: 18, weight: FontWeight.SemiBold) + }; + } + } +} diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs index d43831e576..595b86924b 100644 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs @@ -4,7 +4,6 @@ #nullable disable using System; -using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -31,9 +30,6 @@ namespace osu.Game.Screens.Select public readonly BeatmapDetails Details; - //[Cached] - //public Bindable AdjustedInfo { get; private set; } = new Bindable(); - protected Bindable CurrentTab => tabControl.Current; protected Bindable CurrentModsFilter => tabControl.CurrentModsFilter; diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index 8f609888df..31fac8b4a0 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -46,10 +46,8 @@ namespace osu.Game.Screens.Select.Details private IBeatmapInfo beatmapInfo; -#nullable enable - [Resolved] - private Bindable? adjustedInfo { get; set; } = null; -#nullable disable + [Resolved(canBeNull: true)] + private Bindable adjustedInfo { get; set; } = null; public IBeatmapInfo BeatmapInfo { @@ -104,19 +102,30 @@ namespace osu.Game.Screens.Select.Details private ModSettingChangeTracker modSettingChangeTracker; private ScheduledDelegate debouncedStatisticsUpdate; + private StarDifficulty latestStarDifficulty = new StarDifficulty(); private void updateBindedInfo() { if (adjustedInfo == null) return; - BeatmapInfo adjusted = (BeatmapInfo)beatmapInfo; - adjusted.Difficulty.CircleSize = FirstValue.Value.adjustedValue ?? 0; - adjusted.Difficulty.DrainRate = HpDrain.Value.adjustedValue ?? 0; - adjusted.Difficulty.ApproachRate = ApproachRate.Value.adjustedValue ?? 5; - adjusted.Difficulty.OverallDifficulty = Accuracy.Value.adjustedValue ?? 0; - adjusted.StarRating = starDifficulty.Value.adjustedValue ?? 0; + // sadly need to calculate this to prevent additional data transportation + double rate = 1; + foreach (var mod in mods.Value.OfType()) + rate = mod.ApplyToRate(0, rate); + + double bpm = 0; + if (beatmapInfo != null) bpm = beatmapInfo.BPM * rate; + + BeatmapShortInfo adjusted = new BeatmapShortInfo() + { + CircleSize = FirstValue.Value.adjustedValue ?? FirstValue.Value.baseValue, + DrainRate = HpDrain.Value.adjustedValue ?? HpDrain.Value.baseValue, + ApproachRate = ApproachRate.Value.adjustedValue ?? ApproachRate.Value.baseValue, + OverallDifficulty = Accuracy.Value.adjustedValue ?? Accuracy.Value.baseValue, + BPM = bpm, + StarDifficulty = latestStarDifficulty + }; adjustedInfo.Value = adjusted; - adjustedInfo.TriggerChange(); } private void modsChanged(ValueChangedEvent> mods) @@ -165,6 +174,7 @@ namespace osu.Game.Screens.Select.Details Accuracy.Value = (baseDifficulty?.OverallDifficulty ?? 0, adjustedDifficulty?.OverallDifficulty); ApproachRate.Value = (baseDifficulty?.ApproachRate ?? 0, adjustedDifficulty?.ApproachRate); + updateBindedInfo(); // to faster UI response (without SR calculation) updateStarDifficulty(); } @@ -199,6 +209,7 @@ namespace osu.Game.Screens.Select.Details return; starDifficulty.Value = ((float)normalDifficulty.Value.Stars, (float)moddedDifficulty.Value.Stars); + latestStarDifficulty = moddedDifficulty ?? default; updateBindedInfo(); }), starDifficultyCancellationSource.Token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Current); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 4567869e8e..ad98d1721b 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -100,7 +100,7 @@ namespace osu.Game.Screens.Select private Bindable> selectedMods { get; set; } = null!; [Cached] - private Bindable adjustedInfo { get; set; } = new Bindable(); + private Bindable adjustedInfo { get; set; } = new Bindable(); protected BeatmapCarousel Carousel { get; private set; } = null!; From 0779cd8f4f998c2d9b29fd71787681875bec9979 Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Sun, 3 Sep 2023 02:17:04 +0300 Subject: [PATCH 04/29] minor design fixes --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 59 ++++++++++++---------- osu.Game/Screens/Select/SongSelect.cs | 4 -- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 426c424541..8de4447b31 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -222,41 +222,44 @@ namespace osu.Game.Overlays.Mods }); } - FooterContent.Add(mapInfoContainer = new ModMapInfoContainer + FooterContent.Children = new Drawable[] { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Padding = new MarginPadding + mapInfoContainer = new ModMapInfoContainer { - Vertical = PADDING, - Horizontal = 70 + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Padding = new MarginPadding + { + Vertical = PADDING, + Horizontal = 70 + } }, - }); - - FooterContent.Add(footerButtonFlow = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Padding = new MarginPadding + footerButtonFlow = new FillFlowContainer { - Vertical = PADDING, - Horizontal = 70 - }, - Spacing = new Vector2(10), - ChildrenEnumerable = CreateFooterButtons().Prepend(BackButton = new ShearedButton(BUTTON_WIDTH) - { - Text = CommonStrings.Back, - Action = Hide, - DarkerColour = colours.Pink2, - LighterColour = colours.Pink1 - }) - }); + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Padding = new MarginPadding + { + Vertical = PADDING, + Horizontal = 70 + }, + Spacing = new Vector2(10), + ChildrenEnumerable = CreateFooterButtons().Prepend(BackButton = new ShearedButton(BUTTON_WIDTH) + { + Text = CommonStrings.Back, + Action = Hide, + DarkerColour = colours.Pink2, + LighterColour = colours.Pink1 + }) + } + }; globalAvailableMods.BindTo(game.AvailableMods); } + public override void Hide() { base.Hide(); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index ad98d1721b..7749e3937a 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -308,9 +308,6 @@ namespace osu.Game.Screens.Select // therein it will be registered at the `OsuGame` level to properly function as a blocking overlay. LoadComponent(ModSelect = CreateModSelectOverlay()); - //var bindedStats = BeatmapDetails.Details.GetBindedAdjustedMapStats(); - //ModSelect.SetBindedMapStats(bindedStats); - if (Footer != null) { foreach (var (button, overlay) in CreateFooterButtons()) @@ -586,7 +583,6 @@ namespace osu.Game.Screens.Select FilterControl.Activate(); ModSelect.SelectedMods.BindTo(selectedMods); - //BeatmapDetails.AdjustedInfo.BindTo(adjustedInfo); beginLooping(); } From 5e5fe84a88d15af428ee6bff7ecd3e46b26bbf65 Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Sun, 3 Sep 2023 02:19:02 +0300 Subject: [PATCH 05/29] Update AdvancedStats.cs --- osu.Game/Screens/Select/Details/AdvancedStats.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index 31fac8b4a0..a12323ab70 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -176,7 +176,6 @@ namespace osu.Game.Screens.Select.Details updateBindedInfo(); // to faster UI response (without SR calculation) updateStarDifficulty(); - } private CancellationTokenSource starDifficultyCancellationSource; From 079792644886a6c57fb03eee397d9594419e5847 Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Sun, 3 Sep 2023 12:19:03 +0300 Subject: [PATCH 06/29] Update VerticalAttributeDisplay.cs --- osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs b/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs index 2ad420657c..95d979ebd2 100644 --- a/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs +++ b/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs @@ -12,7 +12,6 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osuTK; - namespace osu.Game.Overlays.Mods { public partial class VerticalAttributeDisplay : Container, IHasCurrentValue From 8281ed5173af43556f8b2e5ba937a2e66eff7f3a Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Sun, 3 Sep 2023 14:51:53 +0300 Subject: [PATCH 07/29] Fixed "no animations" issue --- osu.Game/Overlays/Mods/ModMapInfoContainer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Mods/ModMapInfoContainer.cs b/osu.Game/Overlays/Mods/ModMapInfoContainer.cs index 378e6f6057..281fe8abe5 100644 --- a/osu.Game/Overlays/Mods/ModMapInfoContainer.cs +++ b/osu.Game/Overlays/Mods/ModMapInfoContainer.cs @@ -50,6 +50,7 @@ namespace osu.Game.Overlays.Mods const float corner_radius = 7; const float border_thickness = 2; + AutoSizeAxes = Axes.Both; InternalChild = content = new InputBlockingContainer { Origin = Anchor.BottomRight, From 02e2b8546c4089598a60fe99e18a813b59e7ea1b Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Fri, 8 Sep 2023 20:32:55 +0300 Subject: [PATCH 08/29] fixed all stated problems --- osu.Game/Beatmaps/BeatmapShortInfo.cs | 29 ------- ...oContainer.cs => ModEffectPreviewPanel.cs} | 82 +++++++++++++++---- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 38 +++++---- osu.Game/Screens/Select/BeatmapDetails.cs | 1 - .../Screens/Select/Details/AdvancedStats.cs | 33 -------- osu.Game/Screens/Select/SongSelect.cs | 5 +- 6 files changed, 90 insertions(+), 98 deletions(-) delete mode 100644 osu.Game/Beatmaps/BeatmapShortInfo.cs rename osu.Game/Overlays/Mods/{ModMapInfoContainer.cs => ModEffectPreviewPanel.cs} (75%) diff --git a/osu.Game/Beatmaps/BeatmapShortInfo.cs b/osu.Game/Beatmaps/BeatmapShortInfo.cs deleted file mode 100644 index 633e12d1b2..0000000000 --- a/osu.Game/Beatmaps/BeatmapShortInfo.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; - -namespace osu.Game.Beatmaps -{ - public class BeatmapShortInfo : IEquatable - { - public StarDifficulty StarDifficulty; - public float CircleSize; - public float DrainRate; - public float ApproachRate; - public float OverallDifficulty; - public double BPM; - public bool Equals(BeatmapShortInfo? other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - - return StarDifficulty.Stars == other.StarDifficulty.Stars && - CircleSize.Equals(other.CircleSize) && - DrainRate.Equals(other.DrainRate) && - ApproachRate.Equals(other.ApproachRate) && - OverallDifficulty.Equals(other.OverallDifficulty) && - BPM.Equals(other.BPM); - } - } -} diff --git a/osu.Game/Overlays/Mods/ModMapInfoContainer.cs b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs similarity index 75% rename from osu.Game/Overlays/Mods/ModMapInfoContainer.cs rename to osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs index 281fe8abe5..b6a8dfe827 100644 --- a/osu.Game/Overlays/Mods/ModMapInfoContainer.cs +++ b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs @@ -1,8 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.LocalisationExtensions; @@ -16,12 +16,14 @@ using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets.Mods; using osuTK; using osuTK.Graphics; +using System.Threading; namespace osu.Game.Overlays.Mods { - public partial class ModMapInfoContainer : Container + public partial class ModEffectPreviewPanel : CompositeDrawable { private Container content; private Container innerContent; @@ -37,13 +39,37 @@ namespace osu.Game.Overlays.Mods private VerticalAttributeDisplay approachRateDisplay; private VerticalAttributeDisplay overallDifficultyDisplay; - [Resolved] - private OverlayColourProvider colourProvider { get; set; } + public const float HEIGHT = 50; // as ModSelectOverlay footer buttons + private const float transition_duration = 250; + + private IBeatmapInfo beatmapInfo = null!; + + public IBeatmapInfo BeatmapInfo + { + get => beatmapInfo; + set + { + if (value == beatmapInfo) return; + + beatmapInfo = value; + updateStarDifficultyBind(); + UpdateValues(); + } + } [Resolved] - private Bindable adjustedInfo { get; set; } + private Bindable> mods { get; set; } = null!; - public ModMapInfoContainer() + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + [Resolved] + private BeatmapDifficultyCache difficultyCache { get; set; } = null!; + + private CancellationTokenSource cancellationSource = null!; + private IBindable starDifficulty = null!; + + public ModEffectPreviewPanel() { // values as ModSelectOverlay footer buttons const float shear = ShearedOverlayContainer.SHEAR; @@ -56,7 +82,7 @@ namespace osu.Game.Overlays.Mods Origin = Anchor.BottomRight, Anchor = Anchor.BottomRight, AutoSizeAxes = Axes.X, - Height = 50, // as ModSelectOverlay footer buttons + Height = HEIGHT, Shear = new Vector2(shear, 0), CornerRadius = corner_radius, BorderThickness = border_thickness, @@ -146,27 +172,47 @@ namespace osu.Game.Overlays.Mods } protected override void LoadComplete() { - adjustedInfo.BindValueChanged(e => { UpdateValues(); }, true); - background.Colour = colourProvider.Background4; innerBackground.Colour = colourProvider.Background3; Color4 glow_colour = colourProvider.Background1; content.BorderColour = ColourInfo.GradientVertical(background.Colour, glow_colour); innerContent.BorderColour = ColourInfo.GradientVertical(innerBackground.Colour, glow_colour); - } + updateStarDifficultyBind(); + } + private void updateStarDifficultyBind() + { + if (cancellationSource != null) cancellationSource.Cancel(); + starDifficulty = difficultyCache.GetBindableDifficulty(beatmapInfo, (cancellationSource = new CancellationTokenSource()).Token); + starDifficulty.BindValueChanged(s => + { + starRatingDisplay.Current.Value = s.NewValue ?? default; + + if (!starRatingDisplay.IsPresent) + starRatingDisplay.FinishTransforms(true); + + starRatingDisplay.FadeIn(transition_duration); + }); + } public void UpdateValues() { - if (adjustedInfo.Value == null) return; + if (beatmapInfo == null) return; - starRatingDisplay.Current.Value = adjustedInfo.Value.StarDifficulty; - bpmDisplay.Current.Value = adjustedInfo.Value.BPM; + double rate = 1; + foreach (var mod in mods.Value.OfType()) + rate = mod.ApplyToRate(0, rate); - circleSizeDisplay.Current.Value = adjustedInfo.Value.CircleSize; - drainRateDisplay.Current.Value = adjustedInfo.Value.DrainRate; - approachRateDisplay.Current.Value = adjustedInfo.Value.ApproachRate; - overallDifficultyDisplay.Current.Value = adjustedInfo.Value.OverallDifficulty; + bpmDisplay.Current.Value = beatmapInfo.BPM * rate; + + BeatmapDifficulty adjustedDifficulty = new BeatmapDifficulty(BeatmapInfo.Difficulty); + foreach (var mod in mods.Value.OfType()) + mod.ApplyToDifficulty(adjustedDifficulty); + + circleSizeDisplay.Current.Value = adjustedDifficulty.CircleSize; + drainRateDisplay.Current.Value = adjustedDifficulty.DrainRate; + approachRateDisplay.Current.Value = adjustedDifficulty.ApproachRate; + overallDifficultyDisplay.Current.Value = adjustedDifficulty.OverallDifficulty; } private partial class BPMDisplay : RollingCounter diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 8de4447b31..4989c55d49 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -17,6 +17,7 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Utils; using osu.Game.Audio; +using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -27,7 +28,6 @@ using osu.Game.Localisation; using osu.Game.Rulesets.Mods; using osu.Game.Utils; using osuTK; -using osuTK.Graphics; using osuTK.Input; namespace osu.Game.Overlays.Mods @@ -125,7 +125,7 @@ namespace osu.Game.Overlays.Mods private Container aboveColumnsContent = null!; private DifficultyMultiplierDisplay? multiplierDisplay; - private ModMapInfoContainer mapInfoContainer = null!; + private ModEffectPreviewPanel modEffectPreviewPanel = null!; protected ShearedButton BackButton { get; private set; } = null!; protected ShearedToggleButton? CustomisationButton { get; private set; } @@ -133,6 +133,20 @@ namespace osu.Game.Overlays.Mods private Sample? columnAppearSample; + private WorkingBeatmap beatmap = null!; + + public WorkingBeatmap Beatmap + { + get => beatmap; + set + { + if (beatmap == value) return; + + beatmap = value; + modEffectPreviewPanel.BeatmapInfo = beatmap.BeatmapInfo; + } + } + protected ModSelectOverlay(OverlayColourScheme colourScheme = OverlayColourScheme.Green) : base(colourScheme) { @@ -224,11 +238,11 @@ namespace osu.Game.Overlays.Mods FooterContent.Children = new Drawable[] { - mapInfoContainer = new ModMapInfoContainer + modEffectPreviewPanel = new ModEffectPreviewPanel { Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, - Padding = new MarginPadding + Margin = new MarginPadding { Vertical = PADDING, Horizontal = 70 @@ -286,7 +300,7 @@ namespace osu.Game.Overlays.Mods SelectedMods.BindValueChanged(_ => { - updateMapInfo(); + modEffectPreviewPanel.UpdateValues(); updateMultiplier(); updateFromExternalSelection(); updateCustomisation(); @@ -300,7 +314,11 @@ namespace osu.Game.Overlays.Mods // // See https://github.com/ppy/osu/pull/23284#issuecomment-1529056988 modSettingChangeTracker = new ModSettingChangeTracker(SelectedMods.Value); - modSettingChangeTracker.SettingChanged += _ => updateMultiplier(); + modSettingChangeTracker.SettingChanged += _ => + { + modEffectPreviewPanel.UpdateValues(); + updateMultiplier(); + }; } }, true); @@ -416,14 +434,6 @@ namespace osu.Game.Overlays.Mods multiplierDisplay.Current.Value = multiplier; } - private void updateMapInfo() - { - if (mapInfoContainer == null) - return; - - mapInfoContainer.UpdateValues(); - } - private void updateCustomisation() { if (CustomisationButton == null) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 6ebdca1b8d..712b610515 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -3,7 +3,6 @@ using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index a12323ab70..f77ed28dae 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -46,9 +46,6 @@ namespace osu.Game.Screens.Select.Details private IBeatmapInfo beatmapInfo; - [Resolved(canBeNull: true)] - private Bindable adjustedInfo { get; set; } = null; - public IBeatmapInfo BeatmapInfo { get => beatmapInfo; @@ -101,33 +98,6 @@ namespace osu.Game.Screens.Select.Details private ModSettingChangeTracker modSettingChangeTracker; private ScheduledDelegate debouncedStatisticsUpdate; - - private StarDifficulty latestStarDifficulty = new StarDifficulty(); - private void updateBindedInfo() - { - if (adjustedInfo == null) return; - - // sadly need to calculate this to prevent additional data transportation - double rate = 1; - foreach (var mod in mods.Value.OfType()) - rate = mod.ApplyToRate(0, rate); - - double bpm = 0; - if (beatmapInfo != null) bpm = beatmapInfo.BPM * rate; - - BeatmapShortInfo adjusted = new BeatmapShortInfo() - { - CircleSize = FirstValue.Value.adjustedValue ?? FirstValue.Value.baseValue, - DrainRate = HpDrain.Value.adjustedValue ?? HpDrain.Value.baseValue, - ApproachRate = ApproachRate.Value.adjustedValue ?? ApproachRate.Value.baseValue, - OverallDifficulty = Accuracy.Value.adjustedValue ?? Accuracy.Value.baseValue, - BPM = bpm, - StarDifficulty = latestStarDifficulty - }; - - adjustedInfo.Value = adjusted; - } - private void modsChanged(ValueChangedEvent> mods) { modSettingChangeTracker?.Dispose(); @@ -174,7 +144,6 @@ namespace osu.Game.Screens.Select.Details Accuracy.Value = (baseDifficulty?.OverallDifficulty ?? 0, adjustedDifficulty?.OverallDifficulty); ApproachRate.Value = (baseDifficulty?.ApproachRate ?? 0, adjustedDifficulty?.ApproachRate); - updateBindedInfo(); // to faster UI response (without SR calculation) updateStarDifficulty(); } @@ -208,8 +177,6 @@ namespace osu.Game.Screens.Select.Details return; starDifficulty.Value = ((float)normalDifficulty.Value.Stars, (float)moddedDifficulty.Value.Stars); - latestStarDifficulty = moddedDifficulty ?? default; - updateBindedInfo(); }), starDifficultyCancellationSource.Token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Current); }); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 7749e3937a..f9d41f98ea 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -99,9 +99,6 @@ namespace osu.Game.Screens.Select [Resolved] private Bindable> selectedMods { get; set; } = null!; - [Cached] - private Bindable adjustedInfo { get; set; } = new Bindable(); - protected BeatmapCarousel Carousel { get; private set; } = null!; private ParallaxContainer wedgeBackground = null!; @@ -786,6 +783,8 @@ namespace osu.Game.Screens.Select BeatmapDetails.Beatmap = beatmap; + ModSelect.Beatmap = beatmap; + bool beatmapSelected = beatmap is not DummyWorkingBeatmap; if (beatmapSelected) From a01537c76301ff6de5c5d68080c7a90e68d23903 Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Fri, 8 Sep 2023 20:37:07 +0300 Subject: [PATCH 09/29] minor format fix --- osu.Game/Screens/Select/Details/AdvancedStats.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index f77ed28dae..23298c694b 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -98,6 +98,7 @@ namespace osu.Game.Screens.Select.Details private ModSettingChangeTracker modSettingChangeTracker; private ScheduledDelegate debouncedStatisticsUpdate; + private void modsChanged(ValueChangedEvent> mods) { modSettingChangeTracker?.Dispose(); @@ -175,7 +176,6 @@ namespace osu.Game.Screens.Select.Details if (normalDifficulty == null || moddedDifficulty == null) return; - starDifficulty.Value = ((float)normalDifficulty.Value.Stars, (float)moddedDifficulty.Value.Stars); }), starDifficultyCancellationSource.Token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Current); From ed213dad6c369e66f9277869f3d41dd07135a8ce Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Fri, 8 Sep 2023 20:38:24 +0300 Subject: [PATCH 10/29] minor format fix (again) --- osu.Game/Screens/Select/Details/AdvancedStats.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index 23298c694b..a383298faa 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -176,8 +176,8 @@ namespace osu.Game.Screens.Select.Details if (normalDifficulty == null || moddedDifficulty == null) return; - starDifficulty.Value = ((float)normalDifficulty.Value.Stars, (float)moddedDifficulty.Value.Stars); + starDifficulty.Value = ((float)normalDifficulty.Value.Stars, (float)moddedDifficulty.Value.Stars); }), starDifficultyCancellationSource.Token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Current); }); From 507f9642cc7db892326e4ca8a813063def813bba Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Fri, 8 Sep 2023 22:15:30 +0300 Subject: [PATCH 11/29] Better counter formatization Now CS and HP have 1 decimal point precision, while AR and OD is kept with 2 because of future support of rate-changed AR/OD --- osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs | 8 ++++---- osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs | 9 ++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs index b6a8dfe827..6a101bd9f9 100644 --- a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs +++ b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs @@ -159,10 +159,10 @@ namespace osu.Game.Overlays.Mods Direction = FillDirection.Horizontal, Children = new[] { - circleSizeDisplay = new VerticalAttributeDisplay("CS"), - drainRateDisplay = new VerticalAttributeDisplay("HP"), - approachRateDisplay = new VerticalAttributeDisplay("AR"), - overallDifficultyDisplay = new VerticalAttributeDisplay("OD"), + circleSizeDisplay = new VerticalAttributeDisplay("CS", "0.#"), + drainRateDisplay = new VerticalAttributeDisplay("HP", "0.#"), + approachRateDisplay = new VerticalAttributeDisplay("AR", "0.##"), + overallDifficultyDisplay = new VerticalAttributeDisplay("OD", "0.##"), } } } diff --git a/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs b/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs index 95d979ebd2..503b07f3b9 100644 --- a/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs +++ b/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Mods /// public LocalisableString Label { get; protected set; } - public VerticalAttributeDisplay(LocalisableString label) + public VerticalAttributeDisplay(LocalisableString label, string format = "0.#") { Label = label; AutoSizeAxes = Axes.X; @@ -54,7 +54,8 @@ namespace osu.Game.Overlays.Mods { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Current = { BindTarget = Current } + Current = { BindTarget = Current }, + Format = format } } }; @@ -64,7 +65,9 @@ namespace osu.Game.Overlays.Mods { protected override double RollingDuration => 500; - protected override LocalisableString FormatCount(double count) => count.ToLocalisableString("0.##"); + public string Format = "0.#"; + + protected override LocalisableString FormatCount(double count) => count.ToLocalisableString(Format); protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText { From 23c4a038487c51fc654eba1a17a409d87856cb4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 08:26:05 +0200 Subject: [PATCH 12/29] Fix code inspections --- .../Overlays/Mods/ModEffectPreviewPanel.cs | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs index 6a101bd9f9..79172a595c 100644 --- a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs +++ b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs @@ -25,26 +25,26 @@ namespace osu.Game.Overlays.Mods { public partial class ModEffectPreviewPanel : CompositeDrawable { - private Container content; - private Container innerContent; + private Container content = null!; + private Container innerContent = null!; - private Box background; - private Box innerBackground; + private Box background = null!; + private Box innerBackground = null!; - private StarRatingDisplay starRatingDisplay; - private BPMDisplay bpmDisplay; + private StarRatingDisplay starRatingDisplay = null!; + private BPMDisplay bpmDisplay = null!; - private VerticalAttributeDisplay circleSizeDisplay; - private VerticalAttributeDisplay drainRateDisplay; - private VerticalAttributeDisplay approachRateDisplay; - private VerticalAttributeDisplay overallDifficultyDisplay; + private VerticalAttributeDisplay circleSizeDisplay = null!; + private VerticalAttributeDisplay drainRateDisplay = null!; + private VerticalAttributeDisplay approachRateDisplay = null!; + private VerticalAttributeDisplay overallDifficultyDisplay = null!; public const float HEIGHT = 50; // as ModSelectOverlay footer buttons private const float transition_duration = 250; - private IBeatmapInfo beatmapInfo = null!; + private IBeatmapInfo? beatmapInfo; - public IBeatmapInfo BeatmapInfo + public IBeatmapInfo? BeatmapInfo { get => beatmapInfo; set @@ -66,10 +66,11 @@ namespace osu.Game.Overlays.Mods [Resolved] private BeatmapDifficultyCache difficultyCache { get; set; } = null!; - private CancellationTokenSource cancellationSource = null!; + private CancellationTokenSource? cancellationSource; private IBindable starDifficulty = null!; - public ModEffectPreviewPanel() + [BackgroundDependencyLoader] + private void load() { // values as ModSelectOverlay footer buttons const float shear = ShearedOverlayContainer.SHEAR; @@ -170,20 +171,25 @@ namespace osu.Game.Overlays.Mods } }; } + protected override void LoadComplete() { background.Colour = colourProvider.Background4; innerBackground.Colour = colourProvider.Background3; - Color4 glow_colour = colourProvider.Background1; + Color4 glowColour = colourProvider.Background1; - content.BorderColour = ColourInfo.GradientVertical(background.Colour, glow_colour); - innerContent.BorderColour = ColourInfo.GradientVertical(innerBackground.Colour, glow_colour); + content.BorderColour = ColourInfo.GradientVertical(background.Colour, glowColour); + innerContent.BorderColour = ColourInfo.GradientVertical(innerBackground.Colour, glowColour); updateStarDifficultyBind(); } + private void updateStarDifficultyBind() { - if (cancellationSource != null) cancellationSource.Cancel(); + if (beatmapInfo == null) + return; + + cancellationSource?.Cancel(); starDifficulty = difficultyCache.GetBindableDifficulty(beatmapInfo, (cancellationSource = new CancellationTokenSource()).Token); starDifficulty.BindValueChanged(s => { @@ -195,9 +201,11 @@ namespace osu.Game.Overlays.Mods starRatingDisplay.FadeIn(transition_duration); }); } + public void UpdateValues() { - if (beatmapInfo == null) return; + if (beatmapInfo == null) + return; double rate = 1; foreach (var mod in mods.Value.OfType()) @@ -205,7 +213,7 @@ namespace osu.Game.Overlays.Mods bpmDisplay.Current.Value = beatmapInfo.BPM * rate; - BeatmapDifficulty adjustedDifficulty = new BeatmapDifficulty(BeatmapInfo.Difficulty); + BeatmapDifficulty adjustedDifficulty = new BeatmapDifficulty(beatmapInfo.Difficulty); foreach (var mod in mods.Value.OfType()) mod.ApplyToDifficulty(adjustedDifficulty); From c1a2b86f3f95142b5f0c73b2d2ae5acbd4006aa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 08:29:37 +0200 Subject: [PATCH 13/29] Extract constants properly --- osu.Game/Graphics/UserInterface/ShearedButton.cs | 14 ++++++++------ osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs | 13 +++++-------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/ShearedButton.cs b/osu.Game/Graphics/UserInterface/ShearedButton.cs index f1afacb2f4..b1e7066a01 100644 --- a/osu.Game/Graphics/UserInterface/ShearedButton.cs +++ b/osu.Game/Graphics/UserInterface/ShearedButton.cs @@ -17,6 +17,10 @@ namespace osu.Game.Graphics.UserInterface { public partial class ShearedButton : OsuClickableContainer { + public const float HEIGHT = 50; + public const float CORNER_RADIUS = 7; + public const float BORDER_THICKNESS = 2; + public LocalisableString Text { get => text.Text; @@ -83,12 +87,10 @@ namespace osu.Game.Graphics.UserInterface /// public ShearedButton(float? width = null) { - Height = 50; + Height = HEIGHT; Padding = new MarginPadding { Horizontal = shear * 50 }; - const float corner_radius = 7; - - Content.CornerRadius = corner_radius; + Content.CornerRadius = CORNER_RADIUS; Content.Shear = new Vector2(shear, 0); Content.Masking = true; Content.Anchor = Content.Origin = Anchor.Centre; @@ -98,9 +100,9 @@ namespace osu.Game.Graphics.UserInterface backgroundLayer = new Container { RelativeSizeAxes = Axes.Y, - CornerRadius = corner_radius, + CornerRadius = CORNER_RADIUS, Masking = true, - BorderThickness = 2, + BorderThickness = BORDER_THICKNESS, Children = new Drawable[] { background = new Box diff --git a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs index 79172a595c..aa7ddc47bc 100644 --- a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs +++ b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs @@ -39,7 +39,6 @@ namespace osu.Game.Overlays.Mods private VerticalAttributeDisplay approachRateDisplay = null!; private VerticalAttributeDisplay overallDifficultyDisplay = null!; - public const float HEIGHT = 50; // as ModSelectOverlay footer buttons private const float transition_duration = 250; private IBeatmapInfo? beatmapInfo; @@ -74,8 +73,6 @@ namespace osu.Game.Overlays.Mods { // values as ModSelectOverlay footer buttons const float shear = ShearedOverlayContainer.SHEAR; - const float corner_radius = 7; - const float border_thickness = 2; AutoSizeAxes = Axes.Both; InternalChild = content = new InputBlockingContainer @@ -83,10 +80,10 @@ namespace osu.Game.Overlays.Mods Origin = Anchor.BottomRight, Anchor = Anchor.BottomRight, AutoSizeAxes = Axes.X, - Height = HEIGHT, + Height = ShearedButton.HEIGHT, Shear = new Vector2(shear, 0), - CornerRadius = corner_radius, - BorderThickness = border_thickness, + CornerRadius = ShearedButton.CORNER_RADIUS, + BorderThickness = ShearedButton.BORDER_THICKNESS, Masking = true, Children = new Drawable[] { @@ -107,8 +104,8 @@ namespace osu.Game.Overlays.Mods { AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, - BorderThickness = border_thickness, - CornerRadius = corner_radius, + BorderThickness = ShearedButton.BORDER_THICKNESS, + CornerRadius = ShearedButton.CORNER_RADIUS, Masking = true, Children = new Drawable[] { From f591a30ea77eb11e0fb0a7a2a3c1f02f9871181a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 08:44:25 +0200 Subject: [PATCH 14/29] Refactor preview panel to be more self-contained --- .../Overlays/Mods/ModEffectPreviewPanel.cs | 47 ++++++++----------- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 9 +--- 2 files changed, 22 insertions(+), 34 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs index aa7ddc47bc..dde3761c4a 100644 --- a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs +++ b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs @@ -20,6 +20,7 @@ using osu.Game.Rulesets.Mods; using osuTK; using osuTK.Graphics; using System.Threading; +using osu.Game.Configuration; namespace osu.Game.Overlays.Mods { @@ -41,24 +42,13 @@ namespace osu.Game.Overlays.Mods private const float transition_duration = 250; - private IBeatmapInfo? beatmapInfo; - - public IBeatmapInfo? BeatmapInfo - { - get => beatmapInfo; - set - { - if (value == beatmapInfo) return; - - beatmapInfo = value; - updateStarDifficultyBind(); - UpdateValues(); - } - } + public Bindable BeatmapInfo { get; } = new Bindable(); [Resolved] private Bindable> mods { get; set; } = null!; + private ModSettingChangeTracker? modSettingChangeTracker; + [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -178,16 +168,25 @@ namespace osu.Game.Overlays.Mods content.BorderColour = ColourInfo.GradientVertical(background.Colour, glowColour); innerContent.BorderColour = ColourInfo.GradientVertical(innerBackground.Colour, glowColour); - updateStarDifficultyBind(); + BeatmapInfo.BindValueChanged(_ => updateValues(), true); + + mods.BindValueChanged(_ => + { + modSettingChangeTracker?.Dispose(); + + modSettingChangeTracker = new ModSettingChangeTracker(mods.Value); + modSettingChangeTracker.SettingChanged += _ => updateValues(); + updateValues(); + }); } - private void updateStarDifficultyBind() + private void updateValues() => Scheduler.AddOnce(() => { - if (beatmapInfo == null) + if (BeatmapInfo.Value == null) return; cancellationSource?.Cancel(); - starDifficulty = difficultyCache.GetBindableDifficulty(beatmapInfo, (cancellationSource = new CancellationTokenSource()).Token); + starDifficulty = difficultyCache.GetBindableDifficulty(BeatmapInfo.Value, (cancellationSource = new CancellationTokenSource()).Token); starDifficulty.BindValueChanged(s => { starRatingDisplay.Current.Value = s.NewValue ?? default; @@ -197,20 +196,14 @@ namespace osu.Game.Overlays.Mods starRatingDisplay.FadeIn(transition_duration); }); - } - - public void UpdateValues() - { - if (beatmapInfo == null) - return; double rate = 1; foreach (var mod in mods.Value.OfType()) rate = mod.ApplyToRate(0, rate); - bpmDisplay.Current.Value = beatmapInfo.BPM * rate; + bpmDisplay.Current.Value = BeatmapInfo.Value.BPM * rate; - BeatmapDifficulty adjustedDifficulty = new BeatmapDifficulty(beatmapInfo.Difficulty); + BeatmapDifficulty adjustedDifficulty = new BeatmapDifficulty(BeatmapInfo.Value.Difficulty); foreach (var mod in mods.Value.OfType()) mod.ApplyToDifficulty(adjustedDifficulty); @@ -218,7 +211,7 @@ namespace osu.Game.Overlays.Mods drainRateDisplay.Current.Value = adjustedDifficulty.DrainRate; approachRateDisplay.Current.Value = adjustedDifficulty.ApproachRate; overallDifficultyDisplay.Current.Value = adjustedDifficulty.OverallDifficulty; - } + }); private partial class BPMDisplay : RollingCounter { diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 4989c55d49..f2f2dc970c 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -143,7 +143,7 @@ namespace osu.Game.Overlays.Mods if (beatmap == value) return; beatmap = value; - modEffectPreviewPanel.BeatmapInfo = beatmap.BeatmapInfo; + modEffectPreviewPanel.BeatmapInfo.Value = beatmap.BeatmapInfo; } } @@ -300,7 +300,6 @@ namespace osu.Game.Overlays.Mods SelectedMods.BindValueChanged(_ => { - modEffectPreviewPanel.UpdateValues(); updateMultiplier(); updateFromExternalSelection(); updateCustomisation(); @@ -314,11 +313,7 @@ namespace osu.Game.Overlays.Mods // // See https://github.com/ppy/osu/pull/23284#issuecomment-1529056988 modSettingChangeTracker = new ModSettingChangeTracker(SelectedMods.Value); - modSettingChangeTracker.SettingChanged += _ => - { - modEffectPreviewPanel.UpdateValues(); - updateMultiplier(); - }; + modSettingChangeTracker.SettingChanged += _ => updateMultiplier(); } }, true); From a631fae6dfb2a0ab74ee8fd1e90a6224beb66f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 09:19:37 +0200 Subject: [PATCH 15/29] Add actual testing --- .../TestSceneModEffectPreviewPanel.cs | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs new file mode 100644 index 0000000000..e3afb874db --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs @@ -0,0 +1,128 @@ +// 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.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Overlays; +using osu.Game.Overlays.Mods; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Tests.Beatmaps; + +namespace osu.Game.Tests.Visual.UserInterface +{ + [TestFixture] + public partial class TestSceneModEffectPreviewPanel : OsuTestScene + { + [Cached(typeof(BeatmapDifficultyCache))] + private TestBeatmapDifficultyCache difficultyCache = new TestBeatmapDifficultyCache(); + + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + + private Container content = null!; + private ModEffectPreviewPanel panel = null!; + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("set up cache", () => Children = new Drawable[] + { + difficultyCache, + content = new Container + { + RelativeSizeAxes = Axes.Both + } + }); + } + + [Test] + public void TestDisplay() + { + OsuModDifficultyAdjust difficultyAdjust = new OsuModDifficultyAdjust(); + OsuModDoubleTime doubleTime = new OsuModDoubleTime(); + + AddStep("create display", () => content.Child = panel = new ModEffectPreviewPanel + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + + AddStep("set beatmap", () => + { + var beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo) + { + BeatmapInfo = + { + BPM = 120 + } + }; + + Ruleset.Value = beatmap.BeatmapInfo.Ruleset; + panel.BeatmapInfo.Value = beatmap.BeatmapInfo; + }); + + AddSliderStep("change star rating", 0, 10d, 5, stars => + { + if (panel.IsNotNull()) + previewStarRating(stars); + }); + AddStep("preview ridiculously high SR", () => previewStarRating(1234)); + + AddStep("add DA to mods", () => SelectedMods.Value = new[] { difficultyAdjust }); + + AddSliderStep("change AR", 0, 10f, 5, ar => + { + if (panel.IsNotNull()) + difficultyAdjust.ApproachRate.Value = ar; + }); + AddSliderStep("change CS", 0, 10f, 5, cs => + { + if (panel.IsNotNull()) + difficultyAdjust.CircleSize.Value = cs; + }); + AddSliderStep("change HP", 0, 10f, 5, hp => + { + if (panel.IsNotNull()) + difficultyAdjust.DrainRate.Value = hp; + }); + AddSliderStep("change OD", 0, 10f, 5, od => + { + if (panel.IsNotNull()) + difficultyAdjust.OverallDifficulty.Value = od; + }); + + AddStep("add DT to mods", () => SelectedMods.Value = new Mod[] { difficultyAdjust, doubleTime }); + AddSliderStep("change rate", 1.01d, 2d, 1.5d, rate => + { + if (panel.IsNotNull()) + doubleTime.SpeedChange.Value = rate; + }); + } + + private void previewStarRating(double stars) + { + difficultyCache.Difficulty = new StarDifficulty(stars, 0); + panel.BeatmapInfo.TriggerChange(); + } + + private partial class TestBeatmapDifficultyCache : BeatmapDifficultyCache + { + public StarDifficulty? Difficulty { get; set; } + + public override Task GetDifficultyAsync(IBeatmapInfo beatmapInfo, IRulesetInfo? rulesetInfo = null, IEnumerable? mods = null, + CancellationToken cancellationToken = default) + => Task.FromResult(Difficulty); + } + } +} From 552230af9d23f53e83cc57a06a425c0486e36c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 09:37:25 +0200 Subject: [PATCH 16/29] Refactor layout of display --- .../Overlays/Mods/ModEffectPreviewPanel.cs | 48 ++++++++----------- .../Overlays/Mods/VerticalAttributeDisplay.cs | 10 ++-- 2 files changed, 23 insertions(+), 35 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs index dde3761c4a..1a5d1e98c7 100644 --- a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs +++ b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs @@ -61,7 +61,6 @@ namespace osu.Game.Overlays.Mods [BackgroundDependencyLoader] private void load() { - // values as ModSelectOverlay footer buttons const float shear = ShearedOverlayContainer.SHEAR; AutoSizeAxes = Axes.Both; @@ -103,36 +102,26 @@ namespace osu.Game.Overlays.Mods { RelativeSizeAxes = Axes.Both }, - new FillFlowContainer // actual inner content + new Container // actual inner content { - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - AutoSizeAxes = Axes.X, - Direction = FillDirection.Horizontal, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Width = 140, + RelativeSizeAxes = Axes.Y, Margin = new MarginPadding { Horizontal = 15 }, Children = new Drawable[] { - new Container // wrap to reserve space for StarRatingDisplay - { - Width = 70, // can be up to 70px on extra high SR - Child = starRatingDisplay = new StarRatingDisplay(default, animated: true) - { - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Shear = new Vector2(-shear, 0), - } - }, - new Container // wrap to reserve space for BPM + starRatingDisplay = new StarRatingDisplay(default, animated: true) { Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, - Width = 70, - Child = bpmDisplay = new BPMDisplay - { - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Shear = new Vector2(-shear, 0), - } + Shear = new Vector2(-shear, 0), + }, + bpmDisplay = new BPMDisplay + { + Origin = Anchor.CentreRight, + Anchor = Anchor.CentreRight, + Shear = new Vector2(-shear, 0), } } } @@ -147,10 +136,10 @@ namespace osu.Game.Overlays.Mods Direction = FillDirection.Horizontal, Children = new[] { - circleSizeDisplay = new VerticalAttributeDisplay("CS", "0.#"), - drainRateDisplay = new VerticalAttributeDisplay("HP", "0.#"), - approachRateDisplay = new VerticalAttributeDisplay("AR", "0.##"), - overallDifficultyDisplay = new VerticalAttributeDisplay("OD", "0.##"), + circleSizeDisplay = new VerticalAttributeDisplay("CS"), + drainRateDisplay = new VerticalAttributeDisplay("HP"), + approachRateDisplay = new VerticalAttributeDisplay("AR"), + overallDifficultyDisplay = new VerticalAttributeDisplay("OD"), } } } @@ -221,7 +210,8 @@ namespace osu.Game.Overlays.Mods protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText { - Font = OsuFont.Default.With(size: 20, weight: FontWeight.SemiBold) + Font = OsuFont.Default.With(size: 20, weight: FontWeight.SemiBold), + UseFullGlyphHeight = false, }; } } diff --git a/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs b/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs index 503b07f3b9..ba8efd1c2b 100644 --- a/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs +++ b/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs @@ -21,6 +21,7 @@ namespace osu.Game.Overlays.Mods get => current.Current; set => current.Current = value; } + private readonly BindableWithCurrent current = new BindableWithCurrent(); /// @@ -28,7 +29,7 @@ namespace osu.Game.Overlays.Mods /// public LocalisableString Label { get; protected set; } - public VerticalAttributeDisplay(LocalisableString label, string format = "0.#") + public VerticalAttributeDisplay(LocalisableString label) { Label = label; AutoSizeAxes = Axes.X; @@ -50,12 +51,11 @@ namespace osu.Game.Overlays.Mods Margin = new MarginPadding { Horizontal = 15 }, // to reserve space for 0.XX value Font = OsuFont.Default.With(size: 20, weight: FontWeight.Bold) }, - new EffectCounter() + new EffectCounter { Origin = Anchor.Centre, Anchor = Anchor.Centre, Current = { BindTarget = Current }, - Format = format } } }; @@ -65,9 +65,7 @@ namespace osu.Game.Overlays.Mods { protected override double RollingDuration => 500; - public string Format = "0.#"; - - protected override LocalisableString FormatCount(double count) => count.ToLocalisableString(Format); + protected override LocalisableString FormatCount(double count) => count.ToLocalisableString("0.0"); protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText { From 53c30dca64e7e7eb44f882ffe5f26d44a2adec54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 09:52:43 +0200 Subject: [PATCH 17/29] Fix data flow being sometimes incorrect --- .../Visual/UserInterface/TestSceneModSelectOverlay.cs | 2 ++ osu.Game/Overlays/Mods/ModSelectOverlay.cs | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index ad79865ad9..029a7f8b9e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -51,6 +51,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("clear contents", Clear); AddStep("reset ruleset", () => Ruleset.Value = rulesetStore.GetRuleset(0)); AddStep("reset mods", () => SelectedMods.SetDefault()); + AddStep("set beatmap", () => Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo)); AddStep("set up presets", () => { Realm.Write(r => @@ -92,6 +93,7 @@ namespace osu.Game.Tests.Visual.UserInterface { RelativeSizeAxes = Axes.Both, State = { Value = Visibility.Visible }, + Beatmap = Beatmap.Value, SelectedMods = { BindTarget = SelectedMods } }); waitForColumnLoad(); diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index f2f2dc970c..1c5fc5abde 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -133,9 +133,9 @@ namespace osu.Game.Overlays.Mods private Sample? columnAppearSample; - private WorkingBeatmap beatmap = null!; + private WorkingBeatmap? beatmap; - public WorkingBeatmap Beatmap + public WorkingBeatmap? Beatmap { get => beatmap; set @@ -143,7 +143,8 @@ namespace osu.Game.Overlays.Mods if (beatmap == value) return; beatmap = value; - modEffectPreviewPanel.BeatmapInfo.Value = beatmap.BeatmapInfo; + if (IsLoaded) + modEffectPreviewPanel.BeatmapInfo.Value = beatmap?.BeatmapInfo; } } @@ -246,7 +247,8 @@ namespace osu.Game.Overlays.Mods { Vertical = PADDING, Horizontal = 70 - } + }, + BeatmapInfo = { Value = beatmap?.BeatmapInfo } }, footerButtonFlow = new FillFlowContainer { From 76bf82d900ccc46e1b89a1544f1748b25c74bbad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 09:55:45 +0200 Subject: [PATCH 18/29] Do not show mod effects on free mod select --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 56 +++++++++---------- .../OnlinePlay/FreeModSelectOverlay.cs | 2 +- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 1c5fc5abde..80340d2253 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -78,9 +78,9 @@ namespace osu.Game.Overlays.Mods public ShearedSearchTextBox SearchTextBox { get; private set; } = null!; /// - /// Whether the total score multiplier calculated from the current selected set of mods should be shown. + /// Whether the effects (on score multiplier, on or beatmap difficulty) of the current selected set of mods should be shown. /// - protected virtual bool ShowTotalMultiplier => true; + protected virtual bool ShowModEffects => true; /// /// Whether per-mod customisation controls are visible. @@ -228,18 +228,15 @@ namespace osu.Game.Overlays.Mods } }); - if (ShowTotalMultiplier) + if (ShowModEffects) { aboveColumnsContent.Add(multiplierDisplay = new DifficultyMultiplierDisplay { Anchor = Anchor.TopRight, Origin = Anchor.TopRight }); - } - FooterContent.Children = new Drawable[] - { - modEffectPreviewPanel = new ModEffectPreviewPanel + FooterContent.Add(modEffectPreviewPanel = new ModEffectPreviewPanel { Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, @@ -249,29 +246,30 @@ namespace osu.Game.Overlays.Mods Horizontal = 70 }, BeatmapInfo = { Value = beatmap?.BeatmapInfo } - }, - footerButtonFlow = new FillFlowContainer + }); + } + + FooterContent.Add(footerButtonFlow = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Padding = new MarginPadding { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Padding = new MarginPadding - { - Vertical = PADDING, - Horizontal = 70 - }, - Spacing = new Vector2(10), - ChildrenEnumerable = CreateFooterButtons().Prepend(BackButton = new ShearedButton(BUTTON_WIDTH) - { - Text = CommonStrings.Back, - Action = Hide, - DarkerColour = colours.Pink2, - LighterColour = colours.Pink1 - }) - } - }; + Vertical = PADDING, + Horizontal = 70 + }, + Spacing = new Vector2(10), + ChildrenEnumerable = CreateFooterButtons().Prepend(BackButton = new ShearedButton(BUTTON_WIDTH) + { + Text = CommonStrings.Back, + Action = Hide, + DarkerColour = colours.Pink2, + LighterColour = colours.Pink1 + }) + }); globalAvailableMods.BindTo(game.AvailableMods); } diff --git a/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs b/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs index 4d5d724089..7f090aca57 100644 --- a/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs @@ -14,7 +14,7 @@ namespace osu.Game.Screens.OnlinePlay { public partial class FreeModSelectOverlay : ModSelectOverlay { - protected override bool ShowTotalMultiplier => false; + protected override bool ShowModEffects => false; protected override bool AllowCustomisation => false; From 97665e029b8fbcf6f3a034a9d06592ff2859f755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 10:00:44 +0200 Subject: [PATCH 19/29] Remove weird fade --- osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs index 1a5d1e98c7..1b08b88740 100644 --- a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs +++ b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs @@ -182,8 +182,6 @@ namespace osu.Game.Overlays.Mods if (!starRatingDisplay.IsPresent) starRatingDisplay.FinishTransforms(true); - - starRatingDisplay.FadeIn(transition_duration); }); double rate = 1; From ff6bf0bc2c3754a838be06d99937b2e6e917d51e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 10:16:09 +0200 Subject: [PATCH 20/29] Fix slightly wrong binding setup --- osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs index 1b08b88740..7ace402a24 100644 --- a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs +++ b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs @@ -157,8 +157,7 @@ namespace osu.Game.Overlays.Mods content.BorderColour = ColourInfo.GradientVertical(background.Colour, glowColour); innerContent.BorderColour = ColourInfo.GradientVertical(innerBackground.Colour, glowColour); - BeatmapInfo.BindValueChanged(_ => updateValues(), true); - + BeatmapInfo.BindValueChanged(_ => updateValues()); mods.BindValueChanged(_ => { modSettingChangeTracker?.Dispose(); @@ -166,7 +165,7 @@ namespace osu.Game.Overlays.Mods modSettingChangeTracker = new ModSettingChangeTracker(mods.Value); modSettingChangeTracker.SettingChanged += _ => updateValues(); updateValues(); - }); + }, true); } private void updateValues() => Scheduler.AddOnce(() => From f9d4fbee56eebed60cbbe6a273062beeee30903f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 10:16:24 +0200 Subject: [PATCH 21/29] Add collapsed state to effect preview panel --- .../UserInterface/TestSceneModEffectPreviewPanel.cs | 2 ++ osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs index e3afb874db..f958b231f9 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs @@ -108,6 +108,8 @@ namespace osu.Game.Tests.Visual.UserInterface if (panel.IsNotNull()) doubleTime.SpeedChange.Value = rate; }); + + AddToggleStep("toggle collapsed", collapsed => panel.Collapsed.Value = collapsed); } private void previewStarRating(double stars) diff --git a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs index 7ace402a24..e03beb8649 100644 --- a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs +++ b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs @@ -35,6 +35,7 @@ namespace osu.Game.Overlays.Mods private StarRatingDisplay starRatingDisplay = null!; private BPMDisplay bpmDisplay = null!; + private FillFlowContainer outerContent = null!; private VerticalAttributeDisplay circleSizeDisplay = null!; private VerticalAttributeDisplay drainRateDisplay = null!; private VerticalAttributeDisplay approachRateDisplay = null!; @@ -44,6 +45,8 @@ namespace osu.Game.Overlays.Mods public Bindable BeatmapInfo { get; } = new Bindable(); + public BindableBool Collapsed { get; } = new BindableBool(); + [Resolved] private Bindable> mods { get; set; } = null!; @@ -69,6 +72,8 @@ namespace osu.Game.Overlays.Mods Origin = Anchor.BottomRight, Anchor = Anchor.BottomRight, AutoSizeAxes = Axes.X, + AutoSizeEasing = Easing.OutQuint, + AutoSizeDuration = transition_duration, Height = ShearedButton.HEIGHT, Shear = new Vector2(shear, 0), CornerRadius = ShearedButton.CORNER_RADIUS, @@ -127,7 +132,7 @@ namespace osu.Game.Overlays.Mods } } }, - new FillFlowContainer // outer content + outerContent = new FillFlowContainer { Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, @@ -166,6 +171,8 @@ namespace osu.Game.Overlays.Mods modSettingChangeTracker.SettingChanged += _ => updateValues(); updateValues(); }, true); + + Collapsed.BindValueChanged(collapsed => outerContent.FadeTo(collapsed.NewValue ? 0 : 1, transition_duration, Easing.OutQuint), true); } private void updateValues() => Scheduler.AddOnce(() => From 0822e8b925b6bf9fd9d78c30fd71f740d96dd08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 10:18:24 +0200 Subject: [PATCH 22/29] Fix preview panel not being marked nullable --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 80340d2253..1287c26c99 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -124,8 +124,7 @@ namespace osu.Game.Overlays.Mods private Container aboveColumnsContent = null!; private DifficultyMultiplierDisplay? multiplierDisplay; - - private ModEffectPreviewPanel modEffectPreviewPanel = null!; + private ModEffectPreviewPanel? modEffectPreviewPanel; protected ShearedButton BackButton { get; private set; } = null!; protected ShearedToggleButton? CustomisationButton { get; private set; } @@ -143,7 +142,7 @@ namespace osu.Game.Overlays.Mods if (beatmap == value) return; beatmap = value; - if (IsLoaded) + if (IsLoaded && modEffectPreviewPanel != null) modEffectPreviewPanel.BeatmapInfo.Value = beatmap?.BeatmapInfo; } } From 3deb6cb4ec3eb13135bb93def1b8b9d38d49094c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 10:19:02 +0200 Subject: [PATCH 23/29] Fix z-order of mod preview panel --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 42 +++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 1287c26c99..ca16b90852 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -227,27 +227,6 @@ namespace osu.Game.Overlays.Mods } }); - if (ShowModEffects) - { - aboveColumnsContent.Add(multiplierDisplay = new DifficultyMultiplierDisplay - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight - }); - - FooterContent.Add(modEffectPreviewPanel = new ModEffectPreviewPanel - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Margin = new MarginPadding - { - Vertical = PADDING, - Horizontal = 70 - }, - BeatmapInfo = { Value = beatmap?.BeatmapInfo } - }); - } - FooterContent.Add(footerButtonFlow = new FillFlowContainer { RelativeSizeAxes = Axes.X, @@ -270,6 +249,27 @@ namespace osu.Game.Overlays.Mods }) }); + if (ShowModEffects) + { + aboveColumnsContent.Add(multiplierDisplay = new DifficultyMultiplierDisplay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight + }); + + FooterContent.Add(modEffectPreviewPanel = new ModEffectPreviewPanel + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Margin = new MarginPadding + { + Vertical = PADDING, + Horizontal = 70 + }, + BeatmapInfo = { Value = beatmap?.BeatmapInfo } + }); + } + globalAvailableMods.BindTo(game.AvailableMods); } From d51396fdaf3838addb8ad7c0d268c7661d25aa95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 10:46:07 +0200 Subject: [PATCH 24/29] Collapse mod effect preview when it's not wide enough to fit --- osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs | 3 ++- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs index e03beb8649..5eb1671570 100644 --- a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs +++ b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs @@ -45,7 +45,7 @@ namespace osu.Game.Overlays.Mods public Bindable BeatmapInfo { get; } = new Bindable(); - public BindableBool Collapsed { get; } = new BindableBool(); + public BindableBool Collapsed { get; } = new BindableBool(true); [Resolved] private Bindable> mods { get; set; } = null!; @@ -173,6 +173,7 @@ namespace osu.Game.Overlays.Mods }, true); Collapsed.BindValueChanged(collapsed => outerContent.FadeTo(collapsed.NewValue ? 0 : 1, transition_duration, Easing.OutQuint), true); + FinishTransforms(true); } private void updateValues() => Scheduler.AddOnce(() => diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index ca16b90852..069fdf1af0 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -338,6 +338,15 @@ namespace osu.Game.Overlays.Mods base.Update(); SearchTextBox.PlaceholderText = SearchTextBox.HasFocus ? Resources.Localisation.Web.CommonStrings.InputSearch : ModSelectOverlayStrings.TabToSearch; + + if (modEffectPreviewPanel != null) + { + float rightEdgeOfLastButton = footerButtonFlow.Last().ScreenSpaceDrawQuad.TopRight.X; + // this is cheating a bit; the 375 value is hardcoded based on how wide the expanded panel _generally_ is. + // due to the transition applied, the raw screenspace quad of the panel cannot be used, as it will trigger an ugly feedback cycle of expanding and collapsing. + float projectedLeftEdgeOfExpandedModEffectPreviewPanel = footerButtonFlow.ToScreenSpace(footerButtonFlow.DrawSize - new Vector2(375 + 70, 0)).X; + modEffectPreviewPanel.Collapsed.Value = rightEdgeOfLastButton > projectedLeftEdgeOfExpandedModEffectPreviewPanel; + } } /// From eebacfb982be3e1d0eaf834c2c78f15ec81686be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 10:59:19 +0200 Subject: [PATCH 25/29] Make mod effect preview uncollapse on hover --- .../Overlays/Mods/ModEffectPreviewPanel.cs | 26 +++++++++++++++++-- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 3 +++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs index 5eb1671570..a6d7732cba 100644 --- a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs +++ b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs @@ -20,6 +20,7 @@ using osu.Game.Rulesets.Mods; using osuTK; using osuTK.Graphics; using System.Threading; +using osu.Framework.Input.Events; using osu.Game.Configuration; namespace osu.Game.Overlays.Mods @@ -67,7 +68,7 @@ namespace osu.Game.Overlays.Mods const float shear = ShearedOverlayContainer.SHEAR; AutoSizeAxes = Axes.Both; - InternalChild = content = new InputBlockingContainer + InternalChild = content = new Container { Origin = Anchor.BottomRight, Anchor = Anchor.BottomRight, @@ -172,10 +173,26 @@ namespace osu.Game.Overlays.Mods updateValues(); }, true); - Collapsed.BindValueChanged(collapsed => outerContent.FadeTo(collapsed.NewValue ? 0 : 1, transition_duration, Easing.OutQuint), true); + Collapsed.BindValueChanged(_ => updateCollapsedState(), true); FinishTransforms(true); } + protected override bool OnHover(HoverEvent e) + { + updateCollapsedState(); + return true; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateCollapsedState(); + base.OnHoverLost(e); + } + + protected override bool OnMouseDown(MouseDownEvent e) => true; + + protected override bool OnClick(ClickEvent e) => true; + private void updateValues() => Scheduler.AddOnce(() => { if (BeatmapInfo.Value == null) @@ -207,6 +224,11 @@ namespace osu.Game.Overlays.Mods overallDifficultyDisplay.Current.Value = adjustedDifficulty.OverallDifficulty; }); + private void updateCollapsedState() + { + outerContent.FadeTo(Collapsed.Value && !IsHovered ? 0 : 1, transition_duration, Easing.OutQuint); + } + private partial class BPMDisplay : RollingCounter { protected override double RollingDuration => 500; diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 069fdf1af0..d52782cf11 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -924,6 +924,9 @@ namespace osu.Game.Overlays.Mods OnClicked?.Invoke(); return true; + case HoverEvent: + return false; + case MouseEvent: return true; } From 824416067e0c95bdd4ca74f3da59f0cebfea9827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 11 Sep 2023 20:53:17 +0200 Subject: [PATCH 26/29] Fix test failure --- .../UserInterface/TestSceneModEffectPreviewPanel.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs index f958b231f9..adb12ad249 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs @@ -9,7 +9,6 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Overlays; using osu.Game.Overlays.Mods; @@ -31,12 +30,14 @@ namespace osu.Game.Tests.Visual.UserInterface private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); private Container content = null!; + protected override Container Content => content; + private ModEffectPreviewPanel panel = null!; - [SetUpSteps] - public void SetUpSteps() + [BackgroundDependencyLoader] + private void load() { - AddStep("set up cache", () => Children = new Drawable[] + base.Content.AddRange(new Drawable[] { difficultyCache, content = new Container @@ -52,7 +53,7 @@ namespace osu.Game.Tests.Visual.UserInterface OsuModDifficultyAdjust difficultyAdjust = new OsuModDifficultyAdjust(); OsuModDoubleTime doubleTime = new OsuModDoubleTime(); - AddStep("create display", () => content.Child = panel = new ModEffectPreviewPanel + AddStep("create display", () => Child = panel = new ModEffectPreviewPanel { Anchor = Anchor.Centre, Origin = Anchor.Centre, From e40eaa73774804646f928989672054ce9d56f15a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Sep 2023 17:00:06 +0900 Subject: [PATCH 27/29] Improve collapse/expand animations Especially when on a screen resolution where it would start collapsed. --- .../Overlays/Mods/ModEffectPreviewPanel.cs | 23 +++++++++++++++---- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 4 +++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs index a6d7732cba..b9511cc544 100644 --- a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs +++ b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs @@ -73,8 +73,6 @@ namespace osu.Game.Overlays.Mods Origin = Anchor.BottomRight, Anchor = Anchor.BottomRight, AutoSizeAxes = Axes.X, - AutoSizeEasing = Easing.OutQuint, - AutoSizeDuration = transition_duration, Height = ShearedButton.HEIGHT, Shear = new Vector2(shear, 0), CornerRadius = ShearedButton.CORNER_RADIUS, @@ -135,6 +133,7 @@ namespace osu.Game.Overlays.Mods }, outerContent = new FillFlowContainer { + Alpha = 0, Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, AutoSizeAxes = Axes.X, @@ -163,7 +162,6 @@ namespace osu.Game.Overlays.Mods content.BorderColour = ColourInfo.GradientVertical(background.Colour, glowColour); innerContent.BorderColour = ColourInfo.GradientVertical(innerBackground.Colour, glowColour); - BeatmapInfo.BindValueChanged(_ => updateValues()); mods.BindValueChanged(_ => { modSettingChangeTracker?.Dispose(); @@ -173,12 +171,20 @@ namespace osu.Game.Overlays.Mods updateValues(); }, true); - Collapsed.BindValueChanged(_ => updateCollapsedState(), true); - FinishTransforms(true); + Collapsed.BindValueChanged(_ => + { + // Only start autosize animations on first collapse toggle. This avoids an ugly initial presentation. + startAnimating(); + + updateCollapsedState(); + }); + + BeatmapInfo.BindValueChanged(_ => updateValues(), true); } protected override bool OnHover(HoverEvent e) { + startAnimating(); updateCollapsedState(); return true; } @@ -193,12 +199,19 @@ namespace osu.Game.Overlays.Mods protected override bool OnClick(ClickEvent e) => true; + private void startAnimating() + { + content.AutoSizeEasing = Easing.OutQuint; + content.AutoSizeDuration = transition_duration; + } + private void updateValues() => Scheduler.AddOnce(() => { if (BeatmapInfo.Value == null) return; cancellationSource?.Cancel(); + starDifficulty = difficultyCache.GetBindableDifficulty(BeatmapInfo.Value, (cancellationSource = new CancellationTokenSource()).Token); starDifficulty.BindValueChanged(s => { diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index d52782cf11..242f883068 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -339,9 +339,11 @@ namespace osu.Game.Overlays.Mods SearchTextBox.PlaceholderText = SearchTextBox.HasFocus ? Resources.Localisation.Web.CommonStrings.InputSearch : ModSelectOverlayStrings.TabToSearch; - if (modEffectPreviewPanel != null) + // only update preview panel's collapsed state after we are fully visible, to ensure all the buttons are where we expect them to be. + if (modEffectPreviewPanel != null && Alpha == 1) { float rightEdgeOfLastButton = footerButtonFlow.Last().ScreenSpaceDrawQuad.TopRight.X; + // this is cheating a bit; the 375 value is hardcoded based on how wide the expanded panel _generally_ is. // due to the transition applied, the raw screenspace quad of the panel cannot be used, as it will trigger an ugly feedback cycle of expanding and collapsing. float projectedLeftEdgeOfExpandedModEffectPreviewPanel = footerButtonFlow.ToScreenSpace(footerButtonFlow.DrawSize - new Vector2(375 + 70, 0)).X; From 3da30485b2766242f626798c206940cc52c9f90f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Sep 2023 17:06:42 +0900 Subject: [PATCH 28/29] Move shear spec to correct location --- .../Overlays/Mods/ModEffectPreviewPanel.cs | 20 +++++++++++++++---- .../Overlays/Mods/VerticalAttributeDisplay.cs | 8 +++++--- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs index b9511cc544..c961235cb2 100644 --- a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs +++ b/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs @@ -141,10 +141,22 @@ namespace osu.Game.Overlays.Mods Direction = FillDirection.Horizontal, Children = new[] { - circleSizeDisplay = new VerticalAttributeDisplay("CS"), - drainRateDisplay = new VerticalAttributeDisplay("HP"), - approachRateDisplay = new VerticalAttributeDisplay("AR"), - overallDifficultyDisplay = new VerticalAttributeDisplay("OD"), + circleSizeDisplay = new VerticalAttributeDisplay("CS") + { + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), + }, + drainRateDisplay = new VerticalAttributeDisplay("HP") + { + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), + }, + approachRateDisplay = new VerticalAttributeDisplay("AR") + { + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), + }, + overallDifficultyDisplay = new VerticalAttributeDisplay("OD") + { + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), + }, } } } diff --git a/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs b/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs index ba8efd1c2b..60cc875dbb 100644 --- a/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs +++ b/osu.Game/Overlays/Mods/VerticalAttributeDisplay.cs @@ -10,7 +10,6 @@ using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osuTK; namespace osu.Game.Overlays.Mods { @@ -32,9 +31,12 @@ namespace osu.Game.Overlays.Mods public VerticalAttributeDisplay(LocalisableString label) { Label = label; + AutoSizeAxes = Axes.X; - Origin = Anchor = Anchor.CentreLeft; - Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0); + + Origin = Anchor.CentreLeft; + Anchor = Anchor.CentreLeft; + InternalChild = new FillFlowContainer { Origin = Anchor.CentreLeft, From 7e3652284db7ab6bc14695ea4c4bb345edaf0bf1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Sep 2023 17:15:16 +0900 Subject: [PATCH 29/29] Adjust various class naming and add some xmldoc --- .../UserInterface/TestSceneModEffectPreviewPanel.cs | 4 ++-- .../Visual/UserInterface/TestSceneModsEffectDisplay.cs | 2 +- ...dEffectPreviewPanel.cs => BeatmapAttributesDisplay.cs} | 6 +++++- osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs | 2 +- .../Mods/{ModsEffectDisplay.cs => ModCounterDisplay.cs} | 6 +++--- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 8 ++++---- 6 files changed, 16 insertions(+), 12 deletions(-) rename osu.Game/Overlays/Mods/{ModEffectPreviewPanel.cs => BeatmapAttributesDisplay.cs} (97%) rename osu.Game/Overlays/Mods/{ModsEffectDisplay.cs => ModCounterDisplay.cs} (97%) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs index adb12ad249..b3ad5a499e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModEffectPreviewPanel.cs @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.UserInterface private Container content = null!; protected override Container Content => content; - private ModEffectPreviewPanel panel = null!; + private BeatmapAttributesDisplay panel = null!; [BackgroundDependencyLoader] private void load() @@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.UserInterface OsuModDifficultyAdjust difficultyAdjust = new OsuModDifficultyAdjust(); OsuModDoubleTime doubleTime = new OsuModDoubleTime(); - AddStep("create display", () => Child = panel = new ModEffectPreviewPanel + AddStep("create display", () => Child = panel = new BeatmapAttributesDisplay { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs index a1c8bef1de..bf6a718167 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs @@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("colours are correct", () => testDisplay.Container.Colour == colourProvider.Background5 && background.Colour == colours.ForModType(ModType.DifficultyIncrease)); } - private partial class TestDisplay : ModsEffectDisplay + private partial class TestDisplay : ModCounterDisplay { public Container Container => Content; diff --git a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs b/osu.Game/Overlays/Mods/BeatmapAttributesDisplay.cs similarity index 97% rename from osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs rename to osu.Game/Overlays/Mods/BeatmapAttributesDisplay.cs index c961235cb2..2aea53090a 100644 --- a/osu.Game/Overlays/Mods/ModEffectPreviewPanel.cs +++ b/osu.Game/Overlays/Mods/BeatmapAttributesDisplay.cs @@ -25,7 +25,11 @@ using osu.Game.Configuration; namespace osu.Game.Overlays.Mods { - public partial class ModEffectPreviewPanel : CompositeDrawable + /// + /// On the mod select overlay, this provides a local updating view of BPM, star rating and other + /// difficulty attributes so the user can have a better insight into what mods are changing. + /// + public partial class BeatmapAttributesDisplay : CompositeDrawable { private Container content = null!; private Container innerContent = null!; diff --git a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs index 9e16aa926f..9f4d187879 100644 --- a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs +++ b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs @@ -9,7 +9,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Mods { - public sealed partial class DifficultyMultiplierDisplay : ModsEffectDisplay + public sealed partial class DifficultyMultiplierDisplay : ModCounterDisplay { protected override LocalisableString Label => DifficultyMultiplierDisplayStrings.DifficultyMultiplier; diff --git a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs b/osu.Game/Overlays/Mods/ModCounterDisplay.cs similarity index 97% rename from osu.Game/Overlays/Mods/ModsEffectDisplay.cs rename to osu.Game/Overlays/Mods/ModCounterDisplay.cs index 3f31736ee1..3bec27d290 100644 --- a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs +++ b/osu.Game/Overlays/Mods/ModCounterDisplay.cs @@ -19,9 +19,9 @@ using osuTK; namespace osu.Game.Overlays.Mods { /// - /// Base class for displays of mods effects. + /// Base class for displays of singular counters. Not to be confused with which aggregates multiple attributes. /// - public abstract partial class ModsEffectDisplay : Container, IHasCurrentValue + public abstract partial class ModCounterDisplay : Container, IHasCurrentValue { public const float HEIGHT = 42; private const float transition_duration = 200; @@ -57,7 +57,7 @@ namespace osu.Game.Overlays.Mods protected readonly RollingCounter Counter; - protected ModsEffectDisplay() + protected ModCounterDisplay() { Height = HEIGHT; AutoSizeAxes = Axes.X; diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 242f883068..666e2849e8 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -124,7 +124,7 @@ namespace osu.Game.Overlays.Mods private Container aboveColumnsContent = null!; private DifficultyMultiplierDisplay? multiplierDisplay; - private ModEffectPreviewPanel? modEffectPreviewPanel; + private BeatmapAttributesDisplay? modEffectPreviewPanel; protected ShearedButton BackButton { get; private set; } = null!; protected ShearedToggleButton? CustomisationButton { get; private set; } @@ -181,7 +181,7 @@ namespace osu.Game.Overlays.Mods aboveColumnsContent = new Container { RelativeSizeAxes = Axes.X, - Height = ModsEffectDisplay.HEIGHT, + Height = ModCounterDisplay.HEIGHT, Padding = new MarginPadding { Horizontal = 100 }, Child = SearchTextBox = new ShearedSearchTextBox { @@ -196,7 +196,7 @@ namespace osu.Game.Overlays.Mods { Padding = new MarginPadding { - Top = ModsEffectDisplay.HEIGHT + PADDING, + Top = ModCounterDisplay.HEIGHT + PADDING, Bottom = PADDING }, RelativeSizeAxes = Axes.Both, @@ -257,7 +257,7 @@ namespace osu.Game.Overlays.Mods Origin = Anchor.TopRight }); - FooterContent.Add(modEffectPreviewPanel = new ModEffectPreviewPanel + FooterContent.Add(modEffectPreviewPanel = new BeatmapAttributesDisplay { Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight,