From e2001148d570ca139df57cf7cbd606adf8f50363 Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Tue, 8 Mar 2022 21:47:54 +0000 Subject: [PATCH 001/131] Implement strict tracking mod --- osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs | 3 + .../Mods/OsuModStrictTracking.cs | 59 +++++++++++++++++++ .../Objects/SliderTailCircle.cs | 4 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 1 + 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs index e04a30d06c..f46573c494 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.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 System.Linq; using osu.Framework.Bindables; using osu.Game.Configuration; @@ -16,6 +17,8 @@ namespace osu.Game.Rulesets.Osu.Mods { public class OsuModClassic : ModClassic, IApplicableToHitObject, IApplicableToDrawableHitObject, IApplicableToDrawableRuleset { + public override Type[] IncompatibleMods => new[] { typeof(OsuModStrictTracking) }; + [SettingSource("No slider head accuracy requirement", "Scores sliders proportionally to the number of ticks hit.")] public Bindable NoSliderHeadAccuracy { get; } = new BindableBool(true); diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs new file mode 100644 index 0000000000..13da422049 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -0,0 +1,59 @@ +// 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.Graphics.Sprites; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; + +namespace osu.Game.Rulesets.Osu.Mods +{ + public class OsuModStrictTracking : Mod, IApplicableToDifficulty, IApplicableToDrawableHitObject, IApplicableToHitObject + { + public override string Name => @"Strict Tracking"; + public override string Acronym => @"ST"; + public override IconUsage? Icon => FontAwesome.Solid.PenFancy; + public override ModType Type => ModType.DifficultyIncrease; + public override string Description => @"Follow circles just got serious..."; + public override double ScoreMultiplier => 1.0; + public override Type[] IncompatibleMods => new[] { typeof(ModClassic) }; + + public void ApplyToDifficulty(BeatmapDifficulty difficulty) + { + difficulty.SliderTickRate = 0.0; + } + + public void ApplyToDrawableHitObject(DrawableHitObject drawable) + { + if (drawable is DrawableSlider slider) + { + slider.Tracking.ValueChanged += e => + { + if (e.NewValue || slider.Judged) return; + + slider.MissForcefully(); + + foreach (var o in slider.NestedHitObjects) + { + if (o is DrawableOsuHitObject h && !o.Judged) + h.MissForcefully(); + } + }; + } + } + + public void ApplyToHitObject(HitObject hitObject) + { + switch (hitObject) + { + case Slider slider: + slider.TailCircle.JudgeAsSliderTick = true; + break; + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs index f9450062f4..70459dc432 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs @@ -14,12 +14,14 @@ namespace osu.Game.Rulesets.Osu.Objects /// public class SliderTailCircle : SliderEndCircle { + public bool JudgeAsSliderTick = false; + public SliderTailCircle(Slider slider) : base(slider) { } - public override Judgement CreateJudgement() => new SliderTailJudgement(); + public override Judgement CreateJudgement() => JudgeAsSliderTick ? (OsuJudgement)new SliderTickJudgement() : new SliderTailJudgement(); public class SliderTailJudgement : OsuJudgement { diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 5ade164566..faaab1a8e2 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -159,6 +159,7 @@ namespace osu.Game.Rulesets.Osu new MultiMod(new OsuModDoubleTime(), new OsuModNightcore()), new OsuModHidden(), new MultiMod(new OsuModFlashlight(), new OsuModBlinds()), + new OsuModStrictTracking() }; case ModType.Conversion: From 39c30516d0874b025d3e8e0610bd6ab096ebd2a6 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 14 Mar 2022 18:31:13 +0000 Subject: [PATCH 002/131] Implement `ChannelControlItem` for new chat design Adds new component `ChannelControlItem` and it's child components to be used as the clickable control in the new chat sidebar for joined channels. Has public properties `HasUnread` and `MentionCount` to control the display of the channel having unread messages or mentions of the user. Channel select/join requests are exposed via `OnRequestSelect` and `OnRequestLeave` events respectively which should be handled by a parent component. Requires a cached `Bindable` instance to be managed by a parent component. Requires a cached `OveralayColourScheme` instance to be provided by a parent component. --- .../Online/TestSceneChannelControlItem.cs | 145 +++++++++++++++ .../Chat/ChannelControl/ControlItem.cs | 167 ++++++++++++++++++ .../Chat/ChannelControl/ControlItemAvatar.cs | 60 +++++++ .../Chat/ChannelControl/ControlItemClose.cs | 55 ++++++ .../Chat/ChannelControl/ControlItemMention.cs | 77 ++++++++ .../Chat/ChannelControl/ControlItemText.cs | 71 ++++++++ 6 files changed, 575 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs create mode 100644 osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs create mode 100644 osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs create mode 100644 osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs create mode 100644 osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs create mode 100644 osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs new file mode 100644 index 0000000000..a1431f696b --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs @@ -0,0 +1,145 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Chat; +using osu.Game.Overlays; +using osu.Game.Overlays.Chat.ChannelControl; +using osuTK; + +namespace osu.Game.Tests.Visual.Online +{ + [TestFixture] + public class TestSceneChannelControlItem : OsuTestScene + { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); + + [Cached] + private readonly Bindable selected = new Bindable(); + + private static List channels = new List + { + createPublicChannel("#public-channel"), + createPublicChannel("#public-channel-long-name"), + createPrivateChannel("test user", 2), + createPrivateChannel("test user long name", 3), + }; + + private readonly Dictionary channelMap = new Dictionary(); + + private FillFlowContainer flow; + private OsuSpriteText selectedText; + private OsuSpriteText leaveText; + + [SetUp] + public void SetUp() + { + Schedule(() => + { + Children = new Drawable[] + { + selectedText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Y = -140, + }, + leaveText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Y = -120, + }, + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(190, 200), + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background6, + }, + flow = new FillFlowContainer + { + Spacing = new Vector2(20), + RelativeSizeAxes = Axes.Both, + }, + }, + }, + }; + + selected.BindValueChanged(change => + { + selectedText.Text = $"Selected Channel: {change.NewValue?.Name ?? "[null]"}"; + }, true); + + foreach (var channel in channels) + { + var item = new ControlItem(channel); + flow.Add(item); + channelMap.Add(channel, item); + item.OnRequestSelect += channel => selected.Value = channel; + item.OnRequestLeave += leaveChannel; + } + }); + } + + [Test] + public void TestVisual() + { + AddStep("Unread Selected", () => + { + if (selected.Value != null) + channelMap[selected.Value].HasUnread = true; + }); + + AddStep("Read Selected", () => + { + if (selected.Value != null) + channelMap[selected.Value].HasUnread = false; + }); + + AddStep("Add Mention Selected", () => + { + if (selected.Value != null) + channelMap[selected.Value].MentionCount++; + }); + + AddStep("Add 98 Mentions Selected", () => + { + if (selected.Value != null) + channelMap[selected.Value].MentionCount += 98; + }); + + AddStep("Clear Mentions Selected", () => + { + if (selected.Value != null) + channelMap[selected.Value].MentionCount = 0; + }); + } + + private void leaveChannel(Channel channel) + { + leaveText.Text = $"OnRequestLeave: {channel.Name}"; + leaveText.FadeIn().Then().FadeOut(1000, Easing.InQuint); + } + + private static Channel createPublicChannel(string name) => + new Channel { Name = name, Type = ChannelType.Public, Id = 1234 }; + + private static Channel createPrivateChannel(string username, int id) + => new Channel(new APIUser { Id = id, Username = username }); + } +} diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs new file mode 100644 index 0000000000..559f75f198 --- /dev/null +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs @@ -0,0 +1,167 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using System; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Game.Graphics.Containers; +using osu.Game.Online.Chat; + +namespace osu.Game.Overlays.Chat.ChannelControl +{ + public class ControlItem : OsuClickableContainer + { + public event Action? OnRequestSelect; + public event Action? OnRequestLeave; + + public int MentionCount + { + get => mention?.MentionCount ?? 0; + set + { + if (mention != null) + mention.MentionCount = value; + } + } + + public bool HasUnread + { + get => text?.HasUnread ?? false; + set + { + if (text != null) + text.HasUnread = value; + } + } + + private Box? hoverBox; + private Box? selectBox; + private ControlItemText? text; + private ControlItemMention? mention; + private ControlItemClose? close; + + [Resolved] + private Bindable? selectedChannel { get; set; } + + [Resolved] + private OverlayColourProvider? colourProvider { get; set; } + + private readonly Channel channel; + + public ControlItem(Channel channel) + { + this.channel = channel; + } + + [BackgroundDependencyLoader] + private void load() + { + Height = 30; + RelativeSizeAxes = Axes.X; + + Children = new Drawable[] + { + hoverBox = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider!.Background3, + Alpha = 0f, + }, + selectBox = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider!.Background4, + Alpha = 0f, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = 18, Right = 5 }, + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new Drawable[] + { + createAvatar(), + text = new ControlItemText(channel) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + mention = new ControlItemMention + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Right = 3 }, + }, + close = new ControlItemClose + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Right = 3 }, + } + } + }, + }, + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + selectedChannel?.BindValueChanged(change => + { + if (change.NewValue == channel) + selectBox?.Show(); + else + selectBox?.Hide(); + }, true); + + Action = () => OnRequestSelect?.Invoke(channel); + close!.Action = () => OnRequestLeave?.Invoke(channel); + } + + protected override bool OnHover(HoverEvent e) + { + hoverBox?.Show(); + close?.Show(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + hoverBox?.Hide(); + close?.Hide(); + base.OnHoverLost(e); + } + + private Drawable createAvatar() + { + if (channel.Type != ChannelType.PM) + return Drawable.Empty(); + + return new ControlItemAvatar(channel) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }; + } + } +} diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs new file mode 100644 index 0000000000..9192f20cb1 --- /dev/null +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs @@ -0,0 +1,60 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Online.Chat; +using osu.Game.Users.Drawables; +using osuTK; + +namespace osu.Game.Overlays.Chat.ChannelControl +{ + public class ControlItemAvatar : CircularContainer + { + private DrawableAvatar? avatar; + private readonly Channel channel; + + public ControlItemAvatar(Channel channel) + { + this.channel = channel; + } + + [BackgroundDependencyLoader] + private void load() + { + Size = new Vector2(20); + Margin = new MarginPadding { Right = 5 }; + Masking = true; + + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.Solid.At, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = Colour4.Black, + RelativeSizeAxes = Axes.Both, + Alpha = 0.2f, + }, + new DelayedLoadWrapper(avatar = new DrawableAvatar(channel.Users.First()) + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }), + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + avatar!.OnLoadComplete += d => d.FadeInFromZero(300, Easing.OutQuint); + } + } +} diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs new file mode 100644 index 0000000000..4b190e18fd --- /dev/null +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs @@ -0,0 +1,55 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; +using osu.Game.Graphics.Containers; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Chat.ChannelControl +{ + public class ControlItemClose : OsuClickableContainer + { + private readonly SpriteIcon icon; + + public ControlItemClose() + { + Alpha = 0f; + Size = new Vector2(20); + Child = icon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(0.75f), + Icon = FontAwesome.Solid.TimesCircle, + RelativeSizeAxes = Axes.Both, + }; + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + icon.ScaleTo(0.5f, 1000, Easing.OutQuint); + return base.OnMouseDown(e); + } + + protected override void OnMouseUp(MouseUpEvent e) + { + icon.ScaleTo(0.75f, 1000, Easing.OutElastic); + base.OnMouseUp(e); + } + + protected override bool OnHover(HoverEvent e) + { + icon.FadeColour(Color4.Red, 200, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + icon.FadeColour(Color4.White, 200, Easing.OutQuint); + base.OnHoverLost(e); + } + } +} diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs new file mode 100644 index 0000000000..12de154faa --- /dev/null +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs @@ -0,0 +1,77 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osuTK; + +namespace osu.Game.Overlays.Chat.ChannelControl +{ + public class ControlItemMention : CircularContainer + { + private int mentionCount = 0; + public int MentionCount + { + get => mentionCount; + set + { + if (value == mentionCount) + return; + + mentionCount = value; + updateText(); + } + } + + private OsuSpriteText? countText; + + [Resolved] + private OverlayColourProvider? colourProvider { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + Masking = true; + Size = new Vector2(20, 12); + Alpha = 0f; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider!.Colour1, + }, + countText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.Torus.With(size: 11, weight: FontWeight.Bold), + Margin = new MarginPadding { Bottom = 1 }, + Colour = colourProvider.Background5, + }, + }; + + updateText(); + } + + private void updateText() + { + if (mentionCount > 99) + countText!.Text = "99+"; + else + countText!.Text = mentionCount.ToString(); + + if (mentionCount > 0) + this.Show(); + else + this.Hide(); + } + } +} diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs new file mode 100644 index 0000000000..2b8f50e184 --- /dev/null +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs @@ -0,0 +1,71 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Chat; + +namespace osu.Game.Overlays.Chat.ChannelControl +{ + public class ControlItemText : Container + { + public bool HasUnread + { + get => hasUnread; + set + { + if (hasUnread == value) + return; + + hasUnread = value; + updateText(); + } + } + + private bool hasUnread = false; + private OsuSpriteText? text; + + [Resolved] + private OverlayColourProvider? colourProvider { get; set; } + + private readonly Channel channel; + + public ControlItemText(Channel channel) + { + this.channel = channel; + } + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Both; + Child = text = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = channel.Type == ChannelType.Public ? $"# {channel.Name.Substring(1)}" : channel.Name, + Font = OsuFont.Torus.With(size: 17, weight: FontWeight.SemiBold), + Colour = colourProvider!.Light3, + Margin = new MarginPadding { Bottom = 2 }, + RelativeSizeAxes = Axes.X, + Truncate = true, + }; + } + + private void updateText() + { + if (!IsLoaded) + return; + + if (HasUnread) + text!.Colour = Colour4.White; + else + text!.Colour = colourProvider!.Light3; + } + } +} From c0d82dfb41478a97e633a60fe847930bf85bf7ca Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 14 Mar 2022 19:42:55 +0000 Subject: [PATCH 003/131] Code quality fixes --- .../Visual/Online/TestSceneChannelControlItem.cs | 4 ++-- osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs | 2 +- .../Chat/ChannelControl/ControlItemMention.cs | 12 +++++------- .../Overlays/Chat/ChannelControl/ControlItemText.cs | 3 ++- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs index a1431f696b..64ad924ecb 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs @@ -26,7 +26,7 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly Bindable selected = new Bindable(); - private static List channels = new List + private static readonly List channels = new List { createPublicChannel("#public-channel"), createPublicChannel("#public-channel-long-name"), @@ -90,7 +90,7 @@ namespace osu.Game.Tests.Visual.Online var item = new ControlItem(channel); flow.Add(item); channelMap.Add(channel, item); - item.OnRequestSelect += channel => selected.Value = channel; + item.OnRequestSelect += c => selected.Value = c; item.OnRequestLeave += leaveChannel; } }); diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs index 559f75f198..e475ac7821 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs @@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl }, Content = new[] { - new Drawable[] + new[] { createAvatar(), text = new ControlItemText(channel) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs index 12de154faa..6af2e26af8 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs @@ -15,7 +15,8 @@ namespace osu.Game.Overlays.Chat.ChannelControl { public class ControlItemMention : CircularContainer { - private int mentionCount = 0; + private int mentionCount; + public int MentionCount { get => mentionCount; @@ -63,15 +64,12 @@ namespace osu.Game.Overlays.Chat.ChannelControl private void updateText() { - if (mentionCount > 99) - countText!.Text = "99+"; - else - countText!.Text = mentionCount.ToString(); + countText!.Text = MentionCount > 99 ? "99+" : MentionCount.ToString(); if (mentionCount > 0) - this.Show(); + Show(); else - this.Hide(); + Hide(); } } } diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs index 2b8f50e184..bb88d733d4 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs @@ -14,6 +14,8 @@ namespace osu.Game.Overlays.Chat.ChannelControl { public class ControlItemText : Container { + private bool hasUnread; + public bool HasUnread { get => hasUnread; @@ -27,7 +29,6 @@ namespace osu.Game.Overlays.Chat.ChannelControl } } - private bool hasUnread = false; private OsuSpriteText? text; [Resolved] From e9f0ad33efca61ccbbb0a09c14f88615d3e2f819 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 14 Mar 2022 20:06:31 +0000 Subject: [PATCH 004/131] Use autosizing for ChannelControlItem test scene --- .../Online/TestSceneChannelControlItem.cs | 63 +++++++++++-------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs index 64ad924ecb..7f76dca013 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs @@ -45,36 +45,47 @@ namespace osu.Game.Tests.Visual.Online { Schedule(() => { - Children = new Drawable[] + Child = new FillFlowContainer { - selectedText = new OsuSpriteText + Direction = FillDirection.Vertical, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(10), + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Y = -140, - }, - leaveText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Y = -120, - }, - new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(190, 200), - Children = new Drawable[] + selectedText = new OsuSpriteText { - new Box + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + leaveText = new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Height = 16, + AlwaysPresent = true, + }, + new Container + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Y, + Width = 190, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background6, - }, - flow = new FillFlowContainer - { - Spacing = new Vector2(20), - RelativeSizeAxes = Axes.Both, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background6, + }, + flow = new FillFlowContainer + { + Direction = FillDirection.Vertical, + Spacing = new Vector2(20), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }, }, }, }, From 12472593cc4f2c7b36a8682c7d63d17315e7a9cf Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 14 Mar 2022 20:14:04 +0000 Subject: [PATCH 005/131] Mark required dependencies as non-nullable --- .../Overlays/Chat/ChannelControl/ControlItem.cs | 14 +++++++------- .../Chat/ChannelControl/ControlItemAvatar.cs | 3 ++- .../Chat/ChannelControl/ControlItemMention.cs | 4 ++-- .../Chat/ChannelControl/ControlItemText.cs | 8 ++++---- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs index e475ac7821..073173f2ff 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs @@ -40,6 +40,8 @@ namespace osu.Game.Overlays.Chat.ChannelControl } } + private readonly Channel channel; + private Box? hoverBox; private Box? selectBox; private ControlItemText? text; @@ -47,12 +49,10 @@ namespace osu.Game.Overlays.Chat.ChannelControl private ControlItemClose? close; [Resolved] - private Bindable? selectedChannel { get; set; } + private Bindable selectedChannel { get; set; } = null!; [Resolved] - private OverlayColourProvider? colourProvider { get; set; } - - private readonly Channel channel; + private OverlayColourProvider colourProvider { get; set; } = null!; public ControlItem(Channel channel) { @@ -70,13 +70,13 @@ namespace osu.Game.Overlays.Chat.ChannelControl hoverBox = new Box { RelativeSizeAxes = Axes.Both, - Colour = colourProvider!.Background3, + Colour = colourProvider.Background3, Alpha = 0f, }, selectBox = new Box { RelativeSizeAxes = Axes.Both, - Colour = colourProvider!.Background4, + Colour = colourProvider.Background4, Alpha = 0f, }, new Container @@ -126,7 +126,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl { base.LoadComplete(); - selectedChannel?.BindValueChanged(change => + selectedChannel.BindValueChanged(change => { if (change.NewValue == channel) selectBox?.Show(); diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs index 9192f20cb1..62b893f3bc 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs @@ -16,9 +16,10 @@ namespace osu.Game.Overlays.Chat.ChannelControl { public class ControlItemAvatar : CircularContainer { - private DrawableAvatar? avatar; private readonly Channel channel; + private DrawableAvatar? avatar; + public ControlItemAvatar(Channel channel) { this.channel = channel; diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs index 6af2e26af8..693fb68217 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl private OsuSpriteText? countText; [Resolved] - private OverlayColourProvider? colourProvider { get; set; } + private OverlayColourProvider colourProvider { get; set; } = null!; [BackgroundDependencyLoader] private void load() @@ -47,7 +47,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl new Box { RelativeSizeAxes = Axes.Both, - Colour = colourProvider!.Colour1, + Colour = colourProvider.Colour1, }, countText = new OsuSpriteText { diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs index bb88d733d4..9b0f5011fc 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs @@ -29,12 +29,12 @@ namespace osu.Game.Overlays.Chat.ChannelControl } } + private readonly Channel channel; + private OsuSpriteText? text; [Resolved] - private OverlayColourProvider? colourProvider { get; set; } - - private readonly Channel channel; + private OverlayColourProvider colourProvider { get; set; } = null!; public ControlItemText(Channel channel) { @@ -51,7 +51,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl Origin = Anchor.CentreLeft, Text = channel.Type == ChannelType.Public ? $"# {channel.Name.Substring(1)}" : channel.Name, Font = OsuFont.Torus.With(size: 17, weight: FontWeight.SemiBold), - Colour = colourProvider!.Light3, + Colour = colourProvider.Light3, Margin = new MarginPadding { Bottom = 2 }, RelativeSizeAxes = Axes.X, Truncate = true, From e91af664ef080c250fbfd6997dd5aa1033f502d1 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 14 Mar 2022 20:37:54 +0000 Subject: [PATCH 006/131] Adjust ControlItemAvatar placeholder animation and colour --- .../Overlays/Chat/ChannelControl/ControlItemAvatar.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs index 62b893f3bc..bb3109ec1f 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs @@ -18,6 +18,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl { private readonly Channel channel; + private SpriteIcon? placeholder; private DrawableAvatar? avatar; public ControlItemAvatar(Channel channel) @@ -34,14 +35,14 @@ namespace osu.Game.Overlays.Chat.ChannelControl Children = new Drawable[] { - new SpriteIcon + placeholder = new SpriteIcon { Icon = FontAwesome.Solid.At, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Colour = Colour4.Black, + Colour = Colour4.White, RelativeSizeAxes = Axes.Both, - Alpha = 0.2f, + Alpha = 0.5f, }, new DelayedLoadWrapper(avatar = new DrawableAvatar(channel.Users.First()) { @@ -55,7 +56,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl protected override void LoadComplete() { base.LoadComplete(); - avatar!.OnLoadComplete += d => d.FadeInFromZero(300, Easing.OutQuint); + avatar!.OnLoadComplete += _ => placeholder!.FadeOut(250); } } } From 9621ef9437ca389fde4295e507d8681ee14ee3bb Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 14 Mar 2022 21:10:39 +0000 Subject: [PATCH 007/131] Use OsuColour.Red1 for ControlItemClose hover colour --- .../Visual/Online/TestSceneChannelControlItem.cs | 4 ++++ .../Overlays/Chat/ChannelControl/ControlItemClose.cs | 10 +++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs index 7f76dca013..9464d244be 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs @@ -8,6 +8,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; @@ -23,6 +24,9 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); + [Cached] + private readonly OsuColour osuColour = new OsuColour(); + [Cached] private readonly Bindable selected = new Bindable(); diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs index 4b190e18fd..4730d7b72d 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs @@ -1,12 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; +using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osuTK; -using osuTK.Graphics; namespace osu.Game.Overlays.Chat.ChannelControl { @@ -14,6 +15,9 @@ namespace osu.Game.Overlays.Chat.ChannelControl { private readonly SpriteIcon icon; + [Resolved] + private OsuColour osuColour { get; set; } = null!; + public ControlItemClose() { Alpha = 0f; @@ -42,13 +46,13 @@ namespace osu.Game.Overlays.Chat.ChannelControl protected override bool OnHover(HoverEvent e) { - icon.FadeColour(Color4.Red, 200, Easing.OutQuint); + icon.FadeColour(osuColour.Red1, 200, Easing.OutQuint); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - icon.FadeColour(Color4.White, 200, Easing.OutQuint); + icon.FadeColour(Colour4.White, 200, Easing.OutQuint); base.OnHoverLost(e); } } From 3aa343b9870dc3487013151889880f282b29cafe Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 14 Mar 2022 21:14:33 +0000 Subject: [PATCH 008/131] Use OsuColour.YellowLight for ControlItemMention background --- osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs index 693fb68217..370c435266 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs @@ -32,6 +32,9 @@ namespace osu.Game.Overlays.Chat.ChannelControl private OsuSpriteText? countText; + [Resolved] + private OsuColour osuColour { get; set; } = null!; + [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -47,7 +50,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl new Box { RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Colour1, + Colour = osuColour.YellowLight, }, countText = new OsuSpriteText { From 1f0f6990f096d15a064eda731bd2dbad876ff786 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 14 Mar 2022 21:16:28 +0000 Subject: [PATCH 009/131] Use ColourProvider.Content1 for ControlItemText colour --- osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs index 9b0f5011fc..0c91903f6b 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs @@ -64,9 +64,9 @@ namespace osu.Game.Overlays.Chat.ChannelControl return; if (HasUnread) - text!.Colour = Colour4.White; + text!.Colour = colourProvider.Content1; else - text!.Colour = colourProvider!.Light3; + text!.Colour = colourProvider.Light3; } } } From b01a809d551efcb342e59046ae087d46309323fe Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 14 Mar 2022 21:26:33 +0000 Subject: [PATCH 010/131] Refactor ControlItemMention to use bindable flow --- .../Online/TestSceneChannelControlItem.cs | 6 +-- .../Chat/ChannelControl/ControlItem.cs | 11 +---- .../Chat/ChannelControl/ControlItemMention.cs | 41 ++++++++----------- 3 files changed, 23 insertions(+), 35 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs index 9464d244be..2e5c2cc2cb 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs @@ -129,19 +129,19 @@ namespace osu.Game.Tests.Visual.Online AddStep("Add Mention Selected", () => { if (selected.Value != null) - channelMap[selected.Value].MentionCount++; + channelMap[selected.Value].Mentions.Value++; }); AddStep("Add 98 Mentions Selected", () => { if (selected.Value != null) - channelMap[selected.Value].MentionCount += 98; + channelMap[selected.Value].Mentions.Value += 98; }); AddStep("Clear Mentions Selected", () => { if (selected.Value != null) - channelMap[selected.Value].MentionCount = 0; + channelMap[selected.Value].Mentions.Value = 0; }); } diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs index 073173f2ff..d88a99c484 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs @@ -20,15 +20,8 @@ namespace osu.Game.Overlays.Chat.ChannelControl public event Action? OnRequestSelect; public event Action? OnRequestLeave; - public int MentionCount - { - get => mention?.MentionCount ?? 0; - set - { - if (mention != null) - mention.MentionCount = value; - } - } + [Cached] + public readonly BindableInt Mentions = new BindableInt(); public bool HasUnread { diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs index 370c435266..594a52b8a7 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs @@ -4,6 +4,7 @@ #nullable enable using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -15,23 +16,11 @@ namespace osu.Game.Overlays.Chat.ChannelControl { public class ControlItemMention : CircularContainer { - private int mentionCount; - - public int MentionCount - { - get => mentionCount; - set - { - if (value == mentionCount) - return; - - mentionCount = value; - updateText(); - } - } - private OsuSpriteText? countText; + [Resolved] + private BindableInt mentions { get; set; } = null!; + [Resolved] private OsuColour osuColour { get; set; } = null!; @@ -61,18 +50,24 @@ namespace osu.Game.Overlays.Chat.ChannelControl Colour = colourProvider.Background5, }, }; - - updateText(); } - private void updateText() + protected override void LoadComplete() { - countText!.Text = MentionCount > 99 ? "99+" : MentionCount.ToString(); + base.LoadComplete(); - if (mentionCount > 0) - Show(); - else - Hide(); + mentions.BindValueChanged(change => + { + int mentionCount = change.NewValue; + + countText!.Text = mentionCount > 99 ? "99+" : mentionCount.ToString(); + + if (mentionCount > 0) + Show(); + else + Hide(); + }, true); } + } } From 75958bf2702778784caee4c70ed3040170f16a5e Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 14 Mar 2022 21:32:30 +0000 Subject: [PATCH 011/131] Refactor ControlItemText to use bindable flow for unread state --- .../Online/TestSceneChannelControlItem.cs | 4 +-- .../Chat/ChannelControl/ControlItem.cs | 11 ++---- .../Chat/ChannelControl/ControlItemText.cs | 35 +++++++------------ 3 files changed, 17 insertions(+), 33 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs index 2e5c2cc2cb..9af3b7613b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs @@ -117,13 +117,13 @@ namespace osu.Game.Tests.Visual.Online AddStep("Unread Selected", () => { if (selected.Value != null) - channelMap[selected.Value].HasUnread = true; + channelMap[selected.Value].Unread.Value = true; }); AddStep("Read Selected", () => { if (selected.Value != null) - channelMap[selected.Value].HasUnread = false; + channelMap[selected.Value].Unread.Value = false; }); AddStep("Add Mention Selected", () => diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs index d88a99c484..4b1bbaec82 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs @@ -23,15 +23,8 @@ namespace osu.Game.Overlays.Chat.ChannelControl [Cached] public readonly BindableInt Mentions = new BindableInt(); - public bool HasUnread - { - get => text?.HasUnread ?? false; - set - { - if (text != null) - text.HasUnread = value; - } - } + [Cached] + public readonly BindableBool Unread = new BindableBool(); private readonly Channel channel; diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs index 0c91903f6b..3573c72846 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs @@ -4,6 +4,7 @@ #nullable enable using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; @@ -14,25 +15,13 @@ namespace osu.Game.Overlays.Chat.ChannelControl { public class ControlItemText : Container { - private bool hasUnread; - - public bool HasUnread - { - get => hasUnread; - set - { - if (hasUnread == value) - return; - - hasUnread = value; - updateText(); - } - } - private readonly Channel channel; private OsuSpriteText? text; + [Resolved] + private BindableBool unread { get; set; } = null!; + [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -58,15 +47,17 @@ namespace osu.Game.Overlays.Chat.ChannelControl }; } - private void updateText() + protected override void LoadComplete() { - if (!IsLoaded) - return; + base.LoadComplete(); - if (HasUnread) - text!.Colour = colourProvider.Content1; - else - text!.Colour = colourProvider.Light3; + unread.BindValueChanged(change => + { + if (change.NewValue) + text!.Colour = colourProvider.Content1; + else + text!.Colour = colourProvider.Light3; + }, true); } } } From ec61b88ec27796836ae380c5e845101e1f06f589 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 14 Mar 2022 21:39:57 +0000 Subject: [PATCH 012/131] Adjust ControlItem padding --- osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs index 4b1bbaec82..e944bf4c28 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs @@ -68,7 +68,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = 18, Right = 5 }, + Padding = new MarginPadding { Left = 18, Right = 10 }, Child = new GridContainer { RelativeSizeAxes = Axes.Both, From 73a0373b4ed0d2de982c84b236dafae6c02ee677 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 14 Mar 2022 21:56:56 +0000 Subject: [PATCH 013/131] Code quality fixes --- osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs | 6 ++---- osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs | 1 - osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs | 5 +---- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs index e944bf4c28..f2bab64371 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs @@ -30,8 +30,6 @@ namespace osu.Game.Overlays.Chat.ChannelControl private Box? hoverBox; private Box? selectBox; - private ControlItemText? text; - private ControlItemMention? mention; private ControlItemClose? close; [Resolved] @@ -84,12 +82,12 @@ namespace osu.Game.Overlays.Chat.ChannelControl new[] { createAvatar(), - text = new ControlItemText(channel) + new ControlItemText(channel) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, }, - mention = new ControlItemMention + new ControlItemMention { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs index 594a52b8a7..e9172d99ba 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs @@ -68,6 +68,5 @@ namespace osu.Game.Overlays.Chat.ChannelControl Hide(); }, true); } - } } diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs index 3573c72846..89845dfef8 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs @@ -53,10 +53,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl unread.BindValueChanged(change => { - if (change.NewValue) - text!.Colour = colourProvider.Content1; - else - text!.Colour = colourProvider.Light3; + text!.Colour = change.NewValue ? colourProvider.Content1 : colourProvider.Light3; }, true); } } From 6628b7c654789619617475f7114c84b35acde86a Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 14 Mar 2022 22:21:18 +0000 Subject: [PATCH 014/131] Ensure existing items are expired and cleared in ChannelControlItem test setup --- osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs index 9af3b7613b..e496ef60d7 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs @@ -49,6 +49,11 @@ namespace osu.Game.Tests.Visual.Online { Schedule(() => { + foreach (var item in channelMap.Values) + item.Expire(); + + channelMap.Clear(); + Child = new FillFlowContainer { Direction = FillDirection.Vertical, From 7621e779fa8667110e1b477c5fba3481627ea7f1 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Tue, 15 Mar 2022 22:19:58 +0000 Subject: [PATCH 015/131] Move `ControlItem` Action assignments into BDL --- osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs index f2bab64371..d886e8b45a 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs @@ -98,12 +98,15 @@ namespace osu.Game.Overlays.Chat.ChannelControl Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Margin = new MarginPadding { Right = 3 }, + Action = () => OnRequestLeave?.Invoke(channel), } } }, }, }, }; + + Action = () => OnRequestSelect?.Invoke(channel); } protected override void LoadComplete() @@ -117,9 +120,6 @@ namespace osu.Game.Overlays.Chat.ChannelControl else selectBox?.Hide(); }, true); - - Action = () => OnRequestSelect?.Invoke(channel); - close!.Action = () => OnRequestLeave?.Invoke(channel); } protected override bool OnHover(HoverEvent e) From 481b8fe80bc043b6a70ad1b799fefd94ba58af06 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Tue, 15 Mar 2022 22:22:32 +0000 Subject: [PATCH 016/131] Use `Orange1` for `ControlItemMention` background colour --- osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs index e9172d99ba..5118386977 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs @@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl new Box { RelativeSizeAxes = Axes.Both, - Colour = osuColour.YellowLight, + Colour = osuColour.Orange1, }, countText = new OsuSpriteText { From 49b74d78670d85ef7a3b159b43b9504c5ff7156a Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Tue, 15 Mar 2022 22:33:36 +0000 Subject: [PATCH 017/131] Use `BindTarget` instead of caching for `ControlItem` mentions bindable flow --- osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs | 2 +- .../Overlays/Chat/ChannelControl/ControlItemMention.cs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs index d886e8b45a..d73ebed817 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs @@ -20,7 +20,6 @@ namespace osu.Game.Overlays.Chat.ChannelControl public event Action? OnRequestSelect; public event Action? OnRequestLeave; - [Cached] public readonly BindableInt Mentions = new BindableInt(); [Cached] @@ -92,6 +91,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Margin = new MarginPadding { Right = 3 }, + Mentions = { BindTarget = Mentions }, }, close = new ControlItemClose { diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs index 5118386977..beb2713c92 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs @@ -16,10 +16,9 @@ namespace osu.Game.Overlays.Chat.ChannelControl { public class ControlItemMention : CircularContainer { - private OsuSpriteText? countText; + public readonly BindableInt Mentions = new BindableInt(); - [Resolved] - private BindableInt mentions { get; set; } = null!; + private OsuSpriteText? countText; [Resolved] private OsuColour osuColour { get; set; } = null!; @@ -56,7 +55,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl { base.LoadComplete(); - mentions.BindValueChanged(change => + Mentions.BindValueChanged(change => { int mentionCount = change.NewValue; From e38d9eafa053a4ddc0e374cbead1063a3f194d8c Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Tue, 15 Mar 2022 22:37:15 +0000 Subject: [PATCH 018/131] Use `BindTarget` instead of caching for `ControlItem` unread flow --- osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs | 2 +- osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs index d73ebed817..cc00550965 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs @@ -22,7 +22,6 @@ namespace osu.Game.Overlays.Chat.ChannelControl public readonly BindableInt Mentions = new BindableInt(); - [Cached] public readonly BindableBool Unread = new BindableBool(); private readonly Channel channel; @@ -85,6 +84,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, + Unread = { BindTarget = Unread }, }, new ControlItemMention { diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs index 89845dfef8..490edb5d28 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs @@ -15,13 +15,12 @@ namespace osu.Game.Overlays.Chat.ChannelControl { public class ControlItemText : Container { + public readonly BindableBool Unread = new BindableBool(); + private readonly Channel channel; private OsuSpriteText? text; - [Resolved] - private BindableBool unread { get; set; } = null!; - [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; @@ -51,7 +50,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl { base.LoadComplete(); - unread.BindValueChanged(change => + Unread.BindValueChanged(change => { text!.Colour = change.NewValue ? colourProvider.Content1 : colourProvider.Light3; }, true); From c2e4779c2ed429a5e54dd405938e80347f1d2bab Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Wed, 16 Mar 2022 11:57:11 +0000 Subject: [PATCH 019/131] Remove redundant spacing in `ControlItem` test scene --- osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs index e496ef60d7..8289be033a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs @@ -91,7 +91,6 @@ namespace osu.Game.Tests.Visual.Online flow = new FillFlowContainer { Direction = FillDirection.Vertical, - Spacing = new Vector2(20), RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, }, From 03d3969b38ebd37e03e8b09c4f6eed5218f4766d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 16 Mar 2022 21:46:02 +0100 Subject: [PATCH 020/131] Remove unnecessary `OsuColour` cache One is already cached at `OsuGameBase` level. --- osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs index 8289be033a..3465e7dfec 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs @@ -8,7 +8,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; @@ -24,9 +23,6 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); - [Cached] - private readonly OsuColour osuColour = new OsuColour(); - [Cached] private readonly Bindable selected = new Bindable(); From a8cefca685f9ec5faed81112a70f894c838f7f54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 16 Mar 2022 21:49:04 +0100 Subject: [PATCH 021/131] Simplify fade-out transform --- osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs index 3465e7dfec..e66092bf27 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs @@ -148,7 +148,7 @@ namespace osu.Game.Tests.Visual.Online private void leaveChannel(Channel channel) { leaveText.Text = $"OnRequestLeave: {channel.Name}"; - leaveText.FadeIn().Then().FadeOut(1000, Easing.InQuint); + leaveText.FadeOutFromOne(1000, Easing.InQuint); } private static Channel createPublicChannel(string name) => From b21fa78cbfa57b749138fdcd36a256ea727bc610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 16 Mar 2022 21:55:36 +0100 Subject: [PATCH 022/131] Move dependencies out of fields to BDL args where possible --- osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs | 5 +---- .../Overlays/Chat/ChannelControl/ControlItemMention.cs | 8 +------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs index cc00550965..c27d5fdf5d 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs @@ -33,16 +33,13 @@ namespace osu.Game.Overlays.Chat.ChannelControl [Resolved] private Bindable selectedChannel { get; set; } = null!; - [Resolved] - private OverlayColourProvider colourProvider { get; set; } = null!; - public ControlItem(Channel channel) { this.channel = channel; } [BackgroundDependencyLoader] - private void load() + private void load(OverlayColourProvider colourProvider) { Height = 30; RelativeSizeAxes = Axes.X; diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs index beb2713c92..34e1e33c87 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs @@ -20,14 +20,8 @@ namespace osu.Game.Overlays.Chat.ChannelControl private OsuSpriteText? countText; - [Resolved] - private OsuColour osuColour { get; set; } = null!; - - [Resolved] - private OverlayColourProvider colourProvider { get; set; } = null!; - [BackgroundDependencyLoader] - private void load() + private void load(OsuColour osuColour, OverlayColourProvider colourProvider) { Masking = true; Size = new Vector2(20, 12); From 93bc0ac86966bed11fd59ce02df600e4cf717844 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 17 Mar 2022 17:49:35 +0900 Subject: [PATCH 023/131] Update download links in README.md for macOS (to add Apple Silicon) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f64240f67a..dba0b2670d 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ If you are looking to install or test osu! without setting up a development envi **Latest build:** -| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.15+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 10+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) +| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | macOS 10.15+ ([Intel](https://github.com/ppy/osu/releases/latest/download/osu.app.Intel.zip), [Apple Silicon](https://github.com/ppy/osu/releases/latest/download/osu.app.Apple.Silicon.zip)) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 10+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) | ------------- | ------------- | ------------- | ------------- | ------------- | - The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets. From 0d79dd5e62bd40d850a2eba9fd20eda870d2d790 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 17 Mar 2022 18:45:31 +0900 Subject: [PATCH 024/131] Update SimpleUpdateManager to handle new macOS build naming scheme --- osu.Game/Updater/SimpleUpdateManager.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Updater/SimpleUpdateManager.cs b/osu.Game/Updater/SimpleUpdateManager.cs index 61ca68a1ab..c57a7c768e 100644 --- a/osu.Game/Updater/SimpleUpdateManager.cs +++ b/osu.Game/Updater/SimpleUpdateManager.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using System.Runtime.InteropServices; using System.Threading.Tasks; using osu.Framework; using osu.Framework.Allocation; @@ -82,7 +83,8 @@ namespace osu.Game.Updater break; case RuntimeInfo.Platform.macOS: - bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".app.zip", StringComparison.Ordinal)); + string arch = RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "Apple.Silicon" : "Intel"; + bestAsset = release.Assets?.Find(f => f.Name.EndsWith($".app.{arch}.zip", StringComparison.Ordinal)); break; case RuntimeInfo.Platform.Linux: From d1fd14e287eb7ff00e36d87e3b76f53df2207912 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 13:57:36 +0900 Subject: [PATCH 025/131] Add missing `nullable` --- osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs index 4730d7b72d..c0f419f619 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs @@ -1,6 +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 enable + using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; From 5d940ded09d91d1e1d217b173fa598ed5196985e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 13:59:03 +0900 Subject: [PATCH 026/131] Fix incorrect usage of nullable in `ControlItemMention` --- osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs index 34e1e33c87..f4d65e3cef 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs @@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl { public readonly BindableInt Mentions = new BindableInt(); - private OsuSpriteText? countText; + private OsuSpriteText countText = null!; [BackgroundDependencyLoader] private void load(OsuColour osuColour, OverlayColourProvider colourProvider) @@ -53,7 +53,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl { int mentionCount = change.NewValue; - countText!.Text = mentionCount > 99 ? "99+" : mentionCount.ToString(); + countText.Text = mentionCount > 99 ? "99+" : mentionCount.ToString(); if (mentionCount > 0) Show(); From dfda093f4b8a74726eb1a0dfda261c01de98e3db Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 14:03:52 +0900 Subject: [PATCH 027/131] Rename icon creation method --- osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs index c27d5fdf5d..bf4d60d4e2 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs @@ -76,7 +76,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl { new[] { - createAvatar(), + createIcon(), new ControlItemText(channel) { Anchor = Anchor.CentreLeft, @@ -133,7 +133,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl base.OnHoverLost(e); } - private Drawable createAvatar() + private Drawable createIcon() { if (channel.Type != ChannelType.PM) return Drawable.Empty(); From c2e7ff7e3e2dd645f46b90851307e7f3ed72dd6d Mon Sep 17 00:00:00 2001 From: hwabis Date: Fri, 18 Mar 2022 01:37:53 -0400 Subject: [PATCH 028/131] display count of listQueue --- .../Match/Playlist/MultiplayerPlaylist.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs index eeafebfec0..edd6cf93e9 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs @@ -7,6 +7,8 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; @@ -29,6 +31,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist private MultiplayerHistoryList historyList; private bool firstPopulation = true; + private OsuSpriteText queueListCount; + [BackgroundDependencyLoader] private void load() { @@ -42,6 +46,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist Height = tab_control_height, Current = { BindTarget = DisplayMode } }, + queueListCount = new OsuSpriteText + { + Font = OsuFont.Default.With(weight: FontWeight.Bold), + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, new Container { RelativeSizeAxes = Axes.Both, @@ -70,6 +80,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist { base.LoadComplete(); DisplayMode.BindValueChanged(onDisplayModeChanged, true); + queueList.Items.BindCollectionChanged( + (_, __) => queueListCount.Text = queueList.Items.Count.ToString(), true); } private void onDisplayModeChanged(ValueChangedEvent mode) From 3f92bef9dfe3f58e98127705b75906bd06658aed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 16:50:37 +0900 Subject: [PATCH 029/131] Add setting for judgement line thickness --- .../Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 542731cf93..068a7f96cc 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -4,12 +4,14 @@ using System; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Game.Configuration; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osuTK; @@ -19,7 +21,14 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters public class BarHitErrorMeter : HitErrorMeter { private const int judgement_line_width = 14; - private const int judgement_line_height = 4; + + [SettingSource("Judgement line thickness", "How thick the individual lines should be.")] + public BindableNumber JudgementLineThickness { get; } = new BindableNumber(4) + { + MinValue = 1, + MaxValue = 8, + Precision = 0.1f, + }; private SpriteIcon arrow; private SpriteIcon iconEarly; @@ -255,6 +264,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters judgementsContainer.Add(new JudgementLine { + JudgementLineThickness = { BindTarget = JudgementLineThickness }, Y = getRelativeJudgementPosition(judgement.TimeOffset), Colour = GetColourForHitResult(judgement.Type), }); @@ -268,11 +278,12 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters internal class JudgementLine : CompositeDrawable { + public readonly BindableNumber JudgementLineThickness = new BindableFloat(); + public JudgementLine() { RelativeSizeAxes = Axes.X; RelativePositionAxes = Axes.Y; - Height = judgement_line_height; Blending = BlendingParameters.Additive; @@ -295,6 +306,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Alpha = 0; Width = 0; + JudgementLineThickness.BindValueChanged(thickness => Height = thickness.NewValue, true); + this .FadeTo(0.6f, judgement_fade_in_duration, Easing.OutQuint) .ResizeWidthTo(1, judgement_fade_in_duration, Easing.OutQuint) From 331cb2aa800fe4f8330534da0bd59127abf56f6d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 16:54:09 +0900 Subject: [PATCH 030/131] Add setting to show or hide the moving average arrow --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 068a7f96cc..c12411be64 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -30,6 +30,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Precision = 0.1f, }; + [SettingSource("Show moving average arrow", "Whether an arrow should move beneath the bar showing the average error.")] + public Bindable ShowMovingAverage { get; } = new BindableBool(true); + private SpriteIcon arrow; private SpriteIcon iconEarly; private SpriteIcon iconLate; @@ -41,6 +44,12 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private double maxHitWindow; + private double floatingAverage; + private Container colourBars; + private Container arrowContainer; + + private const int max_concurrent_judgements = 50; + public BarHitErrorMeter() { AutoSizeAxes = Axes.Both; @@ -134,13 +143,16 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters }, } }, - new Container + arrowContainer = new Container { Name = "average chevron", Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + Origin = Anchor.CentreRight, Width = chevron_size, + X = chevron_size, RelativeSizeAxes = Axes.Y, + Alpha = 0, + Scale = new Vector2(0, 1), Child = arrow = new SpriteIcon { Anchor = Anchor.TopCentre, @@ -164,8 +176,15 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters colourBars.Height = 0; colourBars.ResizeHeightTo(1, 800, Easing.OutQuint); - arrow.Alpha = 0; - arrow.Delay(200).FadeInFromZero(600); + // delay the arrow appearance animation for only the initial appearance. + using (arrowContainer.BeginDelayedSequence(250)) + { + ShowMovingAverage.BindValueChanged(visible => + { + arrowContainer.FadeTo(visible.NewValue ? 1 : 0, 250, Easing.OutQuint); + arrowContainer.ScaleTo(visible.NewValue ? new Vector2(1) : new Vector2(0, 1), 250, Easing.OutQuint); + }, true); + } } protected override void Update() @@ -233,11 +252,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - private double floatingAverage; - private Container colourBars; - - private const int max_concurrent_judgements = 50; - protected override void OnNewJudgement(JudgementResult judgement) { const int arrow_move_duration = 800; From cdeab1b14e2b6130f63e3a363f0275363fc2f7a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 17:16:40 +0900 Subject: [PATCH 031/131] Add setting to change the style of the centre marker --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 100 ++++++++++++++---- 1 file changed, 79 insertions(+), 21 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index c12411be64..60b12476d1 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -33,6 +33,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [SettingSource("Show moving average arrow", "Whether an arrow should move beneath the bar showing the average error.")] public Bindable ShowMovingAverage { get; } = new BindableBool(true); + [SettingSource("Centre marker style", "How to signify the centre of the display")] + public Bindable CentreMarkerStyle { get; } = new Bindable(CentreMarker.Circle); + private SpriteIcon arrow; private SpriteIcon iconEarly; private SpriteIcon iconLate; @@ -48,8 +51,14 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private Container colourBars; private Container arrowContainer; + private (HitResult result, double length)[] hitWindows; + private const int max_concurrent_judgements = 50; + private Drawable[] centreMarkerDrawables; + + private const int centre_marker_size = 8; + public BarHitErrorMeter() { AutoSizeAxes = Axes.Both; @@ -58,13 +67,12 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [BackgroundDependencyLoader] private void load() { - const int centre_marker_size = 8; const int bar_height = 200; const int bar_width = 2; const float chevron_size = 8; const float icon_size = 14; - var hitWindows = HitWindows.GetAllAvailableWindows().ToArray(); + hitWindows = HitWindows.GetAllAvailableWindows().ToArray(); InternalChild = new Container { @@ -116,14 +124,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters RelativeSizeAxes = Axes.Y, Height = 0.5f, }, - new Circle - { - Name = "middle marker behind", - Colour = GetColourForHitResult(hitWindows.Last().result), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(centre_marker_size), - }, judgementsContainer = new Container { Name = "judgements", @@ -132,15 +132,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters RelativeSizeAxes = Axes.Y, Width = judgement_line_width, }, - new Circle - { - Name = "middle marker in front", - Colour = GetColourForHitResult(hitWindows.Last().result).Darken(0.3f), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(centre_marker_size), - Scale = new Vector2(0.5f), - }, } }, arrowContainer = new Container @@ -176,8 +167,10 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters colourBars.Height = 0; colourBars.ResizeHeightTo(1, 800, Easing.OutQuint); - // delay the arrow appearance animation for only the initial appearance. - using (arrowContainer.BeginDelayedSequence(250)) + CentreMarkerStyle.BindValueChanged(style => recreateCentreMarker(style.NewValue), true); + + // delay the appearance animations for only the initial appearance. + using (arrowContainer.BeginDelayedSequence(450)) { ShowMovingAverage.BindValueChanged(visible => { @@ -187,6 +180,65 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } + private void recreateCentreMarker(CentreMarker style) + { + if (centreMarkerDrawables != null) + { + foreach (var d in centreMarkerDrawables) + { + d.ScaleTo(0, 500, Easing.OutQuint) + .FadeOut(500, Easing.OutQuint); + + d.Expire(); + } + + centreMarkerDrawables = null; + } + + switch (style) + { + case CentreMarker.None: + break; + + case CentreMarker.Circle: + centreMarkerDrawables = new Drawable[] + { + new Circle + { + Name = "middle marker behind", + Colour = GetColourForHitResult(hitWindows.Last().result), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Depth = float.MaxValue, + Size = new Vector2(centre_marker_size), + }, + new Circle + { + Name = "middle marker in front", + Colour = GetColourForHitResult(hitWindows.Last().result).Darken(0.3f), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Depth = float.MinValue, + Size = new Vector2(centre_marker_size), + Scale = new Vector2(0.5f), + }, + }; + break; + } + + if (centreMarkerDrawables != null) + { + foreach (var d in centreMarkerDrawables) + { + colourBars.Add(d); + + Vector2 originalScale = d.Scale; + d.FadeInFromZero(500, Easing.OutQuint) + .ScaleTo(0).ScaleTo(originalScale, 1000, Easing.OutElasticHalf); + } + } + } + protected override void Update() { base.Update(); @@ -333,5 +385,11 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } public override void Clear() => judgementsContainer.Clear(); + + public enum CentreMarker + { + None, + Circle + } } } From 919583137e9bb2afd8514fbbbdcbe0cef043585d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 17:23:27 +0900 Subject: [PATCH 032/131] Add line style for centre marker --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 48 +++++++++++++++---- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 60b12476d1..3e583317e1 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters public Bindable ShowMovingAverage { get; } = new BindableBool(true); [SettingSource("Centre marker style", "How to signify the centre of the display")] - public Bindable CentreMarkerStyle { get; } = new Bindable(CentreMarker.Circle); + public Bindable CentreMarkerStyle { get; } = new Bindable(CentreMarkerStyles.Circle); private SpriteIcon arrow; private SpriteIcon iconEarly; @@ -180,7 +180,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - private void recreateCentreMarker(CentreMarker style) + private void recreateCentreMarker(CentreMarkerStyles style) { if (centreMarkerDrawables != null) { @@ -197,10 +197,10 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters switch (style) { - case CentreMarker.None: + case CentreMarkerStyles.None: break; - case CentreMarker.Circle: + case CentreMarkerStyles.Circle: centreMarkerDrawables = new Drawable[] { new Circle @@ -219,11 +219,39 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Anchor = Anchor.Centre, Origin = Anchor.Centre, Depth = float.MinValue, - Size = new Vector2(centre_marker_size), - Scale = new Vector2(0.5f), + Size = new Vector2(centre_marker_size / 2f), }, }; break; + + case CentreMarkerStyles.Line: + const float border_size = 1.5f; + + centreMarkerDrawables = new Drawable[] + { + new Box + { + Name = "middle marker behind", + Colour = GetColourForHitResult(hitWindows.Last().result), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Depth = float.MaxValue, + Size = new Vector2(judgement_line_width, centre_marker_size / 3f), + }, + new Box + { + Name = "middle marker in front", + Colour = GetColourForHitResult(hitWindows.Last().result).Darken(0.3f), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Depth = float.MinValue, + Size = new Vector2(judgement_line_width - border_size, centre_marker_size / 3f - border_size), + }, + }; + break; + + default: + throw new ArgumentOutOfRangeException(nameof(style), style, null); } if (centreMarkerDrawables != null) @@ -232,9 +260,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { colourBars.Add(d); - Vector2 originalScale = d.Scale; d.FadeInFromZero(500, Easing.OutQuint) - .ScaleTo(0).ScaleTo(originalScale, 1000, Easing.OutElasticHalf); + .ScaleTo(0).ScaleTo(1, 1000, Easing.OutElasticHalf); } } } @@ -386,10 +413,11 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters public override void Clear() => judgementsContainer.Clear(); - public enum CentreMarker + public enum CentreMarkerStyles { None, - Circle + Circle, + Line } } } From 7c9fe4036cbde6f330c96e5da9dc55af0424d9e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 17:46:22 +0900 Subject: [PATCH 033/131] Add setting to change the style of the early/late markers --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 112 ++++++++++++++---- 1 file changed, 91 insertions(+), 21 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 3e583317e1..02c2a36918 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -12,6 +12,8 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osuTK; @@ -36,9 +38,12 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [SettingSource("Centre marker style", "How to signify the centre of the display")] public Bindable CentreMarkerStyle { get; } = new Bindable(CentreMarkerStyles.Circle); + [SettingSource("Label style", "How to show early/late extremities")] + public Bindable LabelStyle { get; } = new Bindable(LabelStyles.Icons); + private SpriteIcon arrow; - private SpriteIcon iconEarly; - private SpriteIcon iconLate; + private Drawable labelEarly; + private Drawable labelLate; private Container colourBarsEarly; private Container colourBarsLate; @@ -70,7 +75,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters const int bar_height = 200; const int bar_width = 2; const float chevron_size = 8; - const float icon_size = 14; hitWindows = HitWindows.GetAllAvailableWindows().ToArray(); @@ -91,22 +95,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters RelativeSizeAxes = Axes.Y, Children = new Drawable[] { - iconEarly = new SpriteIcon - { - Y = -10, - Size = new Vector2(icon_size), - Icon = FontAwesome.Solid.ShippingFast, - Anchor = Anchor.TopCentre, - Origin = Anchor.Centre, - }, - iconLate = new SpriteIcon - { - Y = 10, - Size = new Vector2(icon_size), - Icon = FontAwesome.Solid.Bicycle, - Anchor = Anchor.BottomCentre, - Origin = Anchor.Centre, - }, colourBarsEarly = new Container { Anchor = Anchor.Centre, @@ -168,6 +156,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters colourBars.ResizeHeightTo(1, 800, Easing.OutQuint); CentreMarkerStyle.BindValueChanged(style => recreateCentreMarker(style.NewValue), true); + LabelStyle.BindValueChanged(style => recreateLabels(style.NewValue), true); // delay the appearance animations for only the initial appearance. using (arrowContainer.BeginDelayedSequence(450)) @@ -266,13 +255,87 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } + private void recreateLabels(LabelStyles style) + { + const float icon_size = 14; + + labelEarly?.Expire(); + labelEarly = null; + + labelLate?.Expire(); + labelLate = null; + + switch (style) + { + case LabelStyles.None: + break; + + case LabelStyles.Icons: + labelEarly = new SpriteIcon + { + Y = -10, + Size = new Vector2(icon_size), + Icon = FontAwesome.Solid.ShippingFast, + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + }; + + labelLate = new SpriteIcon + { + Y = 10, + Size = new Vector2(icon_size), + Icon = FontAwesome.Solid.Bicycle, + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + }; + + break; + + case LabelStyles.Text: + labelEarly = new OsuSpriteText + { + Y = -10, + Text = "Early", + Font = OsuFont.Default.With(size: 10), + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + }; + + labelLate = new OsuSpriteText + { + Y = 10, + Text = "Late", + Font = OsuFont.Default.With(size: 10), + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + }; + + break; + + default: + throw new ArgumentOutOfRangeException(nameof(style), style, null); + } + + if (labelEarly != null) + { + colourBars.Add(labelEarly); + labelEarly.FadeInFromZero(500); + } + + if (labelLate != null) + { + colourBars.Add(labelLate); + labelLate.FadeInFromZero(500); + } + } + protected override void Update() { base.Update(); // undo any layout rotation to display icons in the correct orientation - iconEarly.Rotation = -Rotation; - iconLate.Rotation = -Rotation; + if (labelEarly != null) labelEarly.Rotation = -Rotation; + if (labelLate != null) labelLate.Rotation = -Rotation; } private void createColourBars((HitResult result, double length)[] windows) @@ -419,5 +482,12 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Circle, Line } + + public enum LabelStyles + { + None, + Icons, + Text + } } } From 341201ae55549c2ec4c107b259cc1193e1bf8642 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Mar 2022 12:09:03 +0300 Subject: [PATCH 034/131] Add "bug report" issue form template --- .github/ISSUE_TEMPLATE/bug-issue.yml | 76 ++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-issue.yml diff --git a/.github/ISSUE_TEMPLATE/bug-issue.yml b/.github/ISSUE_TEMPLATE/bug-issue.yml new file mode 100644 index 0000000000..428b749af1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-issue.yml @@ -0,0 +1,76 @@ +name: Bug report +description: Encountered a clear bug or crash with logs backing it? Fill it up! +body: + - type: markdown + attributes: + value: | + # osu! bug report + + Important to note that your issue may have already been reported before. Please check: + - Pinned issues, at the top of https://github.com/ppy/osu/issues. + - Current open `priority:0` issues, filterable [here](https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Apriority%3A0). + + And also search for your issue. If you find that it already exists, respond with a reaction or add any further information that may be helpful. + + - type: dropdown + attributes: + label: Type + description: | + - Game behaviour bug: game gets into an unexpected state (e.g. incorrect scoring, wrong multiplayer room state, etc.). + - Cosmetic bug: something looks wrong (e.g. misaligned component, text not wrapping, etc.) + options: + - Crash to desktop + - Game behaviour bug + - Performance bug + - Cosmetic bug + - Other + validations: + required: true + - type: textarea + attributes: + label: Bug description + description: What are the steps for reproducing the bug? Any additional details that might be of help? + validations: + required: true + - type: textarea + attributes: + label: Screenshots or videos + description: May also help in reproducing the encountered bug, in addition to descriptions. + placeholder: You can attach by dragging and dropping the screenshots/videos into this box. + validations: + required: false + - type: input + attributes: + label: Version + description: The version of osu!(lazer) you encountered this bug on. + validations: + required: true + - type: markdown + attributes: + value: | + ## Logs attachments + + Logs are necessary to further investigate this bug. They are reset every new game session, so you need to ensure the logs are preserved by not starting/restarting osu! after encountering the bug. + + In the case this isn't a "Crash to Desktop" report, to retrieve logs: + 1. Head on to game settings and click on "Open osu! folder" + 2. Then open the `logs` folder located there + + Otherwise, logs can *only* be retrieved via file explorer, as running the game will reset them. + + Logs are, by default, located at: + - `%AppData%/osu/logs` *(on Windows),* + - `~/.local/share/osu/logs` *(on Linux & macOS).* + - `Android/data/sh.ppy.osulazer/files/logs` *(on Android)*, + - on iOS they can be obtained by connecting your device to your desktop and copying the `logs` directory from the app's own document storage using iTunes. (https://support.apple.com/en-us/HT201301#copy-to-computer) + + If you have relocated your game folder, head into that location and open the `logs` folder. + + Finally, select all log files and attach them in the "Logs" box below. + + - type: textarea + attributes: + label: Logs + placeholder: You can attach by dragging and dropping the log files into this box. + validations: + required: true From 105245a53aaa7a65bab884fd1a43073bf6f545e7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Mar 2022 12:41:34 +0300 Subject: [PATCH 035/131] Apply minor rewording suggestions Co-authored-by: Dean Herbert --- .github/ISSUE_TEMPLATE/bug-issue.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-issue.yml b/.github/ISSUE_TEMPLATE/bug-issue.yml index 428b749af1..3bd6767535 100644 --- a/.github/ISSUE_TEMPLATE/bug-issue.yml +++ b/.github/ISSUE_TEMPLATE/bug-issue.yml @@ -1,5 +1,5 @@ name: Bug report -description: Encountered a clear bug or crash with logs backing it? Fill it up! +description: Report a very clearly broken issue. body: - type: markdown attributes: @@ -20,9 +20,9 @@ body: - Cosmetic bug: something looks wrong (e.g. misaligned component, text not wrapping, etc.) options: - Crash to desktop - - Game behaviour bug - - Performance bug - - Cosmetic bug + - Game behaviour + - Performance + - Cosmetic - Other validations: required: true @@ -35,14 +35,14 @@ body: - type: textarea attributes: label: Screenshots or videos - description: May also help in reproducing the encountered bug, in addition to descriptions. + description: Share any kind of visuals you can which show the bug or issue taking place. placeholder: You can attach by dragging and dropping the screenshots/videos into this box. validations: required: false - type: input attributes: label: Version - description: The version of osu!(lazer) you encountered this bug on. + description: The version you encountered this bug on. This is shown at the bottom of the main menu and also at the end of the settings screen. validations: required: true - type: markdown @@ -66,7 +66,7 @@ body: If you have relocated your game folder, head into that location and open the `logs` folder. - Finally, select all log files and attach them in the "Logs" box below. + Finally, select all log files and drag them into the "Logs" box below. - type: textarea attributes: From 32faa05b8707ecd22d4db4bc1ebb4e8536c13b96 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Mar 2022 12:47:33 +0300 Subject: [PATCH 036/131] Include searching step as part of the bullets --- .github/ISSUE_TEMPLATE/bug-issue.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-issue.yml b/.github/ISSUE_TEMPLATE/bug-issue.yml index 3bd6767535..5af9a3d6da 100644 --- a/.github/ISSUE_TEMPLATE/bug-issue.yml +++ b/.github/ISSUE_TEMPLATE/bug-issue.yml @@ -9,8 +9,7 @@ body: Important to note that your issue may have already been reported before. Please check: - Pinned issues, at the top of https://github.com/ppy/osu/issues. - Current open `priority:0` issues, filterable [here](https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Apriority%3A0). - - And also search for your issue. If you find that it already exists, respond with a reaction or add any further information that may be helpful. + - And most importantly, search for your issue. If you find that it already exists, respond with a reaction or add any further information that may be helpful. - type: dropdown attributes: From 4b0649743a5b103f91936530caa9dc0c882d7664 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Mar 2022 12:47:40 +0300 Subject: [PATCH 037/131] Remove unnecessary description --- .github/ISSUE_TEMPLATE/bug-issue.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-issue.yml b/.github/ISSUE_TEMPLATE/bug-issue.yml index 5af9a3d6da..542d0dccaf 100644 --- a/.github/ISSUE_TEMPLATE/bug-issue.yml +++ b/.github/ISSUE_TEMPLATE/bug-issue.yml @@ -14,9 +14,6 @@ body: - type: dropdown attributes: label: Type - description: | - - Game behaviour bug: game gets into an unexpected state (e.g. incorrect scoring, wrong multiplayer room state, etc.). - - Cosmetic bug: something looks wrong (e.g. misaligned component, text not wrapping, etc.) options: - Crash to desktop - Game behaviour From c97aa3a26f5c3edbc4c62e05c98d9027a00afb06 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 18 Mar 2022 18:57:34 +0900 Subject: [PATCH 038/131] Fix intermittent ready button test failure --- .../Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs index f34f7c6c91..dd13d2b6ef 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerReadyButton.cs @@ -148,7 +148,7 @@ namespace osu.Game.Tests.Visual.Multiplayer ClickButtonWhenEnabled(); AddUntilStep("user is idle (match not started)", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Idle); - AddAssert("ready button enabled", () => button.ChildrenOfType().Single().Enabled.Value); + AddUntilStep("ready button enabled", () => button.ChildrenOfType().Single().Enabled.Value); } [TestCase(true)] From 9215384229df6813f1decbe20f398da92ceeb588 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Mar 2022 12:59:51 +0300 Subject: [PATCH 039/131] Display beatmap maximum combo in score panel --- .../Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs | 2 +- .../Screens/Ranking/Expanded/Statistics/ComboStatistic.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 7e39708e65..f43cbc11e2 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -68,7 +68,7 @@ namespace osu.Game.Screens.Ranking.Expanded var topStatistics = new List { new AccuracyStatistic(score.Accuracy), - new ComboStatistic(score.MaxCombo, !score.Statistics.TryGetValue(HitResult.Miss, out int missCount) || missCount == 0), + new ComboStatistic(score.MaxCombo, beatmap.MaxCombo, !score.Statistics.TryGetValue(HitResult.Miss, out int missCount) || missCount == 0), new PerformanceStatistic(score), }; diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs index b92c244174..67d580270d 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs @@ -25,9 +25,10 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics /// Creates a new . /// /// The combo to be displayed. + /// The maximum value of . /// Whether this is a perfect combo. - public ComboStatistic(int combo, bool isPerfect) - : base("combo", combo) + public ComboStatistic(int combo, int? maxCombo, bool isPerfect) + : base("combo", combo, maxCombo) { this.isPerfect = isPerfect; } From af22e67e15af4da1e6730e88cff1f48622582bfd Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Mar 2022 13:00:30 +0300 Subject: [PATCH 040/131] Fix perfect combo check not accounting for `LargeTickMiss` `LargeTickMiss` can affect combo, see https://github.com/ppy/osu/blob/a352a140bc145f342fadc300797a2b05ade3f920/osu.Game/Rulesets/Scoring/HitResult.cs#L124-L144. --- .../Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index f43cbc11e2..fb8a1beb04 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -65,10 +65,14 @@ namespace osu.Game.Screens.Ranking.Expanded var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata; string creator = metadata.Author.Username; + bool isPerfect = true; + isPerfect &= !score.Statistics.TryGetValue(HitResult.Miss, out int missCount) || missCount == 0; + isPerfect &= !score.Statistics.TryGetValue(HitResult.LargeTickMiss, out int largeTickMissCount) || largeTickMissCount == 0; + var topStatistics = new List { new AccuracyStatistic(score.Accuracy), - new ComboStatistic(score.MaxCombo, beatmap.MaxCombo, !score.Statistics.TryGetValue(HitResult.Miss, out int missCount) || missCount == 0), + new ComboStatistic(score.MaxCombo, beatmap.MaxCombo, isPerfect), new PerformanceStatistic(score), }; From 2cb1974a5824b59528986d9ffa5d8392217f1a18 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Mar 2022 13:02:25 +0300 Subject: [PATCH 041/131] Add max combo to test beatmap info --- osu.Game.Tests/Resources/TestResources.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs index 81b624f908..00bb02a937 100644 --- a/osu.Game.Tests/Resources/TestResources.cs +++ b/osu.Game.Tests/Resources/TestResources.cs @@ -133,6 +133,7 @@ namespace osu.Game.Tests.Resources StarRating = diff, Length = length, BPM = bpm, + MaxCombo = 1000, Hash = Guid.NewGuid().ToString().ComputeMD5Hash(), Ruleset = rulesetInfo, Metadata = metadata, From bd488d139d1f8431ed5c1541c159f0090590962d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 20:11:05 +0900 Subject: [PATCH 042/131] Better centre text labels for hit error meter --- osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 02c2a36918..e3a8b6cae6 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -294,6 +294,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters case LabelStyles.Text: labelEarly = new OsuSpriteText { + X = -1, Y = -10, Text = "Early", Font = OsuFont.Default.With(size: 10), @@ -303,6 +304,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters labelLate = new OsuSpriteText { + X = -1, Y = 10, Text = "Late", Font = OsuFont.Default.With(size: 10), From 806a16d8f6a841d3a7bf97a62b63def44a19447a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 20:13:15 +0900 Subject: [PATCH 043/131] Fix `SkinComponentToolbox` attempting to create instances of abstract classes --- osu.Game/Skinning/Editor/SkinComponentToolbox.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs index a586cdcd54..756f229927 100644 --- a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs +++ b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs @@ -51,7 +51,7 @@ namespace osu.Game.Skinning.Editor fill.Clear(); var skinnableTypes = typeof(OsuGame).Assembly.GetTypes() - .Where(t => !t.IsInterface) + .Where(t => !t.IsInterface && !t.IsAbstract) .Where(t => typeof(ISkinnableDrawable).IsAssignableFrom(t)) .OrderBy(t => t.Name) .ToArray(); From ed90dc6d6bba910f908ad23dca8fd5cfa227b3f6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Mar 2022 20:17:04 +0900 Subject: [PATCH 044/131] Fix centering of labels using `Height` instead of location to better handle rotations --- osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index e3a8b6cae6..dca50c07ad 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -294,20 +294,20 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters case LabelStyles.Text: labelEarly = new OsuSpriteText { - X = -1, Y = -10, Text = "Early", Font = OsuFont.Default.With(size: 10), + Height = 12, Anchor = Anchor.TopCentre, Origin = Anchor.Centre, }; labelLate = new OsuSpriteText { - X = -1, Y = 10, Text = "Late", Font = OsuFont.Default.With(size: 10), + Height = 12, Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, }; From fc576b1369c74457c1e673000fb44f4acc7291ba Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Mar 2022 15:22:00 +0300 Subject: [PATCH 045/131] Separate increase/break combo helper methods from `AffectsCombo` --- osu.Game/Rulesets/Scoring/HitResult.cs | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/HitResult.cs b/osu.Game/Rulesets/Scoring/HitResult.cs index 514232db69..decd04967f 100644 --- a/osu.Game/Rulesets/Scoring/HitResult.cs +++ b/osu.Game/Rulesets/Scoring/HitResult.cs @@ -122,19 +122,33 @@ namespace osu.Game.Rulesets.Scoring public static class HitResultExtensions { /// - /// Whether a increases/decreases the combo, and affects the combo portion of the score. + /// Whether a increases the combo. /// - public static bool AffectsCombo(this HitResult result) + public static bool IncreasesCombo(this HitResult result) { switch (result) { - case HitResult.Miss: case HitResult.Meh: case HitResult.Ok: case HitResult.Good: case HitResult.Great: case HitResult.Perfect: case HitResult.LargeTickHit: + return true; + + default: + return false; + } + } + + /// + /// Whether a breaks the combo and resets it back to zero. + /// + public static bool BreaksCombo(this HitResult result) + { + switch (result) + { + case HitResult.Miss: case HitResult.LargeTickMiss: return true; @@ -143,6 +157,12 @@ namespace osu.Game.Rulesets.Scoring } } + /// + /// Whether a increases/breaks the combo, and affects the combo portion of the score. + /// + public static bool AffectsCombo(this HitResult result) + => IncreasesCombo(result) || BreaksCombo(result); + /// /// Whether a affects the accuracy portion of the score. /// From 5ec2d86c094e26f1c2663047ba895c47271b9d6c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Mar 2022 15:22:53 +0300 Subject: [PATCH 046/131] Update `ScoreProcessor` to use new defined helper methods --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 0c585fac98..1e268bb2eb 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -166,20 +166,10 @@ namespace osu.Game.Rulesets.Scoring if (!result.Type.IsScorable()) return; - if (result.Type.AffectsCombo()) - { - switch (result.Type) - { - case HitResult.Miss: - case HitResult.LargeTickMiss: - Combo.Value = 0; - break; - - default: - Combo.Value++; - break; - } - } + if (result.Type.IncreasesCombo()) + Combo.Value++; + else if (result.Type.BreaksCombo()) + Combo.Value = 0; double scoreIncrease = result.Type.IsHit() ? result.Judgement.NumericResultFor(result) : 0; From fa8eb1feec1cf57e8965a12684b4170c6c60ca9a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Mar 2022 15:23:14 +0300 Subject: [PATCH 047/131] Update score panel to check for all combo-breaking statistics --- .../Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index fb8a1beb04..1b1aa3a684 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -65,14 +65,10 @@ namespace osu.Game.Screens.Ranking.Expanded var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata; string creator = metadata.Author.Username; - bool isPerfect = true; - isPerfect &= !score.Statistics.TryGetValue(HitResult.Miss, out int missCount) || missCount == 0; - isPerfect &= !score.Statistics.TryGetValue(HitResult.LargeTickMiss, out int largeTickMissCount) || largeTickMissCount == 0; - var topStatistics = new List { new AccuracyStatistic(score.Accuracy), - new ComboStatistic(score.MaxCombo, beatmap.MaxCombo, isPerfect), + new ComboStatistic(score.MaxCombo, beatmap.MaxCombo, score.Statistics.All(stat => !stat.Key.BreaksCombo() || stat.Value == 0)), new PerformanceStatistic(score), }; From 8078a8c1f8b21709d3741e9dcb83636fecb295a9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Mar 2022 17:18:42 +0300 Subject: [PATCH 048/131] Simplify `IncreasesCombo`/`BreaksCombo` helper method implementation --- osu.Game/Rulesets/Scoring/HitResult.cs | 34 ++++++++++---------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/HitResult.cs b/osu.Game/Rulesets/Scoring/HitResult.cs index decd04967f..9f03c381ee 100644 --- a/osu.Game/Rulesets/Scoring/HitResult.cs +++ b/osu.Game/Rulesets/Scoring/HitResult.cs @@ -125,30 +125,28 @@ namespace osu.Game.Rulesets.Scoring /// Whether a increases the combo. /// public static bool IncreasesCombo(this HitResult result) + => AffectsCombo(result) && IsHit(result); + + /// + /// Whether a breaks the combo and resets it back to zero. + /// + public static bool BreaksCombo(this HitResult result) + => AffectsCombo(result) && !IsHit(result); + + /// + /// Whether a increases/breaks the combo, and affects the combo portion of the score. + /// + public static bool AffectsCombo(this HitResult result) { switch (result) { + case HitResult.Miss: case HitResult.Meh: case HitResult.Ok: case HitResult.Good: case HitResult.Great: case HitResult.Perfect: case HitResult.LargeTickHit: - return true; - - default: - return false; - } - } - - /// - /// Whether a breaks the combo and resets it back to zero. - /// - public static bool BreaksCombo(this HitResult result) - { - switch (result) - { - case HitResult.Miss: case HitResult.LargeTickMiss: return true; @@ -157,12 +155,6 @@ namespace osu.Game.Rulesets.Scoring } } - /// - /// Whether a increases/breaks the combo, and affects the combo portion of the score. - /// - public static bool AffectsCombo(this HitResult result) - => IncreasesCombo(result) || BreaksCombo(result); - /// /// Whether a affects the accuracy portion of the score. /// From faa36c78e5c2c0fc80bd25ba12c82f1213fefeb2 Mon Sep 17 00:00:00 2001 From: hwabis Date: Fri, 18 Mar 2022 12:55:00 -0400 Subject: [PATCH 049/131] put count and tabs into new fillflowcontainer --- .../Match/Playlist/MultiplayerPlaylist.cs | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs index edd6cf93e9..2b59452ff1 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs @@ -12,6 +12,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; +using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist { @@ -34,23 +35,38 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist private OsuSpriteText queueListCount; [BackgroundDependencyLoader] - private void load() + private void load(OsuColour osuColour) { const float tab_control_height = 25; InternalChildren = new Drawable[] { - new OsuTabControl + new FillFlowContainer { - RelativeSizeAxes = Axes.X, - Height = tab_control_height, - Current = { BindTarget = DisplayMode } - }, - queueListCount = new OsuSpriteText - { - Font = OsuFont.Default.With(weight: FontWeight.Bold), Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, + Direction = FillDirection.Horizontal, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(OsuTabControl.HORIZONTAL_SPACING, 0), + Children = new Drawable[] + { + queueListCount = new OsuSpriteText + { + Font = OsuFont.Default.With(weight: FontWeight.Bold), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Colour = osuColour.Yellow, + }, + new OsuTabControl + { + RelativeSizeAxes = Axes.X, + Height = tab_control_height, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Current = { BindTarget = DisplayMode }, + }, + } }, new Container { From b4a8defe1a1efce18553c2d469438be0ec15b8d8 Mon Sep 17 00:00:00 2001 From: Noah M Date: Fri, 18 Mar 2022 14:12:36 -0500 Subject: [PATCH 050/131] Make Relax and Aim assist mods incompatible --- osu.Game.Rulesets.Osu/Mods/OsuModAimAssist.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAimAssist.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAimAssist.cs index ed4b139e00..1abbd67d8f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAimAssist.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAimAssist.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override ModType Type => ModType.Fun; public override string Description => "No need to chase the circle – the circle chases you!"; public override double ScoreMultiplier => 1; - public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay) }; + public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModRelax) }; private IFrameStableClock gameplayClock; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 1bf63ef6d4..09a33e1ed9 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Mods public class OsuModRelax : ModRelax, IUpdatableByPlayfield, IApplicableToDrawableRuleset, IApplicableToPlayer { public override string Description => @"You don't need to click. Give your clicking/tapping fingers a break from the heat of things."; - public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).ToArray(); + public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).Append(typeof(OsuModAimAssist)).ToArray(); /// /// How early before a hitobject's start time to trigger a hit. From 78869c462a8be7606f5d42ce1f978f120d5d5f19 Mon Sep 17 00:00:00 2001 From: Noah M <10090332+Sublimelime@users.noreply.github.com> Date: Fri, 18 Mar 2022 14:24:36 -0500 Subject: [PATCH 051/131] Use `.Concat()` instead of chained Append MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 09a33e1ed9..9719de441e 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Mods public class OsuModRelax : ModRelax, IUpdatableByPlayfield, IApplicableToDrawableRuleset, IApplicableToPlayer { public override string Description => @"You don't need to click. Give your clicking/tapping fingers a break from the heat of things."; - public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).Append(typeof(OsuModAimAssist)).ToArray(); + public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot), typeof(OsuModAimAssist) }).ToArray(); /// /// How early before a hitobject's start time to trigger a hit. From c07a906b224d5921800e0c5d1fe54cdfa5986945 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 19 Mar 2022 02:27:40 +0300 Subject: [PATCH 052/131] Rewrite log attachment section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- .github/ISSUE_TEMPLATE/bug-issue.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-issue.yml b/.github/ISSUE_TEMPLATE/bug-issue.yml index 542d0dccaf..84b77fc298 100644 --- a/.github/ISSUE_TEMPLATE/bug-issue.yml +++ b/.github/ISSUE_TEMPLATE/bug-issue.yml @@ -44,25 +44,25 @@ body: - type: markdown attributes: value: | - ## Logs attachments + ## Logs - Logs are necessary to further investigate this bug. They are reset every new game session, so you need to ensure the logs are preserved by not starting/restarting osu! after encountering the bug. + Attaching log files is required for every reported bug. Instructions how to find the log files are listed below. - In the case this isn't a "Crash to Desktop" report, to retrieve logs: + If the game has not yet been closed since you found the bug: 1. Head on to game settings and click on "Open osu! folder" 2. Then open the `logs` folder located there - Otherwise, logs can *only* be retrieved via file explorer, as running the game will reset them. + If the game crashed or has been closed since you found the bug, **do not** restart the game to retrieve the logs as they will reset. You must find them using the file explorer. - Logs are, by default, located at: + By default logs can be found in: - `%AppData%/osu/logs` *(on Windows),* - `~/.local/share/osu/logs` *(on Linux & macOS).* - `Android/data/sh.ppy.osulazer/files/logs` *(on Android)*, - on iOS they can be obtained by connecting your device to your desktop and copying the `logs` directory from the app's own document storage using iTunes. (https://support.apple.com/en-us/HT201301#copy-to-computer) - If you have relocated your game folder, head into that location and open the `logs` folder. + However, if you have selected a custom location for the game files via settings, you must find that custom folder and open the `logs` folder there. - Finally, select all log files and drag them into the "Logs" box below. + After locating the `logs` folder, select all log files inside and drag them into the "Logs" box below. - type: textarea attributes: From d9b2a29c6d6d90fc568afff257652779f1e401e1 Mon Sep 17 00:00:00 2001 From: hwabis Date: Fri, 18 Mar 2022 20:02:26 -0400 Subject: [PATCH 053/131] (not working yet) add MultiplayerPlaylistTabControl, "Queue ({count})" --- .../Match/Playlist/MultiplayerPlaylist.cs | 36 ++++--------------- .../Playlist/MultiplayerPlaylistTabControl.cs | 34 ++++++++++++++++++ 2 files changed, 40 insertions(+), 30 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs index 2b59452ff1..c65ff1bd00 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs @@ -8,11 +8,8 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; -using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist { @@ -32,41 +29,20 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist private MultiplayerHistoryList historyList; private bool firstPopulation = true; - private OsuSpriteText queueListCount; + private MultiplayerPlaylistTabControl playlistTabControl; [BackgroundDependencyLoader] - private void load(OsuColour osuColour) + private void load() { const float tab_control_height = 25; InternalChildren = new Drawable[] { - new FillFlowContainer + playlistTabControl = new MultiplayerPlaylistTabControl { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Direction = FillDirection.Horizontal, RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(OsuTabControl.HORIZONTAL_SPACING, 0), - Children = new Drawable[] - { - queueListCount = new OsuSpriteText - { - Font = OsuFont.Default.With(weight: FontWeight.Bold), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Colour = osuColour.Yellow, - }, - new OsuTabControl - { - RelativeSizeAxes = Axes.X, - Height = tab_control_height, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Current = { BindTarget = DisplayMode }, - }, - } + Height = tab_control_height, + Current = { BindTarget = DisplayMode }, }, new Container { @@ -97,7 +73,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist base.LoadComplete(); DisplayMode.BindValueChanged(onDisplayModeChanged, true); queueList.Items.BindCollectionChanged( - (_, __) => queueListCount.Text = queueList.Items.Count.ToString(), true); + (_, __) => playlistTabControl.queueListCount = queueList.Items.Count, true); } private void onDisplayModeChanged(ValueChangedEvent mode) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs new file mode 100644 index 0000000000..f6a5bfed41 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs @@ -0,0 +1,34 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist +{ + public class MultiplayerPlaylistTabControl : OsuTabControl + { + public int queueListCount; + + public MultiplayerPlaylistTabControl() + { + queueListCount = 0; + } + + protected override TabItem CreateTabItem(MultiplayerPlaylistDisplayMode value) + { + if (value == MultiplayerPlaylistDisplayMode.Queue) + return new QueueTabItem(value, queueListCount); + return new OsuTabItem(value); + } + + private class QueueTabItem : OsuTabItem + { + public QueueTabItem(MultiplayerPlaylistDisplayMode value, int count) + : base(value) + { + Text.Text += " (" + count + ")"; + } + } + } +} From 7bb8cd5411a06b8483552bea7eba617486b2c14e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 19 Mar 2022 03:22:57 +0300 Subject: [PATCH 054/131] Apply second pass rewordings on logs section Co-authored-by: Walavouchey <36758269+Walavouchey@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/bug-issue.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-issue.yml b/.github/ISSUE_TEMPLATE/bug-issue.yml index 84b77fc298..95c7a089c8 100644 --- a/.github/ISSUE_TEMPLATE/bug-issue.yml +++ b/.github/ISSUE_TEMPLATE/bug-issue.yml @@ -46,21 +46,21 @@ body: value: | ## Logs - Attaching log files is required for every reported bug. Instructions how to find the log files are listed below. + Attaching log files is required for every reported bug. See instructions below on how to find them. If the game has not yet been closed since you found the bug: 1. Head on to game settings and click on "Open osu! folder" 2. Then open the `logs` folder located there - If the game crashed or has been closed since you found the bug, **do not** restart the game to retrieve the logs as they will reset. You must find them using the file explorer. + **Logs are reset when you reopen the game.** If the game crashed or has been closed since you found the bug, retrieve the logs using the file explorer instead. By default logs can be found in: - - `%AppData%/osu/logs` *(on Windows),* - - `~/.local/share/osu/logs` *(on Linux & macOS).* - - `Android/data/sh.ppy.osulazer/files/logs` *(on Android)*, + - `%AppData%/osu/logs` *(on Windows)* + - `~/.local/share/osu/logs` *(on Linux & macOS)* + - `Android/data/sh.ppy.osulazer/files/logs` *(on Android)* - on iOS they can be obtained by connecting your device to your desktop and copying the `logs` directory from the app's own document storage using iTunes. (https://support.apple.com/en-us/HT201301#copy-to-computer) - However, if you have selected a custom location for the game files via settings, you must find that custom folder and open the `logs` folder there. + If you have selected a custom location for the game files, you can find the `logs` folder there. After locating the `logs` folder, select all log files inside and drag them into the "Logs" box below. From 5e5fbc496ed25fd66029305c1665e0d23bb59759 Mon Sep 17 00:00:00 2001 From: hwabis Date: Fri, 18 Mar 2022 20:32:37 -0400 Subject: [PATCH 055/131] (still not working) try bindables instead of int --- .../Match/Playlist/MultiplayerPlaylist.cs | 2 +- .../Match/Playlist/MultiplayerPlaylistTabControl.cs | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs index c65ff1bd00..a1feda9000 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs @@ -73,7 +73,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist base.LoadComplete(); DisplayMode.BindValueChanged(onDisplayModeChanged, true); queueList.Items.BindCollectionChanged( - (_, __) => playlistTabControl.queueListCount = queueList.Items.Count, true); + (_, __) => playlistTabControl.queueListCount.Value = queueList.Items.Count, true); } private void onDisplayModeChanged(ValueChangedEvent mode) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs index f6a5bfed41..a459ec6f80 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Bindables; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; @@ -8,11 +9,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist { public class MultiplayerPlaylistTabControl : OsuTabControl { - public int queueListCount; + public Bindable queueListCount = new Bindable(0); public MultiplayerPlaylistTabControl() { - queueListCount = 0; } protected override TabItem CreateTabItem(MultiplayerPlaylistDisplayMode value) @@ -24,10 +24,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist private class QueueTabItem : OsuTabItem { - public QueueTabItem(MultiplayerPlaylistDisplayMode value, int count) + private Bindable count; + + public QueueTabItem(MultiplayerPlaylistDisplayMode value, Bindable queueListCount) : base(value) { - Text.Text += " (" + count + ")"; + count = new Bindable(); + count.BindTo(queueListCount); + Text.Text += " (" + count.Value + ")"; } } } From 744cd6164379e2498704d56808408b09dac2d915 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 19 Mar 2022 03:33:13 +0300 Subject: [PATCH 056/131] Apply further minor rewordings Co-authored-by: Walavouchey <36758269+Walavouchey@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/bug-issue.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-issue.yml b/.github/ISSUE_TEMPLATE/bug-issue.yml index 95c7a089c8..882b0bf6bf 100644 --- a/.github/ISSUE_TEMPLATE/bug-issue.yml +++ b/.github/ISSUE_TEMPLATE/bug-issue.yml @@ -54,11 +54,11 @@ body: **Logs are reset when you reopen the game.** If the game crashed or has been closed since you found the bug, retrieve the logs using the file explorer instead. - By default logs can be found in: - - `%AppData%/osu/logs` *(on Windows)* - - `~/.local/share/osu/logs` *(on Linux & macOS)* - - `Android/data/sh.ppy.osulazer/files/logs` *(on Android)* - - on iOS they can be obtained by connecting your device to your desktop and copying the `logs` directory from the app's own document storage using iTunes. (https://support.apple.com/en-us/HT201301#copy-to-computer) + The default places to find the logs are as follows: + - `%AppData%/osu/logs` *on Windows* + - `~/.local/share/osu/logs` *on Linux & macOS* + - `Android/data/sh.ppy.osulazer/files/logs` *on Android* + - *On iOS*, they can be obtained by connecting your device to your desktop and copying the `logs` directory from the app's own document storage using iTunes. (https://support.apple.com/en-us/HT201301#copy-to-computer) If you have selected a custom location for the game files, you can find the `logs` folder there. From 5a5629eb5a50b6d5d4987167ff564403d49835eb Mon Sep 17 00:00:00 2001 From: hwabis Date: Fri, 18 Mar 2022 20:47:45 -0400 Subject: [PATCH 057/131] (works now) use BindValueChanged to set the Queue text --- .../Match/Playlist/MultiplayerPlaylistTabControl.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs index a459ec6f80..f0a51eb5e1 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs @@ -24,14 +24,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist private class QueueTabItem : OsuTabItem { - private Bindable count; - public QueueTabItem(MultiplayerPlaylistDisplayMode value, Bindable queueListCount) : base(value) { - count = new Bindable(); - count.BindTo(queueListCount); - Text.Text += " (" + count.Value + ")"; + queueListCount.BindValueChanged( + _ => Text.Text = "Queue (" + queueListCount.Value + ")", true); } } } From 5bcb7c167c5ae837be46f56752dd41c1236cec0b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 19 Mar 2022 05:02:20 +0300 Subject: [PATCH 058/131] Swap placements of "hold for menu" and key counter --- osu.Game/Screens/Play/HUDOverlay.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 628452fbc8..9edcbf3e07 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -111,8 +111,11 @@ namespace osu.Game.Screens.Play Direction = FillDirection.Vertical, Children = new Drawable[] { - KeyCounter = CreateKeyCounter(), HoldToQuit = CreateHoldForMenuButton(), + KeyCounter = CreateKeyCounter().With(k => + { + k.Margin = new MarginPadding { Horizontal = 10 }; + }), } } }; @@ -235,13 +238,11 @@ namespace osu.Game.Screens.Play { PlayerSettingsOverlay.Show(); ModDisplay.FadeIn(200); - KeyCounter.Margin = new MarginPadding(10) { Bottom = 30 }; } else { PlayerSettingsOverlay.Hide(); ModDisplay.Delay(2000).FadeOut(200); - KeyCounter.Margin = new MarginPadding(10); } updateVisibility(); From 486be831778a6b57fdb210bfe9ce646b51c0c3b8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 19 Mar 2022 05:04:11 +0300 Subject: [PATCH 059/131] Calculate position adjustment distance in local parent space --- osu.Game/Screens/Play/HUD/HoldForMenuButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 4087011933..065ed0dd5f 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -84,7 +84,7 @@ namespace osu.Game.Screens.Play.HUD protected override bool OnMouseMove(MouseMoveEvent e) { - positionalAdjust = Vector2.Distance(e.ScreenSpaceMousePosition, button.ScreenSpaceDrawQuad.Centre) / 200; + positionalAdjust = Vector2.Distance(e.MousePosition, button.ToSpaceOfOtherDrawable(button.DrawRectangle.Centre, Parent)) / 200; return base.OnMouseMove(e); } From ad9b119e3dd85d4207c477da59ef45366936fde9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 19 Mar 2022 05:04:54 +0300 Subject: [PATCH 060/131] Reduce "hold for menu" radius of visibility --- osu.Game/Screens/Play/HUD/HoldForMenuButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 065ed0dd5f..3da63ec2cc 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -84,7 +84,7 @@ namespace osu.Game.Screens.Play.HUD protected override bool OnMouseMove(MouseMoveEvent e) { - positionalAdjust = Vector2.Distance(e.MousePosition, button.ToSpaceOfOtherDrawable(button.DrawRectangle.Centre, Parent)) / 200; + positionalAdjust = Vector2.Distance(e.MousePosition, button.ToSpaceOfOtherDrawable(button.DrawRectangle.Centre, Parent)) / 100; return base.OnMouseMove(e); } From 5d16519a822db2eda9d8759b0a27046bbe77e891 Mon Sep 17 00:00:00 2001 From: hwabis Date: Fri, 18 Mar 2022 23:41:55 -0400 Subject: [PATCH 061/131] make code prettier --- .../Multiplayer/Match/Playlist/MultiplayerPlaylist.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs index a1feda9000..3269257260 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs @@ -7,7 +7,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; @@ -25,12 +24,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist /// public Action RequestEdit; + private MultiplayerPlaylistTabControl playlistTabControl; private MultiplayerQueueList queueList; private MultiplayerHistoryList historyList; private bool firstPopulation = true; - private MultiplayerPlaylistTabControl playlistTabControl; - [BackgroundDependencyLoader] private void load() { @@ -42,7 +40,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist { RelativeSizeAxes = Axes.X, Height = tab_control_height, - Current = { BindTarget = DisplayMode }, + Current = { BindTarget = DisplayMode } }, new Container { From 79f6e7cc1ce8723c26e30c5acb475d02b2befbad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 19 Mar 2022 12:42:25 +0900 Subject: [PATCH 062/131] Simplify wording of description hint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- .github/ISSUE_TEMPLATE/bug-issue.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug-issue.yml b/.github/ISSUE_TEMPLATE/bug-issue.yml index 882b0bf6bf..0174a0d47f 100644 --- a/.github/ISSUE_TEMPLATE/bug-issue.yml +++ b/.github/ISSUE_TEMPLATE/bug-issue.yml @@ -25,7 +25,7 @@ body: - type: textarea attributes: label: Bug description - description: What are the steps for reproducing the bug? Any additional details that might be of help? + description: How did you find the bug? Any additional details that might help? validations: required: true - type: textarea From 762385d336273e719b5a7f2930225b9350fcac09 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 19 Mar 2022 12:43:08 +0900 Subject: [PATCH 063/131] Simplify log drag-drop message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- .github/ISSUE_TEMPLATE/bug-issue.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug-issue.yml b/.github/ISSUE_TEMPLATE/bug-issue.yml index 0174a0d47f..a8b02b32ee 100644 --- a/.github/ISSUE_TEMPLATE/bug-issue.yml +++ b/.github/ISSUE_TEMPLATE/bug-issue.yml @@ -67,6 +67,6 @@ body: - type: textarea attributes: label: Logs - placeholder: You can attach by dragging and dropping the log files into this box. + placeholder: Drag and drop the log files into this box. validations: required: true From 41ab798bbe1c0daf9f634904ec16b6658b0a425c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 19 Mar 2022 12:43:48 +0900 Subject: [PATCH 064/131] Simplify screenshot/video attach text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- .github/ISSUE_TEMPLATE/bug-issue.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-issue.yml b/.github/ISSUE_TEMPLATE/bug-issue.yml index a8b02b32ee..5b19c3732c 100644 --- a/.github/ISSUE_TEMPLATE/bug-issue.yml +++ b/.github/ISSUE_TEMPLATE/bug-issue.yml @@ -31,8 +31,8 @@ body: - type: textarea attributes: label: Screenshots or videos - description: Share any kind of visuals you can which show the bug or issue taking place. - placeholder: You can attach by dragging and dropping the screenshots/videos into this box. + description: Add screenshots or videos that show the bug here. + placeholder: Drag and drop the screenshots/videos into this box. validations: required: false - type: input From b99541fb5e3fccd2235bd40027ba8545e33d92ee Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 19 Mar 2022 08:08:07 +0300 Subject: [PATCH 065/131] Revert "Swap placements of "hold for menu" and key counter" This reverts commit 5bcb7c167c5ae837be46f56752dd41c1236cec0b. --- osu.Game/Screens/Play/HUDOverlay.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 9edcbf3e07..628452fbc8 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -111,11 +111,8 @@ namespace osu.Game.Screens.Play Direction = FillDirection.Vertical, Children = new Drawable[] { + KeyCounter = CreateKeyCounter(), HoldToQuit = CreateHoldForMenuButton(), - KeyCounter = CreateKeyCounter().With(k => - { - k.Margin = new MarginPadding { Horizontal = 10 }; - }), } } }; @@ -238,11 +235,13 @@ namespace osu.Game.Screens.Play { PlayerSettingsOverlay.Show(); ModDisplay.FadeIn(200); + KeyCounter.Margin = new MarginPadding(10) { Bottom = 30 }; } else { PlayerSettingsOverlay.Hide(); ModDisplay.Delay(2000).FadeOut(200); + KeyCounter.Margin = new MarginPadding(10); } updateVisibility(); From da76358ee0530e4c5303cefc3c782ab051ec094f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Mar 2022 19:23:43 +0900 Subject: [PATCH 066/131] Expose the loading player in `PlayerLoader` --- osu.Game/Screens/Play/PlayerLoader.cs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 41eb822e39..384561d616 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -90,7 +90,7 @@ namespace osu.Game.Screens.Play private bool readyForPush => !playerConsumed // don't push unless the player is completely loaded - && player?.LoadState == LoadState.Ready + && CurrentPlayer?.LoadState == LoadState.Ready // don't push if the user is hovering one of the panes, unless they are idle. && (IsHovered || idleTracker.IsIdle.Value) // don't push if the user is dragging a slider or otherwise. @@ -100,10 +100,14 @@ namespace osu.Game.Screens.Play private readonly Func createPlayer; - private Player player; + /// + /// The instance being loaded by this screen. + /// + [CanBeNull] + public Player CurrentPlayer { get; private set; } /// - /// Whether the curent player instance has been consumed via . + /// Whether the current player instance has been consumed via . /// private bool playerConsumed; @@ -237,12 +241,12 @@ namespace osu.Game.Screens.Play { base.OnResuming(last); - var lastScore = player.Score; + var lastScore = CurrentPlayer.Score; AudioSettings.ReferenceScore.Value = lastScore?.ScoreInfo; // prepare for a retry. - player = null; + CurrentPlayer = null; playerConsumed = false; cancelLoad(); @@ -346,7 +350,7 @@ namespace osu.Game.Screens.Play Debug.Assert(!playerConsumed); playerConsumed = true; - return player; + return CurrentPlayer; } private void prepareNewPlayer() @@ -354,11 +358,11 @@ namespace osu.Game.Screens.Play if (!this.IsCurrentScreen()) return; - player = createPlayer(); - player.RestartCount = restartCount++; - player.RestartRequested = restartRequested; + CurrentPlayer = createPlayer(); + CurrentPlayer.RestartCount = restartCount++; + CurrentPlayer.RestartRequested = restartRequested; - LoadTask = LoadComponentAsync(player, _ => MetadataInfo.Loading = false); + LoadTask = LoadComponentAsync(CurrentPlayer, _ => MetadataInfo.Loading = false); } private void restartRequested() @@ -472,7 +476,7 @@ namespace osu.Game.Screens.Play if (isDisposing) { // if the player never got pushed, we should explicitly dispose it. - DisposalTask = LoadTask?.ContinueWith(_ => player?.Dispose()); + DisposalTask = LoadTask?.ContinueWith(_ => CurrentPlayer?.Dispose()); } } From dae5569e367acdacc1f6ee2c6f0f7c80da15762d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Mar 2022 19:36:33 +0900 Subject: [PATCH 067/131] Use `nullable` in `PlayerLoader` --- osu.Game/Screens/Play/PlayerLoader.cs | 54 ++++++++++++++------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 384561d616..ba720af2a1 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -1,10 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +#nullable enable + using System; using System.Diagnostics; using System.Threading.Tasks; -using JetBrains.Annotations; using ManagedBass.Fx; using osu.Framework.Allocation; using osu.Framework.Audio; @@ -48,31 +49,31 @@ namespace osu.Game.Screens.Play public override bool HandlePositionalInput => true; // We show the previous screen status - protected override UserActivity InitialActivity => null; + protected override UserActivity? InitialActivity => null; protected override bool PlayResumeSound => false; - protected BeatmapMetadataDisplay MetadataInfo { get; private set; } + protected BeatmapMetadataDisplay MetadataInfo { get; private set; } = null!; /// /// A fill flow containing the player settings groups, exposed for the ability to hide it from inheritors of the player loader. /// - protected FillFlowContainer PlayerSettings { get; private set; } + protected FillFlowContainer PlayerSettings { get; private set; } = null!; - protected VisualSettings VisualSettings { get; private set; } + protected VisualSettings VisualSettings { get; private set; } = null!; - protected AudioSettings AudioSettings { get; private set; } + protected AudioSettings AudioSettings { get; private set; } = null!; - protected Task LoadTask { get; private set; } + protected Task? LoadTask { get; private set; } - protected Task DisposalTask { get; private set; } + protected Task? DisposalTask { get; private set; } private bool backgroundBrightnessReduction; private readonly BindableDouble volumeAdjustment = new BindableDouble(1); - private AudioFilter lowPassFilter; - private AudioFilter highPassFilter; + private AudioFilter lowPassFilter = null!; + private AudioFilter highPassFilter = null!; protected bool BackgroundBrightnessReduction { @@ -94,47 +95,45 @@ namespace osu.Game.Screens.Play // don't push if the user is hovering one of the panes, unless they are idle. && (IsHovered || idleTracker.IsIdle.Value) // don't push if the user is dragging a slider or otherwise. - && inputManager?.DraggedDrawable == null + && inputManager.DraggedDrawable == null // don't push if a focused overlay is visible, like settings. - && inputManager?.FocusedDrawable == null; + && inputManager.FocusedDrawable == null; private readonly Func createPlayer; /// /// The instance being loaded by this screen. /// - [CanBeNull] - public Player CurrentPlayer { get; private set; } + public Player? CurrentPlayer { get; private set; } /// /// Whether the current player instance has been consumed via . /// private bool playerConsumed; - private LogoTrackingContainer content; + private LogoTrackingContainer content = null!; private bool hideOverlays; - private InputManager inputManager; + private InputManager inputManager = null!; - private IdleTracker idleTracker; + private IdleTracker idleTracker = null!; - private ScheduledDelegate scheduledPushPlayer; + private ScheduledDelegate? scheduledPushPlayer; - [CanBeNull] - private EpilepsyWarning epilepsyWarning; + private EpilepsyWarning? epilepsyWarning; [Resolved(CanBeNull = true)] - private NotificationOverlay notificationOverlay { get; set; } + private NotificationOverlay? notificationOverlay { get; set; } [Resolved(CanBeNull = true)] - private VolumeOverlay volumeOverlay { get; set; } + private VolumeOverlay? volumeOverlay { get; set; } [Resolved] - private AudioManager audioManager { get; set; } + private AudioManager audioManager { get; set; } = null!; [Resolved(CanBeNull = true)] - private BatteryInfo batteryInfo { get; set; } + private BatteryInfo? batteryInfo { get; set; } public PlayerLoader(Func createPlayer) { @@ -241,6 +240,8 @@ namespace osu.Game.Screens.Play { base.OnResuming(last); + Debug.Assert(CurrentPlayer != null); + var lastScore = CurrentPlayer.Score; AudioSettings.ReferenceScore.Value = lastScore?.ScoreInfo; @@ -348,6 +349,7 @@ namespace osu.Game.Screens.Play private Player consumePlayer() { Debug.Assert(!playerConsumed); + Debug.Assert(CurrentPlayer != null); playerConsumed = true; return CurrentPlayer; @@ -484,7 +486,7 @@ namespace osu.Game.Screens.Play #region Mute warning - private Bindable muteWarningShownOnce; + private Bindable muteWarningShownOnce = null!; private int restartCount; @@ -539,7 +541,7 @@ namespace osu.Game.Screens.Play #region Low battery warning - private Bindable batteryWarningShownOnce; + private Bindable batteryWarningShownOnce = null!; private void showBatteryWarningIfNeeded() { From 63998ad9f121221d4ba27478c2db10aa0d61dcb8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Mar 2022 19:23:49 +0900 Subject: [PATCH 068/131] Add test coverage of `SpectatorPlayer` failing to seek on inopportune frame arrival time --- .../Visual/Gameplay/TestSceneSpectator.cs | 54 ++++++++++++++++++- .../Visual/Spectator/TestSpectatorClient.cs | 5 +- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs index d614815316..8b420cebc8 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs @@ -70,6 +70,56 @@ namespace osu.Game.Tests.Visual.Gameplay }); } + [Test] + public void TestSeekToGameplayStartFramesArriveAfterPlayerLoad() + { + const double gameplay_start = 10000; + + loadSpectatingScreen(); + + start(); + + waitForPlayer(); + + sendFrames(startTime: gameplay_start); + + AddAssert("time is greater than seek target", () => currentFrameStableTime > gameplay_start); + } + + /// + /// Tests the same as but with the frames arriving just as is transitioning into existence. + /// + [Test] + public void TestSeekToGameplayStartFramesArriveAsPlayerLoaded() + { + const double gameplay_start = 10000; + + loadSpectatingScreen(); + + start(); + + AddUntilStep("wait for player loader", () => (Stack.CurrentScreen as PlayerLoader)?.IsLoaded == true); + + AddUntilStep("queue send frames on player load", () => + { + var loadingPlayer = (Stack.CurrentScreen as PlayerLoader)?.CurrentPlayer; + + if (loadingPlayer == null) + return false; + + loadingPlayer.OnLoadComplete += _ => + { + spectatorClient.SendFramesFromUser(streamingUser.Id, 10, gameplay_start); + }; + return true; + }); + + waitForPlayer(); + + AddUntilStep("state is playing", () => spectatorClient.WatchedUserStates[streamingUser.Id].State == SpectatedUserState.Playing); + AddAssert("time is greater than seek target", () => currentFrameStableTime > gameplay_start); + } + [Test] public void TestFrameStarvationAndResume() { @@ -319,9 +369,9 @@ namespace osu.Game.Tests.Visual.Gameplay private void checkPaused(bool state) => AddUntilStep($"game is {(state ? "paused" : "playing")}", () => player.ChildrenOfType().First().IsPaused.Value == state); - private void sendFrames(int count = 10) + private void sendFrames(int count = 10, double startTime = 0) { - AddStep("send frames", () => spectatorClient.SendFramesFromUser(streamingUser.Id, count)); + AddStep("send frames", () => spectatorClient.SendFramesFromUser(streamingUser.Id, count, startTime)); } private void loadSpectatingScreen() diff --git a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs index f5da95bd7b..ac7cb43e02 100644 --- a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs +++ b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs @@ -88,7 +88,8 @@ namespace osu.Game.Tests.Visual.Spectator /// /// The user to send frames for. /// The total number of frames to send. - public void SendFramesFromUser(int userId, int count) + /// The time to start gameplay frames from. + public void SendFramesFromUser(int userId, int count, double startTime = 0) { var frames = new List(); @@ -102,7 +103,7 @@ namespace osu.Game.Tests.Visual.Spectator flush(); var buttonState = currentFrameIndex == lastFrameIndex ? ReplayButtonState.None : ReplayButtonState.Left1; - frames.Add(new LegacyReplayFrame(currentFrameIndex * 100, RNG.Next(0, 512), RNG.Next(0, 512), buttonState)); + frames.Add(new LegacyReplayFrame(currentFrameIndex * 100 + startTime, RNG.Next(0, 512), RNG.Next(0, 512), buttonState)); } flush(); From 2b59eff465ef38c6e2e8c6edf1f8bb368f7eb8a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 19 Mar 2022 15:06:09 +0900 Subject: [PATCH 069/131] Fix spectator not starting from correct seek point (hotfix) --- .../Play/MasterGameplayClockContainer.cs | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index af58e9d910..410f257a44 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -78,17 +78,12 @@ namespace osu.Game.Screens.Play firstHitObjectTime = beatmap.Beatmap.HitObjects.First().StartTime; } - protected override void LoadComplete() + [BackgroundDependencyLoader] + private void load() { - base.LoadComplete(); - - userAudioOffset = config.GetBindable(OsuSetting.AudioOffset); - userAudioOffset.BindValueChanged(offset => userGlobalOffsetClock.Offset = offset.NewValue, true); - - beatmapOffsetSubscription = realm.SubscribeToPropertyChanged( - r => r.Find(beatmap.BeatmapInfo.ID)?.UserSettings, - settings => settings.Offset, - val => userBeatmapOffsetClock.Offset = val); + // TODO: This code should not be in the BDL load method, but is to avoid seeks being overwritten. + // See https://github.com/ppy/osu/issues/17267 for the issue. + // See https://github.com/ppy/osu/pull/17302 for a better fix which needs some more time. // sane default provided by ruleset. startOffset = gameplayStartTime; @@ -112,6 +107,19 @@ namespace osu.Game.Screens.Play Seek(startOffset); } + protected override void LoadComplete() + { + base.LoadComplete(); + + userAudioOffset = config.GetBindable(OsuSetting.AudioOffset); + userAudioOffset.BindValueChanged(offset => userGlobalOffsetClock.Offset = offset.NewValue, true); + + beatmapOffsetSubscription = realm.SubscribeToPropertyChanged( + r => r.Find(beatmap.BeatmapInfo.ID)?.UserSettings, + settings => settings.Offset, + val => userBeatmapOffsetClock.Offset = val); + } + protected override void OnIsPausedChanged(ValueChangedEvent isPaused) { // The source is stopped by a frequency fade first. From cf2212e79464aa30c0ea721d00bf71f955fbc1a6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 19 Mar 2022 17:20:54 +0900 Subject: [PATCH 070/131] Revert "Fix spectator not starting from correct seek point (hotfix)" This reverts commit 2b59eff465ef38c6e2e8c6edf1f8bb368f7eb8a9. --- .../Play/MasterGameplayClockContainer.cs | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 410f257a44..af58e9d910 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -78,12 +78,17 @@ namespace osu.Game.Screens.Play firstHitObjectTime = beatmap.Beatmap.HitObjects.First().StartTime; } - [BackgroundDependencyLoader] - private void load() + protected override void LoadComplete() { - // TODO: This code should not be in the BDL load method, but is to avoid seeks being overwritten. - // See https://github.com/ppy/osu/issues/17267 for the issue. - // See https://github.com/ppy/osu/pull/17302 for a better fix which needs some more time. + base.LoadComplete(); + + userAudioOffset = config.GetBindable(OsuSetting.AudioOffset); + userAudioOffset.BindValueChanged(offset => userGlobalOffsetClock.Offset = offset.NewValue, true); + + beatmapOffsetSubscription = realm.SubscribeToPropertyChanged( + r => r.Find(beatmap.BeatmapInfo.ID)?.UserSettings, + settings => settings.Offset, + val => userBeatmapOffsetClock.Offset = val); // sane default provided by ruleset. startOffset = gameplayStartTime; @@ -107,19 +112,6 @@ namespace osu.Game.Screens.Play Seek(startOffset); } - protected override void LoadComplete() - { - base.LoadComplete(); - - userAudioOffset = config.GetBindable(OsuSetting.AudioOffset); - userAudioOffset.BindValueChanged(offset => userGlobalOffsetClock.Offset = offset.NewValue, true); - - beatmapOffsetSubscription = realm.SubscribeToPropertyChanged( - r => r.Find(beatmap.BeatmapInfo.ID)?.UserSettings, - settings => settings.Offset, - val => userBeatmapOffsetClock.Offset = val); - } - protected override void OnIsPausedChanged(ValueChangedEvent isPaused) { // The source is stopped by a frequency fade first. From a903aee17e4a8c44e2d1d56b8e964a7fc9b0c459 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 19 Mar 2022 17:23:37 +0900 Subject: [PATCH 071/131] Use schedule to workaround seek issue instead --- osu.Game/Screens/Play/Player.cs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index cb8f4b6020..73bdeb5783 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -615,16 +615,22 @@ namespace osu.Game.Screens.Play /// The destination time to seek to. internal void NonFrameStableSeek(double time) { - if (frameStablePlaybackResetDelegate?.Cancelled == false && !frameStablePlaybackResetDelegate.Completed) - frameStablePlaybackResetDelegate.RunTask(); + // TODO: This schedule should not be required and is a temporary hotfix. + // See https://github.com/ppy/osu/issues/17267 for the issue. + // See https://github.com/ppy/osu/pull/17302 for a better fix which needs some more time. + ScheduleAfterChildren(() => + { + if (frameStablePlaybackResetDelegate?.Cancelled == false && !frameStablePlaybackResetDelegate.Completed) + frameStablePlaybackResetDelegate.RunTask(); - bool wasFrameStable = DrawableRuleset.FrameStablePlayback; - DrawableRuleset.FrameStablePlayback = false; + bool wasFrameStable = DrawableRuleset.FrameStablePlayback; + DrawableRuleset.FrameStablePlayback = false; - Seek(time); + Seek(time); - // Delay resetting frame-stable playback for one frame to give the FrameStabilityContainer a chance to seek. - frameStablePlaybackResetDelegate = ScheduleAfterChildren(() => DrawableRuleset.FrameStablePlayback = wasFrameStable); + // Delay resetting frame-stable playback for one frame to give the FrameStabilityContainer a chance to seek. + frameStablePlaybackResetDelegate = ScheduleAfterChildren(() => DrawableRuleset.FrameStablePlayback = wasFrameStable); + }); } /// From a293e0c7664f74aec797793bb930119bc42ccba0 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sat, 19 Mar 2022 16:44:58 +0000 Subject: [PATCH 072/131] Remove redundant `ControlItemText` class --- .../Chat/ChannelControl/ControlItem.cs | 22 ++++++- .../Chat/ChannelControl/ControlItemText.cs | 59 ------------------- 2 files changed, 19 insertions(+), 62 deletions(-) delete mode 100644 osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs index bf4d60d4e2..df857a6dce 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs @@ -10,7 +10,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; +using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; using osu.Game.Online.Chat; namespace osu.Game.Overlays.Chat.ChannelControl @@ -28,18 +30,22 @@ namespace osu.Game.Overlays.Chat.ChannelControl private Box? hoverBox; private Box? selectBox; + private OsuSpriteText? text; private ControlItemClose? close; [Resolved] private Bindable selectedChannel { get; set; } = null!; + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + public ControlItem(Channel channel) { this.channel = channel; } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load() { Height = 30; RelativeSizeAxes = Axes.X; @@ -77,11 +83,16 @@ namespace osu.Game.Overlays.Chat.ChannelControl new[] { createIcon(), - new ControlItemText(channel) + text = new OsuSpriteText { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Unread = { BindTarget = Unread }, + Text = channel.Type == ChannelType.Public ? $"# {channel.Name.Substring(1)}" : channel.Name, + Font = OsuFont.Torus.With(size: 17, weight: FontWeight.SemiBold), + Colour = colourProvider.Light3, + Margin = new MarginPadding { Bottom = 2 }, + RelativeSizeAxes = Axes.X, + Truncate = true, }, new ControlItemMention { @@ -117,6 +128,11 @@ namespace osu.Game.Overlays.Chat.ChannelControl else selectBox?.Hide(); }, true); + + Unread.BindValueChanged(change => + { + text!.Colour = change.NewValue ? colourProvider.Content1 : colourProvider.Light3; + }, true); } protected override bool OnHover(HoverEvent e) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs deleted file mode 100644 index 490edb5d28..0000000000 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemText.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable enable - -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Online.Chat; - -namespace osu.Game.Overlays.Chat.ChannelControl -{ - public class ControlItemText : Container - { - public readonly BindableBool Unread = new BindableBool(); - - private readonly Channel channel; - - private OsuSpriteText? text; - - [Resolved] - private OverlayColourProvider colourProvider { get; set; } = null!; - - public ControlItemText(Channel channel) - { - this.channel = channel; - } - - [BackgroundDependencyLoader] - private void load() - { - RelativeSizeAxes = Axes.Both; - Child = text = new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Text = channel.Type == ChannelType.Public ? $"# {channel.Name.Substring(1)}" : channel.Name, - Font = OsuFont.Torus.With(size: 17, weight: FontWeight.SemiBold), - Colour = colourProvider.Light3, - Margin = new MarginPadding { Bottom = 2 }, - RelativeSizeAxes = Axes.X, - Truncate = true, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - Unread.BindValueChanged(change => - { - text!.Colour = change.NewValue ? colourProvider.Content1 : colourProvider.Light3; - }, true); - } - } -} From ef823d58a7e790d370a9e184405eedbc30f5025d Mon Sep 17 00:00:00 2001 From: hwabis Date: Sat, 19 Mar 2022 13:05:35 -0400 Subject: [PATCH 073/131] address frenzibyte review (refactor bindable flow, clean up CI stuff) --- .../Match/Playlist/MultiplayerPlaylist.cs | 3 +- .../Playlist/MultiplayerPlaylistTabControl.cs | 31 ++++++++++++------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs index 3269257260..77076bd1cc 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs @@ -70,8 +70,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist { base.LoadComplete(); DisplayMode.BindValueChanged(onDisplayModeChanged, true); - queueList.Items.BindCollectionChanged( - (_, __) => playlistTabControl.queueListCount.Value = queueList.Items.Count, true); + playlistTabControl.QueueItems.BindTarget = queueList.Items; } private void onDisplayModeChanged(ValueChangedEvent mode) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs index f0a51eb5e1..882a96c877 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs @@ -4,31 +4,40 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist { public class MultiplayerPlaylistTabControl : OsuTabControl { - public Bindable queueListCount = new Bindable(0); - - public MultiplayerPlaylistTabControl() - { - } + public readonly IBindableList QueueItems = new BindableList(); protected override TabItem CreateTabItem(MultiplayerPlaylistDisplayMode value) { if (value == MultiplayerPlaylistDisplayMode.Queue) - return new QueueTabItem(value, queueListCount); - return new OsuTabItem(value); + return new QueueTabItem { QueueItems = { BindTarget = QueueItems } }; + + return base.CreateTabItem(value); } private class QueueTabItem : OsuTabItem { - public QueueTabItem(MultiplayerPlaylistDisplayMode value, Bindable queueListCount) - : base(value) + public readonly IBindableList QueueItems = new BindableList(); + + public QueueTabItem() + : base(MultiplayerPlaylistDisplayMode.Queue) { - queueListCount.BindValueChanged( - _ => Text.Text = "Queue (" + queueListCount.Value + ")", true); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + QueueItems.BindCollectionChanged((_,__) => + { + Text.Text = $"Queue"; + if (QueueItems.Count != 0) + Text.Text += $" ({QueueItems.Count})"; + }, true); } } } From 149cfd338dd5e77dca9cc7f612ab311914176cfd Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Sat, 19 Mar 2022 18:29:44 +0000 Subject: [PATCH 074/131] Use new mod-related object types for Strict Tracking --- .../StrictTrackingDrawableSliderTail.cs | 12 ++++ .../Mods/Objects/StrictTrackingSlider.cs | 70 +++++++++++++++++++ .../Objects/StrictTrackingSliderTailCircle.cs | 19 +++++ .../Mods/OsuModStrictTracking.cs | 40 +++++++---- osu.Game.Rulesets.Osu/Objects/Slider.cs | 6 +- osu.Game/Rulesets/UI/Playfield.cs | 2 +- 6 files changed, 132 insertions(+), 17 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs create mode 100644 osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs create mode 100644 osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs diff --git a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs new file mode 100644 index 0000000000..110b09f4f9 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs @@ -0,0 +1,12 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Osu.Objects.Drawables; + +namespace osu.Game.Rulesets.Osu.Mods.Objects +{ + public class StrictTrackingDrawableSliderTail : DrawableSliderTail + { + public override bool DisplayResult => true; + } +} diff --git a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs new file mode 100644 index 0000000000..bf0a57d871 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs @@ -0,0 +1,70 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Mods.Objects +{ + public class StrictTrackingSlider : Slider + { + public StrictTrackingSlider(Slider original) + { + StartTime = original.StartTime; + Samples = original.Samples; + Path = original.Path; + NodeSamples = original.NodeSamples; + RepeatCount = original.RepeatCount; + Position = original.Position; + NewCombo = original.NewCombo; + ComboOffset = original.ComboOffset; + LegacyLastTickOffset = original.LegacyLastTickOffset; + TickDistanceMultiplier = original.TickDistanceMultiplier; + } + + protected override void CreateNestedHitObjects(CancellationToken cancellationToken) + { + var sliderEvents = SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, cancellationToken); + + foreach (var e in sliderEvents) + { + switch (e.Type) + { + case SliderEventType.Head: + AddNested(HeadCircle = new SliderHeadCircle + { + StartTime = e.Time, + Position = Position, + StackHeight = StackHeight, + }); + break; + + case SliderEventType.LegacyLastTick: + AddNested(TailCircle = new StrictTrackingSliderTailCircle(this) + { + RepeatIndex = e.SpanIndex, + StartTime = e.Time, + Position = EndPosition, + StackHeight = StackHeight + }); + break; + + case SliderEventType.Repeat: + AddNested(new SliderRepeat(this) + { + RepeatIndex = e.SpanIndex, + StartTime = StartTime + (e.SpanIndex + 1) * SpanDuration, + Position = Position + Path.PositionAt(e.PathProgress), + StackHeight = StackHeight, + Scale = Scale, + }); + break; + } + } + + UpdateNestedSamples(); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs new file mode 100644 index 0000000000..7d93f2cf39 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Osu.Judgements; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Mods.Objects +{ + public class StrictTrackingSliderTailCircle : SliderTailCircle + { + public StrictTrackingSliderTailCircle(Slider slider) + : base(slider) + { + } + + public override Judgement CreateJudgement() => new OsuJudgement(); + } +} diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs index 13da422049..255ac4fa22 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -2,17 +2,20 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Rulesets.Osu.Mods.Objects; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModStrictTracking : Mod, IApplicableToDifficulty, IApplicableToDrawableHitObject, IApplicableToHitObject + public class OsuModStrictTracking : Mod, IApplicableAfterBeatmapConversion, IApplicableToDrawableHitObject, IApplicableToDrawableRuleset { public override string Name => @"Strict Tracking"; public override string Acronym => @"ST"; @@ -22,11 +25,6 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1.0; public override Type[] IncompatibleMods => new[] { typeof(ModClassic) }; - public void ApplyToDifficulty(BeatmapDifficulty difficulty) - { - difficulty.SliderTickRate = 0.0; - } - public void ApplyToDrawableHitObject(DrawableHitObject drawable) { if (drawable is DrawableSlider slider) @@ -46,14 +44,30 @@ namespace osu.Game.Rulesets.Osu.Mods } } - public void ApplyToHitObject(HitObject hitObject) + public void ApplyToBeatmap(IBeatmap beatmap) { - switch (hitObject) + var osuBeatmap = (OsuBeatmap)beatmap; + + if (osuBeatmap.HitObjects.Count == 0) return; + + var hitObjects = osuBeatmap.HitObjects.Select(ho => { - case Slider slider: - slider.TailCircle.JudgeAsSliderTick = true; - break; - } + if (ho is Slider slider) + { + var newSlider = new StrictTrackingSlider(slider); + return newSlider; + } + + return ho; + }).ToList(); + + osuBeatmap.HitObjects = hitObjects; + } + + public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) + { + drawableRuleset.Playfield.RegisterPool(10, 100); + drawableRuleset.Playfield.RegisterPool(10, 100); } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 5c1c3fd253..64dbab6fb8 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -137,7 +137,7 @@ namespace osu.Game.Rulesets.Osu.Objects public Slider() { - SamplesBindable.CollectionChanged += (_, __) => updateNestedSamples(); + SamplesBindable.CollectionChanged += (_, __) => UpdateNestedSamples(); Path.Version.ValueChanged += _ => updateNestedPositions(); } @@ -210,7 +210,7 @@ namespace osu.Game.Rulesets.Osu.Objects } } - updateNestedSamples(); + UpdateNestedSamples(); } private void updateNestedPositions() @@ -224,7 +224,7 @@ namespace osu.Game.Rulesets.Osu.Objects TailCircle.Position = EndPosition; } - private void updateNestedSamples() + protected void UpdateNestedSamples() { var firstSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL) ?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933) diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 30e71dde1c..940b8d1ac1 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -308,7 +308,7 @@ namespace osu.Game.Rulesets.UI /// /// The type. /// The receiver for s. - protected void RegisterPool(int initialSize, int? maximumSize = null) + public void RegisterPool(int initialSize, int? maximumSize = null) where TObject : HitObject where TDrawable : DrawableHitObject, new() => RegisterPool(new DrawablePool(initialSize, maximumSize)); From 5373c3066ffc070476c1402b7032aa3e8f3846c6 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sat, 19 Mar 2022 17:23:59 +0000 Subject: [PATCH 075/131] Use `OsuAnimatedButton` as base for `ControlItemClose` --- .../Chat/ChannelControl/ControlItemClose.cs | 42 ++++--------------- 1 file changed, 7 insertions(+), 35 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs index c0f419f619..6064e3790d 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs @@ -6,56 +6,28 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; -using osu.Framework.Input.Events; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; using osuTK; namespace osu.Game.Overlays.Chat.ChannelControl { - public class ControlItemClose : OsuClickableContainer + public class ControlItemClose : OsuAnimatedButton { - private readonly SpriteIcon icon; - - [Resolved] - private OsuColour osuColour { get; set; } = null!; - - public ControlItemClose() + [BackgroundDependencyLoader] + private void load(OsuColour osuColour) { Alpha = 0f; Size = new Vector2(20); - Child = icon = new SpriteIcon + Add(new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, Scale = new Vector2(0.75f), Icon = FontAwesome.Solid.TimesCircle, RelativeSizeAxes = Axes.Both, - }; - } - - protected override bool OnMouseDown(MouseDownEvent e) - { - icon.ScaleTo(0.5f, 1000, Easing.OutQuint); - return base.OnMouseDown(e); - } - - protected override void OnMouseUp(MouseUpEvent e) - { - icon.ScaleTo(0.75f, 1000, Easing.OutElastic); - base.OnMouseUp(e); - } - - protected override bool OnHover(HoverEvent e) - { - icon.FadeColour(osuColour.Red1, 200, Easing.OutQuint); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - icon.FadeColour(Colour4.White, 200, Easing.OutQuint); - base.OnHoverLost(e); + Colour = osuColour.Red1, + }); } } } From 653bb47dd587d8feac0f48b5465a9fccd3f66ca0 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sat, 19 Mar 2022 21:36:11 +0000 Subject: [PATCH 076/131] Use `UpdateableAvatar` and remove redundant `ControlItemAvatar` class --- .../Chat/ChannelControl/ControlItem.cs | 9 ++- .../Chat/ChannelControl/ControlItemAvatar.cs | 62 ------------------- 2 files changed, 8 insertions(+), 63 deletions(-) delete mode 100644 osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs index df857a6dce..a388ebc52f 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs +++ b/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs @@ -4,6 +4,7 @@ #nullable enable using System; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -14,6 +15,8 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Online.Chat; +using osu.Game.Users.Drawables; +using osuTK; namespace osu.Game.Overlays.Chat.ChannelControl { @@ -154,10 +157,14 @@ namespace osu.Game.Overlays.Chat.ChannelControl if (channel.Type != ChannelType.PM) return Drawable.Empty(); - return new ControlItemAvatar(channel) + return new UpdateableAvatar(channel.Users.First(), false, false, true) { + Size = new Vector2(20), + Margin = new MarginPadding { Right = 5 }, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, + CornerRadius = 10, + Masking = true, }; } } diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs b/osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs deleted file mode 100644 index bb3109ec1f..0000000000 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemAvatar.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable enable - -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; -using osu.Game.Online.Chat; -using osu.Game.Users.Drawables; -using osuTK; - -namespace osu.Game.Overlays.Chat.ChannelControl -{ - public class ControlItemAvatar : CircularContainer - { - private readonly Channel channel; - - private SpriteIcon? placeholder; - private DrawableAvatar? avatar; - - public ControlItemAvatar(Channel channel) - { - this.channel = channel; - } - - [BackgroundDependencyLoader] - private void load() - { - Size = new Vector2(20); - Margin = new MarginPadding { Right = 5 }; - Masking = true; - - Children = new Drawable[] - { - placeholder = new SpriteIcon - { - Icon = FontAwesome.Solid.At, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = Colour4.White, - RelativeSizeAxes = Axes.Both, - Alpha = 0.5f, - }, - new DelayedLoadWrapper(avatar = new DrawableAvatar(channel.Users.First()) - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }), - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - avatar!.OnLoadComplete += _ => placeholder!.FadeOut(250); - } - } -} From ba5a43b5260536275e00d97720a0d05e81529bb9 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sat, 19 Mar 2022 21:49:14 +0000 Subject: [PATCH 077/131] Rename `ControlItem` -> `ChannelListItem` and associated classes --- ...nelControlItem.cs => TestSceneChannelListItem.cs} | 8 ++++---- .../ChannelListItem.cs} | 12 ++++++------ .../ChannelListItemClose.cs} | 4 ++-- .../ChannelListItemMention.cs} | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) rename osu.Game.Tests/Visual/Online/{TestSceneChannelControlItem.cs => TestSceneChannelListItem.cs} (95%) rename osu.Game/Overlays/Chat/{ChannelControl/ControlItem.cs => ChannelList/ChannelListItem.cs} (94%) rename osu.Game/Overlays/Chat/{ChannelControl/ControlItemClose.cs => ChannelList/ChannelListItemClose.cs} (89%) rename osu.Game/Overlays/Chat/{ChannelControl/ControlItemMention.cs => ChannelList/ChannelListItemMention.cs} (94%) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelListItem.cs similarity index 95% rename from osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs rename to osu.Game.Tests/Visual/Online/TestSceneChannelListItem.cs index e66092bf27..ac829f8cbc 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelControlItem.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelListItem.cs @@ -12,13 +12,13 @@ using osu.Game.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Overlays; -using osu.Game.Overlays.Chat.ChannelControl; +using osu.Game.Overlays.Chat.ChannelList; using osuTK; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneChannelControlItem : OsuTestScene + public class TestSceneChannelListItem : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); @@ -34,7 +34,7 @@ namespace osu.Game.Tests.Visual.Online createPrivateChannel("test user long name", 3), }; - private readonly Dictionary channelMap = new Dictionary(); + private readonly Dictionary channelMap = new Dictionary(); private FillFlowContainer flow; private OsuSpriteText selectedText; @@ -102,7 +102,7 @@ namespace osu.Game.Tests.Visual.Online foreach (var channel in channels) { - var item = new ControlItem(channel); + var item = new ChannelListItem(channel); flow.Add(item); channelMap.Add(channel, item); item.OnRequestSelect += c => selected.Value = c; diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs similarity index 94% rename from osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs rename to osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs index a388ebc52f..247b04688c 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItem.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs @@ -18,9 +18,9 @@ using osu.Game.Online.Chat; using osu.Game.Users.Drawables; using osuTK; -namespace osu.Game.Overlays.Chat.ChannelControl +namespace osu.Game.Overlays.Chat.ChannelList { - public class ControlItem : OsuClickableContainer + public class ChannelListItem : OsuClickableContainer { public event Action? OnRequestSelect; public event Action? OnRequestLeave; @@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl private Box? hoverBox; private Box? selectBox; private OsuSpriteText? text; - private ControlItemClose? close; + private ChannelListItemClose? close; [Resolved] private Bindable selectedChannel { get; set; } = null!; @@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Chat.ChannelControl [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; - public ControlItem(Channel channel) + public ChannelListItem(Channel channel) { this.channel = channel; } @@ -97,14 +97,14 @@ namespace osu.Game.Overlays.Chat.ChannelControl RelativeSizeAxes = Axes.X, Truncate = true, }, - new ControlItemMention + new ChannelListItemMention { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Margin = new MarginPadding { Right = 3 }, Mentions = { BindTarget = Mentions }, }, - close = new ControlItemClose + close = new ChannelListItemClose { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemClose.cs similarity index 89% rename from osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs rename to osu.Game/Overlays/Chat/ChannelList/ChannelListItemClose.cs index 6064e3790d..37a1fcdde7 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemClose.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemClose.cs @@ -10,9 +10,9 @@ using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osuTK; -namespace osu.Game.Overlays.Chat.ChannelControl +namespace osu.Game.Overlays.Chat.ChannelList { - public class ControlItemClose : OsuAnimatedButton + public class ChannelListItemClose : OsuAnimatedButton { [BackgroundDependencyLoader] private void load(OsuColour osuColour) diff --git a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemMention.cs similarity index 94% rename from osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs rename to osu.Game/Overlays/Chat/ChannelList/ChannelListItemMention.cs index f4d65e3cef..3a1c3b7619 100644 --- a/osu.Game/Overlays/Chat/ChannelControl/ControlItemMention.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemMention.cs @@ -12,9 +12,9 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osuTK; -namespace osu.Game.Overlays.Chat.ChannelControl +namespace osu.Game.Overlays.Chat.ChannelList { - public class ControlItemMention : CircularContainer + public class ChannelListItemMention : CircularContainer { public readonly BindableInt Mentions = new BindableInt(); From f3702fbefbb9f42041d68c7d73d8a63a33f61d94 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sat, 19 Mar 2022 22:20:17 +0000 Subject: [PATCH 078/131] Pass correct params to `UpdateableAvatar` ctor in `ChannelListItem` --- osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs index 247b04688c..583493181b 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs @@ -157,7 +157,7 @@ namespace osu.Game.Overlays.Chat.ChannelList if (channel.Type != ChannelType.PM) return Drawable.Empty(); - return new UpdateableAvatar(channel.Users.First(), false, false, true) + return new UpdateableAvatar(channel.Users.First(), isInteractive: false) { Size = new Vector2(20), Margin = new MarginPadding { Right = 5 }, From 52d6f083dc2ab487c9fdd11905644296a3f41830 Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Sat, 19 Mar 2022 23:42:12 +0000 Subject: [PATCH 079/131] Only miss slider tail on untrack --- osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs index 255ac4fa22..b8d7134e5f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -33,13 +33,10 @@ namespace osu.Game.Rulesets.Osu.Mods { if (e.NewValue || slider.Judged) return; - slider.MissForcefully(); + var tail = slider.NestedHitObjects.OfType().First(); - foreach (var o in slider.NestedHitObjects) - { - if (o is DrawableOsuHitObject h && !o.Judged) - h.MissForcefully(); - } + if (!tail.Judged) + tail.MissForcefully(); }; } } @@ -66,7 +63,6 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - drawableRuleset.Playfield.RegisterPool(10, 100); drawableRuleset.Playfield.RegisterPool(10, 100); } } From c5cc7eec79ba4c2797c2ec5f11cf702bd8bcc49c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 20 Mar 2022 05:01:32 +0300 Subject: [PATCH 080/131] Add explicit todo about removing `BeatmapInfo.MaxCombo` Using that property is a trap basically. --- osu.Game/Beatmaps/BeatmapInfo.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index c6f69286cd..5a2cfd63cf 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -9,6 +9,7 @@ using osu.Framework.Testing; using osu.Game.Database; using osu.Game.Models; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays.BeatmapSet.Scores; using osu.Game.Rulesets; using osu.Game.Scoring; using Realms; @@ -169,6 +170,10 @@ namespace osu.Game.Beatmaps [Ignored] public APIBeatmap? OnlineInfo { get; set; } + /// + /// The maximum achievable combo on this beatmap, populated for online info purposes only. + /// Todo: This should never be used nor exist, but is still relied on in since can't be used yet. + /// [Ignored] public int? MaxCombo { get; set; } From d36f32a9c99780d183214dba8b609bf0693bb9a1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 20 Mar 2022 05:28:07 +0300 Subject: [PATCH 081/131] Introduce method for computing maximum achievable combo properly --- osu.Game/Scoring/ScoreManager.cs | 62 ++++++++++++++++---------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 02a7d9a39f..0f3c991f07 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -134,35 +134,9 @@ namespace osu.Game.Scoring if (string.IsNullOrEmpty(score.BeatmapInfo.MD5Hash)) return score.TotalScore; - int beatmapMaxCombo; - - if (score.IsLegacyScore) - { - // This score is guaranteed to be an osu!stable score. - // The combo must be determined through either the beatmap's max combo value or the difficulty calculator, as lazer's scoring has changed and the score statistics cannot be used. - if (score.BeatmapInfo.MaxCombo != null) - beatmapMaxCombo = score.BeatmapInfo.MaxCombo.Value; - else - { - if (difficulties == null) - return score.TotalScore; - - // We can compute the max combo locally after the async beatmap difficulty computation. - var difficulty = await difficulties().GetDifficultyAsync(score.BeatmapInfo, score.Ruleset, score.Mods, cancellationToken).ConfigureAwait(false); - - // Something failed during difficulty calculation. Fall back to provided score. - if (difficulty == null) - return score.TotalScore; - - beatmapMaxCombo = difficulty.Value.MaxCombo; - } - } - else - { - // This is guaranteed to be a non-legacy score. - // The combo must be determined through the score's statistics, as both the beatmap's max combo and the difficulty calculator will provide osu!stable combo values. - beatmapMaxCombo = Enum.GetValues(typeof(HitResult)).OfType().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetValueOrDefault(r)).Sum(); - } + int? beatmapMaxCombo = await GetBeatmapMaximumComboAsync(score, cancellationToken).ConfigureAwait(false); + if (beatmapMaxCombo == null) + return score.TotalScore; if (beatmapMaxCombo == 0) return 0; @@ -171,7 +145,35 @@ namespace osu.Game.Scoring var scoreProcessor = ruleset.CreateScoreProcessor(); scoreProcessor.Mods.Value = score.Mods; - return (long)Math.Round(scoreProcessor.ComputeFinalLegacyScore(mode, score, beatmapMaxCombo)); + return (long)Math.Round(scoreProcessor.ComputeFinalLegacyScore(mode, score, beatmapMaxCombo.Value)); + } + + /// + /// Retrieves the maximum achievable combo on the beatmap of the provided score. + /// + /// The to compute the maximum achievable combo for. + /// A to cancel the process. + /// The maximum achievable combo. + public async Task GetBeatmapMaximumComboAsync([NotNull] ScoreInfo score, CancellationToken cancellationToken = default) + { + if (score.IsLegacyScore) + { + // This score is guaranteed to be an osu!stable score. + // The combo must be determined through either the beatmap's max combo value or the difficulty calculator, as lazer's scoring has changed and the score statistics cannot be used. + if (score.BeatmapInfo.MaxCombo != null) + return score.BeatmapInfo.MaxCombo.Value; + + if (difficulties == null) + return null; + + // We can compute the max combo locally after the async beatmap difficulty computation. + var difficulty = await difficulties().GetDifficultyAsync(score.BeatmapInfo, score.Ruleset, score.Mods, cancellationToken).ConfigureAwait(false); + return difficulty?.MaxCombo; + } + + // This is guaranteed to be a non-legacy score. + // The combo must be determined through the score's statistics, as both the beatmap's max combo and the difficulty calculator will provide osu!stable combo values. + return Enum.GetValues(typeof(HitResult)).OfType().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetValueOrDefault(r)).Sum(); } /// From eca7975864911eb8d13062b113cc779928afcded Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 20 Mar 2022 05:33:35 +0300 Subject: [PATCH 082/131] Compute the beatmap maximum achievable combo instead of `Beatmap.MaxCombo` --- .../Ranking/Expanded/ExpandedPanelMiddleContent.cs | 8 +++++--- .../Screens/Ranking/Expanded/Statistics/ComboStatistic.cs | 5 ++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 1b1aa3a684..1d80bcbbe6 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -65,10 +65,12 @@ namespace osu.Game.Screens.Ranking.Expanded var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata; string creator = metadata.Author.Username; + int? beatmapMaxCombo = scoreManager.GetBeatmapMaximumComboAsync(score).GetResultSafely(); + var topStatistics = new List { new AccuracyStatistic(score.Accuracy), - new ComboStatistic(score.MaxCombo, beatmap.MaxCombo, score.Statistics.All(stat => !stat.Key.BreaksCombo() || stat.Value == 0)), + new ComboStatistic(score.MaxCombo, beatmapMaxCombo), new PerformanceStatistic(score), }; @@ -80,8 +82,6 @@ namespace osu.Game.Screens.Ranking.Expanded statisticDisplays.AddRange(topStatistics); statisticDisplays.AddRange(bottomStatistics); - var starDifficulty = beatmapDifficultyCache.GetDifficultyAsync(beatmap, score.Ruleset, score.Mods).GetResultSafely(); - AddInternal(new FillFlowContainer { RelativeSizeAxes = Axes.Both, @@ -224,6 +224,8 @@ namespace osu.Game.Screens.Ranking.Expanded if (score.Date != default) AddInternal(new PlayedOnText(score.Date)); + var starDifficulty = beatmapDifficultyCache.GetDifficultyAsync(beatmap, score.Ruleset, score.Mods).GetResultSafely(); + if (starDifficulty != null) { starAndModDisplay.Add(new StarRatingDisplay(starDifficulty.Value) diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs index 67d580270d..0e42ec026a 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs @@ -26,11 +26,10 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics /// /// The combo to be displayed. /// The maximum value of . - /// Whether this is a perfect combo. - public ComboStatistic(int combo, int? maxCombo, bool isPerfect) + public ComboStatistic(int combo, int? maxCombo) : base("combo", combo, maxCombo) { - this.isPerfect = isPerfect; + isPerfect = combo == maxCombo; } public override void Appear() From 7529d6fc0078197d0f58e1c5fa0dc6cd3855a921 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 20 Mar 2022 06:23:42 +0300 Subject: [PATCH 083/131] Bind queue items during playlist initialization Along with where the other bindables are bound together (only bind, not listening). --- .../Multiplayer/Match/Playlist/MultiplayerPlaylist.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs index 77076bd1cc..879a21e7c1 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs @@ -64,13 +64,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist } } }; + + playlistTabControl.QueueItems.BindTarget = queueList.Items; } protected override void LoadComplete() { base.LoadComplete(); DisplayMode.BindValueChanged(onDisplayModeChanged, true); - playlistTabControl.QueueItems.BindTarget = queueList.Items; } private void onDisplayModeChanged(ValueChangedEvent mode) From e1d22e58bfbd03c6d8c198460711860ae1c23fb1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 20 Mar 2022 06:25:07 +0300 Subject: [PATCH 084/131] Simplify queue count text logic --- .../Match/Playlist/MultiplayerPlaylistTabControl.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs index 882a96c877..583a05839f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs @@ -32,12 +32,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist protected override void LoadComplete() { base.LoadComplete(); - QueueItems.BindCollectionChanged((_,__) => - { - Text.Text = $"Queue"; - if (QueueItems.Count != 0) - Text.Text += $" ({QueueItems.Count})"; - }, true); + QueueItems.BindCollectionChanged((_, __) => Text.Text = QueueItems.Count > 0 ? $"Queue ({QueueItems.Count})" : "Queue", true); } } } From 2a78042038da441a2d4cfa8b72b130fd182d2949 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 20 Mar 2022 16:18:53 +0300 Subject: [PATCH 085/131] `GetBeatmapMaximumComboAsync` -> `GetMaximumAchievableComboAsync` --- osu.Game/Scoring/ScoreManager.cs | 6 +++--- .../Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 0f3c991f07..e6bfe284cb 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -134,7 +134,7 @@ namespace osu.Game.Scoring if (string.IsNullOrEmpty(score.BeatmapInfo.MD5Hash)) return score.TotalScore; - int? beatmapMaxCombo = await GetBeatmapMaximumComboAsync(score, cancellationToken).ConfigureAwait(false); + int? beatmapMaxCombo = await GetMaximumAchievableComboAsync(score, cancellationToken).ConfigureAwait(false); if (beatmapMaxCombo == null) return score.TotalScore; @@ -149,12 +149,12 @@ namespace osu.Game.Scoring } /// - /// Retrieves the maximum achievable combo on the beatmap of the provided score. + /// Retrieves the maximum achievable combo for the provided score. /// /// The to compute the maximum achievable combo for. /// A to cancel the process. /// The maximum achievable combo. - public async Task GetBeatmapMaximumComboAsync([NotNull] ScoreInfo score, CancellationToken cancellationToken = default) + public async Task GetMaximumAchievableComboAsync([NotNull] ScoreInfo score, CancellationToken cancellationToken = default) { if (score.IsLegacyScore) { diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 1d80bcbbe6..5b3129dad6 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -65,7 +65,7 @@ namespace osu.Game.Screens.Ranking.Expanded var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata; string creator = metadata.Author.Username; - int? beatmapMaxCombo = scoreManager.GetBeatmapMaximumComboAsync(score).GetResultSafely(); + int? beatmapMaxCombo = scoreManager.GetMaximumAchievableComboAsync(score).GetResultSafely(); var topStatistics = new List { From aef40da8d4d39f80f9566b658e3d4918176c7316 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 20 Mar 2022 16:24:29 +0300 Subject: [PATCH 086/131] Add note about null return value --- osu.Game/Scoring/ScoreManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index e6bfe284cb..371cbbf597 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -153,7 +153,7 @@ namespace osu.Game.Scoring /// /// The to compute the maximum achievable combo for. /// A to cancel the process. - /// The maximum achievable combo. + /// The maximum achievable combo. A return value indicates the difficulty cache has failed to retrieve the combo. public async Task GetMaximumAchievableComboAsync([NotNull] ScoreInfo score, CancellationToken cancellationToken = default) { if (score.IsLegacyScore) From c2063f415d674338066a31e93617f505aa71eed9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 20 Mar 2022 16:27:54 +0300 Subject: [PATCH 087/131] Remove unnecessary `MaxCombo` migration between unmapped database fields --- osu.Game/Beatmaps/EFBeatmapInfo.cs | 3 --- osu.Game/Database/EFToRealmMigrator.cs | 1 - 2 files changed, 4 deletions(-) diff --git a/osu.Game/Beatmaps/EFBeatmapInfo.cs b/osu.Game/Beatmaps/EFBeatmapInfo.cs index 8daeaa7030..740adfd1c7 100644 --- a/osu.Game/Beatmaps/EFBeatmapInfo.cs +++ b/osu.Game/Beatmaps/EFBeatmapInfo.cs @@ -53,9 +53,6 @@ namespace osu.Game.Beatmaps [NotMapped] public APIBeatmap OnlineInfo { get; set; } - [NotMapped] - public int? MaxCombo { get; set; } - /// /// The playable length in milliseconds of this beatmap. /// diff --git a/osu.Game/Database/EFToRealmMigrator.cs b/osu.Game/Database/EFToRealmMigrator.cs index c9deee19fe..cbf5c5ffe9 100644 --- a/osu.Game/Database/EFToRealmMigrator.cs +++ b/osu.Game/Database/EFToRealmMigrator.cs @@ -295,7 +295,6 @@ namespace osu.Game.Database TimelineZoom = beatmap.TimelineZoom, Countdown = beatmap.Countdown, CountdownOffset = beatmap.CountdownOffset, - MaxCombo = beatmap.MaxCombo, Bookmarks = beatmap.Bookmarks, BeatmapSet = realmBeatmapSet, }; From 6f47f7ffc886f608df86c00d36790e57c8a95c37 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 20 Mar 2022 16:29:56 +0300 Subject: [PATCH 088/131] Remove no longer necessary `MaxCombo` assignment in tests --- osu.Game.Tests/Resources/TestResources.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs index 00bb02a937..81b624f908 100644 --- a/osu.Game.Tests/Resources/TestResources.cs +++ b/osu.Game.Tests/Resources/TestResources.cs @@ -133,7 +133,6 @@ namespace osu.Game.Tests.Resources StarRating = diff, Length = length, BPM = bpm, - MaxCombo = 1000, Hash = Guid.NewGuid().ToString().ComputeMD5Hash(), Ruleset = rulesetInfo, Metadata = metadata, From b9859f9f215f129ec89e9d17bf0677187d8c7e54 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 20 Mar 2022 16:30:28 +0300 Subject: [PATCH 089/131] Obsolete `BeatmapInfo.MaxCombo` and suppress in usages --- osu.Game/Beatmaps/BeatmapInfo.cs | 3 ++- osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs | 2 ++ osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs | 2 ++ osu.Game/Scoring/ScoreInfo.cs | 2 +- osu.Game/Scoring/ScoreManager.cs | 2 ++ 5 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 5a2cfd63cf..f90208d0c0 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -172,9 +172,10 @@ namespace osu.Game.Beatmaps /// /// The maximum achievable combo on this beatmap, populated for online info purposes only. - /// Todo: This should never be used nor exist, but is still relied on in since can't be used yet. + /// Todo: This should never be used nor exist, but is still relied on in since can't be used yet. For now this is obsoleted until it is removed. /// [Ignored] + [Obsolete("Use ScoreManager.GetMaximumAchievableComboAsync instead.")] public int? MaxCombo { get; set; } [Ignored] diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index 5ef434c427..86e72e9faa 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -173,7 +173,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { Text = score.MaxCombo.ToLocalisableString(@"0\x"), Font = OsuFont.GetFont(size: text_size), +#pragma warning disable 618 Colour = score.MaxCombo == score.BeatmapInfo.MaxCombo ? highAccuracyColour : Color4.White +#pragma warning restore 618 } }; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 6f07b20049..7d59c95396 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -78,7 +78,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores // TODO: temporary. should be removed once `OrderByTotalScore` can accept `IScoreInfo`. var beatmapInfo = new BeatmapInfo { +#pragma warning disable 618 MaxCombo = apiBeatmap.MaxCombo, +#pragma warning restore 618 Status = apiBeatmap.Status, MD5Hash = apiBeatmap.MD5Hash }; diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index 4de1d580dc..d7185a1677 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -157,7 +157,7 @@ namespace osu.Game.Scoring public LocalisableString DisplayAccuracy => Accuracy.FormatAccuracy(); /// - /// Whether this represents a legacy (osu!stable) score. + /// Whether this represents a legacy (osu!stable) score. /// [Ignored] public bool IsLegacyScore => Mods.OfType().Any(); diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 371cbbf597..83359838aa 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -160,8 +160,10 @@ namespace osu.Game.Scoring { // This score is guaranteed to be an osu!stable score. // The combo must be determined through either the beatmap's max combo value or the difficulty calculator, as lazer's scoring has changed and the score statistics cannot be used. +#pragma warning disable CS0618 if (score.BeatmapInfo.MaxCombo != null) return score.BeatmapInfo.MaxCombo.Value; +#pragma warning restore CS0618 if (difficulties == null) return null; From 35e2e6a4e75eb2ab8e1ba9bc30d357971977f88d Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Sun, 20 Mar 2022 15:41:46 +0000 Subject: [PATCH 090/131] Remove slider tick judgement flag --- osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs index 70459dc432..f9450062f4 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs @@ -14,14 +14,12 @@ namespace osu.Game.Rulesets.Osu.Objects /// public class SliderTailCircle : SliderEndCircle { - public bool JudgeAsSliderTick = false; - public SliderTailCircle(Slider slider) : base(slider) { } - public override Judgement CreateJudgement() => JudgeAsSliderTick ? (OsuJudgement)new SliderTickJudgement() : new SliderTailJudgement(); + public override Judgement CreateJudgement() => new SliderTailJudgement(); public class SliderTailJudgement : OsuJudgement { From d3742a91a80262ef7038665e6de01a3bb81f5060 Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Sun, 20 Mar 2022 15:56:41 +0000 Subject: [PATCH 091/131] Nest specific object classes within the mod --- .../StrictTrackingDrawableSliderTail.cs | 12 --- .../Mods/Objects/StrictTrackingSlider.cs | 70 ---------------- .../Objects/StrictTrackingSliderTailCircle.cs | 19 ----- .../Mods/OsuModStrictTracking.cs | 81 ++++++++++++++++++- 4 files changed, 80 insertions(+), 102 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs delete mode 100644 osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs delete mode 100644 osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs diff --git a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs deleted file mode 100644 index 110b09f4f9..0000000000 --- a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Rulesets.Osu.Objects.Drawables; - -namespace osu.Game.Rulesets.Osu.Mods.Objects -{ - public class StrictTrackingDrawableSliderTail : DrawableSliderTail - { - public override bool DisplayResult => true; - } -} diff --git a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs deleted file mode 100644 index bf0a57d871..0000000000 --- a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs +++ /dev/null @@ -1,70 +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.Threading; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Osu.Objects; - -namespace osu.Game.Rulesets.Osu.Mods.Objects -{ - public class StrictTrackingSlider : Slider - { - public StrictTrackingSlider(Slider original) - { - StartTime = original.StartTime; - Samples = original.Samples; - Path = original.Path; - NodeSamples = original.NodeSamples; - RepeatCount = original.RepeatCount; - Position = original.Position; - NewCombo = original.NewCombo; - ComboOffset = original.ComboOffset; - LegacyLastTickOffset = original.LegacyLastTickOffset; - TickDistanceMultiplier = original.TickDistanceMultiplier; - } - - protected override void CreateNestedHitObjects(CancellationToken cancellationToken) - { - var sliderEvents = SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, cancellationToken); - - foreach (var e in sliderEvents) - { - switch (e.Type) - { - case SliderEventType.Head: - AddNested(HeadCircle = new SliderHeadCircle - { - StartTime = e.Time, - Position = Position, - StackHeight = StackHeight, - }); - break; - - case SliderEventType.LegacyLastTick: - AddNested(TailCircle = new StrictTrackingSliderTailCircle(this) - { - RepeatIndex = e.SpanIndex, - StartTime = e.Time, - Position = EndPosition, - StackHeight = StackHeight - }); - break; - - case SliderEventType.Repeat: - AddNested(new SliderRepeat(this) - { - RepeatIndex = e.SpanIndex, - StartTime = StartTime + (e.SpanIndex + 1) * SpanDuration, - Position = Position + Path.PositionAt(e.PathProgress), - StackHeight = StackHeight, - Scale = Scale, - }); - break; - } - } - - UpdateNestedSamples(); - } - } -} diff --git a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs deleted file mode 100644 index 7d93f2cf39..0000000000 --- a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Osu.Judgements; -using osu.Game.Rulesets.Osu.Objects; - -namespace osu.Game.Rulesets.Osu.Mods.Objects -{ - public class StrictTrackingSliderTailCircle : SliderTailCircle - { - public StrictTrackingSliderTailCircle(Slider slider) - : base(slider) - { - } - - public override Judgement CreateJudgement() => new OsuJudgement(); - } -} diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs index b8d7134e5f..ee325db66a 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -3,12 +3,16 @@ using System; using System.Linq; +using System.Threading; using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps; +using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Beatmaps; -using osu.Game.Rulesets.Osu.Mods.Objects; +using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.UI; @@ -65,5 +69,80 @@ namespace osu.Game.Rulesets.Osu.Mods { drawableRuleset.Playfield.RegisterPool(10, 100); } + + private class StrictTrackingSliderTailCircle : SliderTailCircle + { + public StrictTrackingSliderTailCircle(Slider slider) + : base(slider) + { + } + + public override Judgement CreateJudgement() => new OsuJudgement(); + } + + private class StrictTrackingDrawableSliderTail : DrawableSliderTail + { + public override bool DisplayResult => true; + } + + private class StrictTrackingSlider : Slider + { + public StrictTrackingSlider(Slider original) + { + StartTime = original.StartTime; + Samples = original.Samples; + Path = original.Path; + NodeSamples = original.NodeSamples; + RepeatCount = original.RepeatCount; + Position = original.Position; + NewCombo = original.NewCombo; + ComboOffset = original.ComboOffset; + LegacyLastTickOffset = original.LegacyLastTickOffset; + TickDistanceMultiplier = original.TickDistanceMultiplier; + } + + protected override void CreateNestedHitObjects(CancellationToken cancellationToken) + { + var sliderEvents = SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, cancellationToken); + + foreach (var e in sliderEvents) + { + switch (e.Type) + { + case SliderEventType.Head: + AddNested(HeadCircle = new SliderHeadCircle + { + StartTime = e.Time, + Position = Position, + StackHeight = StackHeight, + }); + break; + + case SliderEventType.LegacyLastTick: + AddNested(TailCircle = new StrictTrackingSliderTailCircle(this) + { + RepeatIndex = e.SpanIndex, + StartTime = e.Time, + Position = EndPosition, + StackHeight = StackHeight + }); + break; + + case SliderEventType.Repeat: + AddNested(new SliderRepeat(this) + { + RepeatIndex = e.SpanIndex, + StartTime = StartTime + (e.SpanIndex + 1) * SpanDuration, + Position = Position + Path.PositionAt(e.PathProgress), + StackHeight = StackHeight, + Scale = Scale, + }); + break; + } + } + + UpdateNestedSamples(); + } + } } } From 8fbdd068951bf1f213f396aaa57fe51498a7c194 Mon Sep 17 00:00:00 2001 From: hwabis Date: Sun, 20 Mar 2022 16:24:41 -0400 Subject: [PATCH 092/131] add queue tab count test --- .../TestSceneMultiplayerPlaylist.cs | 31 +++++++++++++++++++ .../Graphics/UserInterface/OsuTabControl.cs | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs index 6b5b45b73e..af17458649 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Rulesets; @@ -129,6 +130,25 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("item 1 not in lists", () => !inHistoryList(0) && !inQueueList(0)); } + [Test] + public void TestTabQueueListCount() + { + assertQueueTabCount(1); + + addItemStep(); + assertQueueTabCount(2); + + addItemStep(); + assertQueueTabCount(3); + + AddStep("finish current item", () => MultiplayerClient.FinishCurrentItem().WaitSafely()); + assertQueueTabCount(2); + + AddStep("leave room", () => RoomManager.PartRoom()); + AddUntilStep("wait for room part", () => !RoomJoined); + assertQueueTabCount(0); + } + [Ignore("Expired items are initially removed from the room.")] [Test] public void TestJoinRoomWithMixedItemsAddedInCorrectLists() @@ -213,6 +233,17 @@ namespace osu.Game.Tests.Visual.Multiplayer }); } + private void assertQueueTabCount(int count) + { + string queueTabText = count > 0 ? $"Queue ({count})" : "Queue"; + AddUntilStep($"Queue tab shows \"{queueTabText}\"", () => + { + return this.ChildrenOfType.OsuTabItem>() + .First() + .Text.Text.Equals(queueTabText); + }); + } + private void changeDisplayModeStep(MultiplayerPlaylistDisplayMode mode) => AddStep($"change list to {mode}", () => list.DisplayMode.Value = mode); private bool inQueueList(int playlistItemId) diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs index 3572ea5c31..ab03669207 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs @@ -98,7 +98,7 @@ namespace osu.Game.Graphics.UserInterface public class OsuTabItem : TabItem, IHasAccentColour { - protected readonly SpriteText Text; + public readonly SpriteText Text; protected readonly Box Bar; private Color4 accentColour; From 63b668638462a9e92af2b1a1bb1d150ed540b6e3 Mon Sep 17 00:00:00 2001 From: hwabis Date: Sun, 20 Mar 2022 16:28:05 -0400 Subject: [PATCH 093/131] make test name clearer --- .../Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs index af17458649..15b626ceeb 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs @@ -131,7 +131,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - public void TestTabQueueListCount() + public void TestQueueTabCount() { assertQueueTabCount(1); From 06136b2247c81868cb69ad3497fb681cc4e0e89d Mon Sep 17 00:00:00 2001 From: hwabis Date: Sun, 20 Mar 2022 21:37:02 -0400 Subject: [PATCH 094/131] Revert OsuTabItem Text to protected, update tab count test --- .../Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs | 5 +++-- osu.Game/Graphics/UserInterface/OsuTabControl.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs index 15b626ceeb..cbd8b472b8 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; @@ -239,8 +240,8 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep($"Queue tab shows \"{queueTabText}\"", () => { return this.ChildrenOfType.OsuTabItem>() - .First() - .Text.Text.Equals(queueTabText); + .Single(t => t.Value == MultiplayerPlaylistDisplayMode.Queue) + .ChildrenOfType().Single().Text == queueTabText; }); } diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs index ab03669207..3572ea5c31 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs @@ -98,7 +98,7 @@ namespace osu.Game.Graphics.UserInterface public class OsuTabItem : TabItem, IHasAccentColour { - public readonly SpriteText Text; + protected readonly SpriteText Text; protected readonly Box Bar; private Color4 accentColour; From 355b0fa3144915016411b3b26b931e5734d45da9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 13:49:55 +0900 Subject: [PATCH 095/131] Fix loading player via skin editor still allowing changing current audio track `PlayerLoader` is required in the sequence to get the game into the correct state for gameplay right now. Applying ths simplest fix here. Closes https://github.com/ppy/osu/issues/17351. --- osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs index 5da6147e4c..eac13922d7 100644 --- a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs @@ -94,7 +94,7 @@ namespace osu.Game.Skinning.Editor var replayGeneratingMod = ruleset.Value.CreateInstance().GetAutoplayMod(); if (replayGeneratingMod != null) - screen.Push(new ReplayPlayer((beatmap, mods) => replayGeneratingMod.CreateReplayScore(beatmap, mods))); + screen.Push(new PlayerLoader(() => new ReplayPlayer((beatmap, mods) => replayGeneratingMod.CreateReplayScore(beatmap, mods)))); }, new[] { typeof(Player), typeof(SongSelect) }) }, } From f922a6b55607148c40189e29b6f3447fb1773dcc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 14:15:22 +0900 Subject: [PATCH 096/131] Rename renaming button/pill classes --- osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs | 6 +++--- ...hannelListItemClose.cs => ChannelListItemCloseButton.cs} | 2 +- ...nnelListItemMention.cs => ChannelListItemMentionPill.cs} | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename osu.Game/Overlays/Chat/ChannelList/{ChannelListItemClose.cs => ChannelListItemCloseButton.cs} (93%) rename osu.Game/Overlays/Chat/ChannelList/{ChannelListItemMention.cs => ChannelListItemMentionPill.cs} (96%) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs index 583493181b..006cfdea3b 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs @@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Chat.ChannelList private Box? hoverBox; private Box? selectBox; private OsuSpriteText? text; - private ChannelListItemClose? close; + private ChannelListItemCloseButton? close; [Resolved] private Bindable selectedChannel { get; set; } = null!; @@ -97,14 +97,14 @@ namespace osu.Game.Overlays.Chat.ChannelList RelativeSizeAxes = Axes.X, Truncate = true, }, - new ChannelListItemMention + new ChannelListItemMentionPill { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Margin = new MarginPadding { Right = 3 }, Mentions = { BindTarget = Mentions }, }, - close = new ChannelListItemClose + close = new ChannelListItemCloseButton { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItemClose.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs similarity index 93% rename from osu.Game/Overlays/Chat/ChannelList/ChannelListItemClose.cs rename to osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs index 37a1fcdde7..3e595093b4 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItemClose.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Overlays.Chat.ChannelList { - public class ChannelListItemClose : OsuAnimatedButton + public class ChannelListItemCloseButton : OsuAnimatedButton { [BackgroundDependencyLoader] private void load(OsuColour osuColour) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItemMention.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemMentionPill.cs similarity index 96% rename from osu.Game/Overlays/Chat/ChannelList/ChannelListItemMention.cs rename to osu.Game/Overlays/Chat/ChannelList/ChannelListItemMentionPill.cs index 3a1c3b7619..165756cfcd 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItemMention.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemMentionPill.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Overlays.Chat.ChannelList { - public class ChannelListItemMention : CircularContainer + public class ChannelListItemMentionPill : CircularContainer { public readonly BindableInt Mentions = new BindableInt(); From 9eda2f2df126f28079b05e9c87955fb08dd63364 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 14:25:29 +0900 Subject: [PATCH 097/131] Remove box surrounding close button --- .../ChannelList/ChannelListItemCloseButton.cs | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs index 3e595093b4..a5876c8ad8 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs @@ -6,28 +6,63 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.Containers; using osuTK; +using osuTK.Graphics; namespace osu.Game.Overlays.Chat.ChannelList { - public class ChannelListItemCloseButton : OsuAnimatedButton + public class ChannelListItemCloseButton : OsuClickableContainer { + private SpriteIcon icon = null!; + + private Color4 normalColour; + private Color4 hoveredColour; + [BackgroundDependencyLoader] private void load(OsuColour osuColour) { + normalColour = osuColour.Red2; + hoveredColour = Color4.White; + Alpha = 0f; Size = new Vector2(20); - Add(new SpriteIcon + Add(icon = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, Scale = new Vector2(0.75f), Icon = FontAwesome.Solid.TimesCircle, RelativeSizeAxes = Axes.Both, - Colour = osuColour.Red1, + Colour = normalColour, }); } + + // Transforms matching OsuAnimatedButton + protected override bool OnHover(HoverEvent e) + { + icon.FadeColour(hoveredColour, 300, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + icon.FadeColour(normalColour, 300, Easing.OutQuint); + base.OnHoverLost(e); + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + icon.ScaleTo(0.75f, 2000, Easing.OutQuint); + return base.OnMouseDown(e); + } + + protected override void OnMouseUp(MouseUpEvent e) + { + icon.ScaleTo(1, 1000, Easing.OutElastic); + base.OnMouseUp(e); + } } } From 11b050b66b66d189c9f84a740709ff72b7674aa2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 14:28:12 +0900 Subject: [PATCH 098/131] Add slight fade when hovering `ChannelListItem`s --- osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs index 006cfdea3b..9dc0529ce4 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs @@ -140,15 +140,15 @@ namespace osu.Game.Overlays.Chat.ChannelList protected override bool OnHover(HoverEvent e) { - hoverBox?.Show(); - close?.Show(); + hoverBox?.FadeIn(300, Easing.OutQuint); + close?.FadeIn(300, Easing.OutQuint); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - hoverBox?.Hide(); - close?.Hide(); + hoverBox?.FadeOut(200, Easing.OutQuint); + close?.FadeOut(200, Easing.OutQuint); base.OnHoverLost(e); } From 692362131ef80b4990d2b7437c5b10c818513b02 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 14:31:51 +0900 Subject: [PATCH 099/131] Add animation when mention pill appears (or a new message arrives) --- .../Chat/ChannelList/ChannelListItemMentionPill.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItemMentionPill.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemMentionPill.cs index 165756cfcd..5018c8cd64 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItemMentionPill.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemMentionPill.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osuTK; +using osuTK.Graphics; namespace osu.Game.Overlays.Chat.ChannelList { @@ -20,6 +21,8 @@ namespace osu.Game.Overlays.Chat.ChannelList private OsuSpriteText countText = null!; + private Box box = null!; + [BackgroundDependencyLoader] private void load(OsuColour osuColour, OverlayColourProvider colourProvider) { @@ -29,7 +32,7 @@ namespace osu.Game.Overlays.Chat.ChannelList Children = new Drawable[] { - new Box + box = new Box { RelativeSizeAxes = Axes.Both, Colour = osuColour.Orange1, @@ -56,9 +59,12 @@ namespace osu.Game.Overlays.Chat.ChannelList countText.Text = mentionCount > 99 ? "99+" : mentionCount.ToString(); if (mentionCount > 0) - Show(); + { + this.FadeIn(1000, Easing.OutQuint); + box.FlashColour(Color4.White, 500, Easing.OutQuint); + } else - Hide(); + this.FadeOut(100, Easing.OutQuint); }, true); } } From 5104e4db21ef5eec39bf463ea59cc2f1dfafc96f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 14:33:50 +0900 Subject: [PATCH 100/131] Add step to `TestSceneChannelListItem` to actually select an item --- osu.Game.Tests/Visual/Online/TestSceneChannelListItem.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelListItem.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelListItem.cs index ac829f8cbc..af419c8b91 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelListItem.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelListItem.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -114,6 +115,8 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestVisual() { + AddStep("Select second item", () => selected.Value = channels.Skip(1).First()); + AddStep("Unread Selected", () => { if (selected.Value != null) From 16caf2d30b989917100589f6fe072354995bf9b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 14:34:54 +0900 Subject: [PATCH 101/131] Add slight animation when highlighting an unread channel --- osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs index 9dc0529ce4..8cf37fd0d5 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs @@ -134,7 +134,7 @@ namespace osu.Game.Overlays.Chat.ChannelList Unread.BindValueChanged(change => { - text!.Colour = change.NewValue ? colourProvider.Content1 : colourProvider.Light3; + text!.FadeColour(change.NewValue ? colourProvider.Content1 : colourProvider.Light3, 300, Easing.OutQuint); }, true); } From 428e439f40e1a1c0c4cf665d3e3138ebe785ec34 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 14:36:55 +0900 Subject: [PATCH 102/131] Remove space between '#' and channel name This was in flyte's design (he was following discord) but doesn't feel too correct when it's not aligned with anything else. We can revisit this if/when we have better glyphs to represent channel types. --- osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs index 8cf37fd0d5..f3bbe101de 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs @@ -90,7 +90,7 @@ namespace osu.Game.Overlays.Chat.ChannelList { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Text = channel.Type == ChannelType.Public ? $"# {channel.Name.Substring(1)}" : channel.Name, + Text = channel.Name, Font = OsuFont.Torus.With(size: 17, weight: FontWeight.SemiBold), Colour = colourProvider.Light3, Margin = new MarginPadding { Bottom = 2 }, From 7ca3beb7cc5ef647e51a1d2aa9f858b25c44cedd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 14:41:42 +0900 Subject: [PATCH 103/131] Also add fade to `ChannelItem` selected box --- osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs index f3bbe101de..43574351ed 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs @@ -127,9 +127,9 @@ namespace osu.Game.Overlays.Chat.ChannelList selectedChannel.BindValueChanged(change => { if (change.NewValue == channel) - selectBox?.Show(); + selectBox?.FadeIn(300, Easing.OutQuint); else - selectBox?.Hide(); + selectBox?.FadeOut(200, Easing.OutQuint); }, true); Unread.BindValueChanged(change => From 3bb01fd59583939aa46e5e8e18189375cc222d24 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 14:41:57 +0900 Subject: [PATCH 104/131] Fix close button animation not being applied correct on mouse down due to conflicting scales --- .../Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs index a5876c8ad8..65b9c4a79b 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Chat.ChannelList { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Scale = new Vector2(0.75f), + Size = new Vector2(0.75f), Icon = FontAwesome.Solid.TimesCircle, RelativeSizeAxes = Axes.Both, Colour = normalColour, From b42081dd9bca5e574fa6fe0b0af576a99a53ffa2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 16:06:32 +0900 Subject: [PATCH 105/131] Add `DangerousButton` for use in popup dialogs --- .../UserInterface/TestScenePopupDialog.cs | 4 ++ .../Graphics/UserInterface/DialogButton.cs | 19 +++--- .../Dialog/PopupDialogDangerousButton.cs | 59 +++++++++++++++++++ 3 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs index 8e53c7c402..6bd6115e68 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs @@ -40,6 +40,10 @@ namespace osu.Game.Tests.Visual.UserInterface { Text = @"You're a fake!", }, + new PopupDialogDangerousButton + { + Text = @"Careful with this one..", + }, }; } } diff --git a/osu.Game/Graphics/UserInterface/DialogButton.cs b/osu.Game/Graphics/UserInterface/DialogButton.cs index 2f9e4dae51..ad69ec4078 100644 --- a/osu.Game/Graphics/UserInterface/DialogButton.cs +++ b/osu.Game/Graphics/UserInterface/DialogButton.cs @@ -45,8 +45,9 @@ namespace osu.Game.Graphics.UserInterface } } + protected readonly Container ColourContainer; + private readonly Container backgroundContainer; - private readonly Container colourContainer; private readonly Container glowContainer; private readonly Box leftGlow; private readonly Box centerGlow; @@ -113,7 +114,7 @@ namespace osu.Game.Graphics.UserInterface Masking = true, Children = new Drawable[] { - colourContainer = new Container + ColourContainer = new Container { RelativeSizeAxes = Axes.Both, Origin = Anchor.Centre, @@ -182,7 +183,7 @@ namespace osu.Game.Graphics.UserInterface { buttonColour = value; updateGlow(); - colourContainer.Colour = value; + ColourContainer.Colour = value; } } @@ -230,11 +231,11 @@ namespace osu.Game.Graphics.UserInterface Alpha = 0.05f }; - colourContainer.Add(flash); + ColourContainer.Add(flash); flash.FadeOutFromOne(100).Expire(); clickAnimating = true; - colourContainer.ResizeWidthTo(colourContainer.Width * 1.05f, 100, Easing.OutQuint) + ColourContainer.ResizeWidthTo(ColourContainer.Width * 1.05f, 100, Easing.OutQuint) .OnComplete(_ => { clickAnimating = false; @@ -246,14 +247,14 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnMouseDown(MouseDownEvent e) { - colourContainer.ResizeWidthTo(hover_width * 0.98f, click_duration * 4, Easing.OutQuad); + ColourContainer.ResizeWidthTo(hover_width * 0.98f, click_duration * 4, Easing.OutQuad); return base.OnMouseDown(e); } protected override void OnMouseUp(MouseUpEvent e) { if (State == SelectionState.Selected) - colourContainer.ResizeWidthTo(hover_width, click_duration, Easing.In); + ColourContainer.ResizeWidthTo(hover_width, click_duration, Easing.In); base.OnMouseUp(e); } @@ -279,12 +280,12 @@ namespace osu.Game.Graphics.UserInterface if (newState == SelectionState.Selected) { spriteText.TransformSpacingTo(hoverSpacing, hover_duration, Easing.OutElastic); - colourContainer.ResizeWidthTo(hover_width, hover_duration, Easing.OutElastic); + ColourContainer.ResizeWidthTo(hover_width, hover_duration, Easing.OutElastic); glowContainer.FadeIn(hover_duration, Easing.OutQuint); } else { - colourContainer.ResizeWidthTo(idle_width, hover_duration, Easing.OutElastic); + ColourContainer.ResizeWidthTo(idle_width, hover_duration, Easing.OutElastic); spriteText.TransformSpacingTo(Vector2.Zero, hover_duration, Easing.OutElastic); glowContainer.FadeOut(hover_duration, Easing.OutQuint); } diff --git a/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs new file mode 100644 index 0000000000..1911a4fa56 --- /dev/null +++ b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs @@ -0,0 +1,59 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; + +namespace osu.Game.Overlays.Dialog +{ + public class PopupDialogDangerousButton : PopupDialogButton + { + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + ButtonColour = colours.Red3; + + ColourContainer.Add(new ConfirmFillBox + { + Action = () => Action(), + RelativeSizeAxes = Axes.Both, + Blending = BlendingParameters.Additive, + }); + } + + private class ConfirmFillBox : HoldToConfirmContainer + { + private Box box; + + protected override double? HoldActivationDelay => 500; + + protected override void LoadComplete() + { + base.LoadComplete(); + + Child = box = new Box + { + RelativeSizeAxes = Axes.Both, + }; + + Progress.BindValueChanged(progress => box.Width = (float)progress.NewValue, true); + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + BeginConfirm(); + return true; + } + + protected override void OnMouseUp(MouseUpEvent e) + { + if (!e.HasAnyButtonPressed) + AbortConfirm(); + } + } + } +} From d811a70f4b42cb638a6cc6be169acfb0f99275f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 16:06:58 +0900 Subject: [PATCH 106/131] Change button types on editor exit dialog to match purpose Addresses https://github.com/ppy/osu/discussions/17363. --- osu.Game/Screens/Edit/PromptForSaveDialog.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/PromptForSaveDialog.cs b/osu.Game/Screens/Edit/PromptForSaveDialog.cs index e308a9533d..4f70491ade 100644 --- a/osu.Game/Screens/Edit/PromptForSaveDialog.cs +++ b/osu.Game/Screens/Edit/PromptForSaveDialog.cs @@ -17,12 +17,12 @@ namespace osu.Game.Screens.Edit Buttons = new PopupDialogButton[] { - new PopupDialogCancelButton + new PopupDialogOkButton { Text = @"Save my masterpiece!", Action = saveAndExit }, - new PopupDialogOkButton + new PopupDialogDangerousButton { Text = @"Forget all changes", Action = exit From 36868dbdb4d8f480ebbbd68d268c4e35c8fd4ba0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 16:07:26 +0900 Subject: [PATCH 107/131] Add the ability to override the user setting for hold-to-confirm containers Sometimes the user is not right. --- .../Graphics/Containers/HoldToConfirmContainer.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs index 999dd183aa..b2f08eee0a 100644 --- a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs +++ b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs @@ -28,6 +28,14 @@ namespace osu.Game.Graphics.Containers /// protected virtual bool AllowMultipleFires => false; + /// + /// Specify a custom activation delay, overriding the game-wide user setting. + /// + /// + /// This should be used in special cases where we want to be extra sure the user knows what they are doing. An example is when changes would be lost. + /// + protected virtual double? HoldActivationDelay => null; + public Bindable Progress = new BindableDouble(); private Bindable holdActivationDelay; @@ -35,7 +43,9 @@ namespace osu.Game.Graphics.Containers [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - holdActivationDelay = config.GetBindable(OsuSetting.UIHoldActivationDelay); + holdActivationDelay = HoldActivationDelay != null + ? new Bindable(HoldActivationDelay.Value) + : config.GetBindable(OsuSetting.UIHoldActivationDelay); } protected void BeginConfirm() From 3643f879e42fda75f2e2308c098f7fa2fbcf1bd8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 17:01:46 +0900 Subject: [PATCH 108/131] Add test coverage of skin editor settings slider not working via keyboard adjustments --- .../Visual/Gameplay/TestSceneSkinEditor.cs | 37 ++++++++- .../Navigation/TestSceneScreenNavigation.cs | 77 ++++++++++++++++++- .../Skinning/Editor/SkinEditorSceneLibrary.cs | 3 +- 3 files changed, 113 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs index e74345aae9..38d83058c0 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs @@ -1,14 +1,19 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; using osu.Game.Overlays; +using osu.Game.Overlays.Settings; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Play.HUD.HitErrorMeters; using osu.Game.Skinning.Editor; +using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { @@ -29,7 +34,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("reload skin editor", () => { skinEditor?.Expire(); - Player.ScaleTo(0.8f); + Player.ScaleTo(0.4f); LoadComponentAsync(skinEditor = new SkinEditor(Player), Add); }); } @@ -40,6 +45,36 @@ namespace osu.Game.Tests.Visual.Gameplay AddToggleStep("toggle editor visibility", visible => skinEditor.ToggleVisibility()); } + [Test] + public void TestEditComponent() + { + BarHitErrorMeter hitErrorMeter = null; + + AddStep("select bar hit error blueprint", () => + { + var blueprint = skinEditor.ChildrenOfType().First(b => b.Item is BarHitErrorMeter); + + hitErrorMeter = (BarHitErrorMeter)blueprint.Item; + skinEditor.SelectedComponents.Clear(); + skinEditor.SelectedComponents.Add(blueprint.Item); + }); + + AddAssert("value is default", () => hitErrorMeter.JudgementLineThickness.IsDefault); + + AddStep("hover first slider", () => + { + InputManager.MoveMouseTo( + skinEditor.ChildrenOfType().First() + .ChildrenOfType>().First() + .ChildrenOfType>().First() + ); + }); + + AddStep("adjust slider via keyboard", () => InputManager.Key(Key.Left)); + + AddAssert("value is less than default", () => hitErrorMeter.JudgementLineThickness.Value < hitErrorMeter.JudgementLineThickness.Default); + } + protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); } } diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index f2e6aa1e16..46266e844a 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; @@ -14,6 +15,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.Leaderboards; using osu.Game.Overlays; using osu.Game.Overlays.Mods; +using osu.Game.Overlays.Settings; using osu.Game.Overlays.Toolbar; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; @@ -21,10 +23,12 @@ using osu.Game.Scoring; using osu.Game.Screens.Menu; using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD.HitErrorMeters; using osu.Game.Screens.Ranking; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Leaderboards; using osu.Game.Screens.Select.Options; +using osu.Game.Skinning.Editor; using osu.Game.Tests.Beatmaps.IO; using osuTK; using osuTK.Input; @@ -66,6 +70,73 @@ namespace osu.Game.Tests.Visual.Navigation AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible); } + [Test] + public void TestEditComponentDuringGameplay() + { + Screens.Select.SongSelect songSelect = null; + PushAndConfirm(() => songSelect = new TestPlaySongSelect()); + AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded); + + AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely()); + + AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault); + + SkinEditor skinEditor = null; + + AddStep("open skin editor", () => + { + InputManager.PressKey(Key.ControlLeft); + InputManager.PressKey(Key.ShiftLeft); + InputManager.Key(Key.S); + InputManager.ReleaseKey(Key.ControlLeft); + InputManager.ReleaseKey(Key.ShiftLeft); + }); + + AddUntilStep("get skin editor", () => (skinEditor = Game.ChildrenOfType().FirstOrDefault()) != null); + + AddStep("Click gameplay scene button", () => + { + skinEditor.ChildrenOfType().First(b => b.Text == "Gameplay").TriggerClick(); + }); + + AddUntilStep("wait for player", () => + { + // dismiss any notifications that may appear (ie. muted notification). + clickMouseInCentre(); + return Game.ScreenStack.CurrentScreen is Player; + }); + + BarHitErrorMeter hitErrorMeter = null; + + AddUntilStep("select bar hit error blueprint", () => + { + var blueprint = skinEditor.ChildrenOfType().FirstOrDefault(b => b.Item is BarHitErrorMeter); + + if (blueprint == null) + return false; + + hitErrorMeter = (BarHitErrorMeter)blueprint.Item; + skinEditor.SelectedComponents.Clear(); + skinEditor.SelectedComponents.Add(blueprint.Item); + return true; + }); + + AddAssert("value is default", () => hitErrorMeter.JudgementLineThickness.IsDefault); + + AddStep("hover first slider", () => + { + InputManager.MoveMouseTo( + skinEditor.ChildrenOfType().First() + .ChildrenOfType>().First() + .ChildrenOfType>().First() + ); + }); + + AddStep("adjust slider via keyboard", () => InputManager.Key(Key.Left)); + + AddAssert("value is less than default", () => hitErrorMeter.JudgementLineThickness.Value < hitErrorMeter.JudgementLineThickness.Default); + } + [Test] public void TestRetryCountIncrements() { @@ -120,7 +191,8 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("press back button", () => Game.ChildrenOfType().First().Action()); - AddStep("show local scores", () => Game.ChildrenOfType().First().Current.Value = new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local)); + AddStep("show local scores", + () => Game.ChildrenOfType().First().Current.Value = new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local)); AddUntilStep("wait for score displayed", () => (scorePanel = Game.ChildrenOfType().FirstOrDefault(s => s.Score.Equals(score))) != null); @@ -152,7 +224,8 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("press back button", () => Game.ChildrenOfType().First().Action()); - AddStep("show local scores", () => Game.ChildrenOfType().First().Current.Value = new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local)); + AddStep("show local scores", + () => Game.ChildrenOfType().First().Current.Value = new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local)); AddUntilStep("wait for score displayed", () => (scorePanel = Game.ChildrenOfType().FirstOrDefault(s => s.Score.Equals(score))) != null); diff --git a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs index eac13922d7..4a7cce5a97 100644 --- a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Screens; +using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -104,7 +105,7 @@ namespace osu.Game.Skinning.Editor }; } - private class SceneButton : OsuButton + public class SceneButton : OsuButton { public SceneButton() { From 2f18c512cd48d594876f9222bb33bc9ca281468c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 16:52:06 +0900 Subject: [PATCH 109/131] Convert `SkinEditorOverlay` to an `OverlayContainer` to allow it to block input --- osu.Game/OsuGame.cs | 4 +++ .../Overlays/Settings/Sections/SkinSection.cs | 2 +- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 30 +++++++------------ 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 25bd3d71de..4cd954a646 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1046,6 +1046,10 @@ namespace osu.Game switch (e.Action) { + case GlobalAction.ToggleSkinEditor: + skinEditor.ToggleVisibility(); + return true; + case GlobalAction.ResetInputSettings: Host.ResetInputHandlers(); frameworkConfig.GetBindable(FrameworkSetting.ConfineMouseMode).SetDefault(); diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 475c4bff8d..a34776ddf0 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -64,7 +64,7 @@ namespace osu.Game.Overlays.Settings.Sections new SettingsButton { Text = SkinSettingsStrings.SkinLayoutEditor, - Action = () => skinEditor?.Toggle(), + Action = () => skinEditor?.ToggleVisibility(), }, new ExportSkinButton(), }; diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 9fc233d3e3..970a27285e 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -19,10 +19,12 @@ namespace osu.Game.Skinning.Editor /// A container which handles loading a skin editor on user request for a specified target. /// This also handles the scaling / positioning adjustment of the target. /// - public class SkinEditorOverlay : CompositeDrawable, IKeyBindingHandler + public class SkinEditorOverlay : OverlayContainer, IKeyBindingHandler { private readonly ScalingContainer scalingContainer; + protected override bool BlockNonPositionalInput => true; + [CanBeNull] private SkinEditor skinEditor; @@ -49,30 +51,12 @@ namespace osu.Game.Skinning.Editor Hide(); return true; - - case GlobalAction.ToggleSkinEditor: - Toggle(); - return true; } return false; } - public void Toggle() - { - if (skinEditor == null) - Show(); - else - skinEditor.ToggleVisibility(); - } - - public override void Hide() - { - // base call intentionally omitted. - skinEditor?.Hide(); - } - - public override void Show() + protected override void PopIn() { // base call intentionally omitted as we have custom behaviour. @@ -106,6 +90,12 @@ namespace osu.Game.Skinning.Editor }); } + protected override void PopOut() + { + // base call intentionally omitted. + skinEditor?.Hide(); + } + private void updateComponentVisibility() { Debug.Assert(skinEditor != null); From 2a696783af33c7af24f100cb68598d080acaa6b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 17:32:56 +0900 Subject: [PATCH 110/131] Remove unused const in `SkinEditorOverlay` --- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 970a27285e..f848c07680 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -28,8 +28,6 @@ namespace osu.Game.Skinning.Editor [CanBeNull] private SkinEditor skinEditor; - public const float VISIBLE_TARGET_SCALE = 0.8f; - [Resolved(canBeNull: true)] private OsuGame game { get; set; } From ed66f86ac6073ee655025ddfbddb9726b6cba2a8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 17:52:54 +0900 Subject: [PATCH 111/131] Update editor exit-without-safe tests to account for hold behaviour --- .../Editing/TestSceneEditorBeatmapCreation.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index ecd4035edd..b109234fec 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -13,6 +13,7 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Database; +using osu.Game.Overlays.Dialog; using osu.Game.Rulesets; using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Osu; @@ -23,6 +24,7 @@ using osu.Game.Screens.Edit.Setup; using osu.Game.Storyboards; using osu.Game.Tests.Resources; using osuTK; +using osuTK.Input; using SharpCompress.Archives; using SharpCompress.Archives.Zip; @@ -63,13 +65,19 @@ namespace osu.Game.Tests.Visual.Editing EditorBeatmap editorBeatmap = null; AddStep("store editor beatmap", () => editorBeatmap = EditorBeatmap); - AddStep("exit without save", () => + + AddStep("exit without save", () => Editor.Exit()); + AddStep("hold to confirm", () => { - Editor.Exit(); - DialogOverlay.CurrentDialog.PerformOkAction(); + var confirmButton = DialogOverlay.CurrentDialog.ChildrenOfType().First(); + + InputManager.MoveMouseTo(confirmButton); + InputManager.PressButton(MouseButton.Left); }); AddUntilStep("wait for exit", () => !Editor.IsCurrentScreen()); + AddStep("release", () => InputManager.ReleaseButton(MouseButton.Left)); + AddAssert("new beatmap not persisted", () => beatmapManager.QueryBeatmapSet(s => s.ID == editorBeatmap.BeatmapInfo.BeatmapSet.ID)?.Value.DeletePending == true); } From e4b2242719456749a8b7d828e1194551d18db7c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 18:29:13 +0900 Subject: [PATCH 112/131] Fix follow point animations not looping Because they do in stable. I don't know why but let's go with it. Resolves issue reported in https://github.com/ppy/osu/discussions/17072. --- .../Skinning/Legacy/OsuLegacySkinTransformer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index ff9f6f0e07..900ad6f6d3 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy switch (osuComponent.Component) { case OsuSkinComponents.FollowPoint: - return this.GetAnimation(component.LookupName, true, false, true, startAtCurrentTime: false); + return this.GetAnimation(component.LookupName, true, true, true, startAtCurrentTime: false); case OsuSkinComponents.SliderFollowCircle: var followCircle = this.GetAnimation("sliderfollowcircle", true, true, true); From 058fbbbe6cc0b3422f50a495b7b09dc5049cff1d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 21 Mar 2022 14:06:36 +0300 Subject: [PATCH 113/131] Remove unused using directive --- osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs index 4a7cce5a97..d126eff075 100644 --- a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Screens; -using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; From 33acc5d720c94eb1754759adc2d3a6079ee9de88 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 21 Mar 2022 14:06:47 +0300 Subject: [PATCH 114/131] Remove no longer valid comments --- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index f848c07680..819b0cbc6c 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -56,8 +56,6 @@ namespace osu.Game.Skinning.Editor protected override void PopIn() { - // base call intentionally omitted as we have custom behaviour. - if (skinEditor != null) { skinEditor.Show(); @@ -88,11 +86,7 @@ namespace osu.Game.Skinning.Editor }); } - protected override void PopOut() - { - // base call intentionally omitted. - skinEditor?.Hide(); - } + protected override void PopOut() => skinEditor?.Hide(); private void updateComponentVisibility() { From 9a2691c1bc0b8bf1578996a1cd0a56eb6b865f2f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Mar 2022 23:54:47 +0900 Subject: [PATCH 115/131] Remove unnecessary schedule --- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 819b0cbc6c..1a427d5f5d 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -63,26 +63,22 @@ namespace osu.Game.Skinning.Editor } var editor = new SkinEditor(); + editor.State.BindValueChanged(visibility => updateComponentVisibility()); skinEditor = editor; - // Schedule ensures that if `Show` is called before this overlay is loaded, - // it will not throw (LoadComponentAsync requires the load target to be in a loaded state). - Schedule(() => + if (editor != skinEditor) + return; + + LoadComponentAsync(editor, _ => { if (editor != skinEditor) return; - LoadComponentAsync(editor, _ => - { - if (editor != skinEditor) - return; + AddInternal(editor); - AddInternal(editor); - - SetTarget(lastTargetScreen); - }); + SetTarget(lastTargetScreen); }); } From 17b639b4045974c255e8525b8f6cdfb6ade74373 Mon Sep 17 00:00:00 2001 From: NAGILSON Date: Mon, 21 Mar 2022 22:42:17 -0400 Subject: [PATCH 116/131] Implement suggested change to wipe mods on multiplayer screen --- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index bf1699dca0..c56d04d5ac 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -115,6 +115,8 @@ namespace osu.Game.Screens.OnlinePlay this.FadeIn(); waves.Show(); + Mods.SetDefault(); + if (loungeSubScreen.IsCurrentScreen()) loungeSubScreen.OnEntering(last); else From 74ce009ed8ce926041f4fa60ba0467783761bb59 Mon Sep 17 00:00:00 2001 From: NAGILSON Date: Mon, 21 Mar 2022 22:46:20 -0400 Subject: [PATCH 117/131] [WIP] Multiplayer Mods Regression Test --- .../Multiplayer/TestMultiplayerModLoading.cs | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs new file mode 100644 index 0000000000..e9013af412 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs @@ -0,0 +1,52 @@ +// 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 NUnit.Framework; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Screens.Select; + +// Resolve these names to types because there is a Namespace called "Playlists" and "Multiplayer" which conflicts +using MultiplayerScreenAlias = osu.Game.Screens.OnlinePlay.Multiplayer.Multiplayer; +using PlaylistsScreenAlias = osu.Game.Screens.OnlinePlay.Playlists.Playlists; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestMultiplayerModLoading : OsuGameTestScene + { + + [SetUp] + public void SetUp() => Schedule(() => + { + SelectedMods.Value = Array.Empty(); + }); + + + /// + /// This is a regression test that tests whether a singleplayer mod can transfer over to a multiplayer screen. + /// It should not carry over from these screens, prevents regression on https://github.com/ppy/osu/pull/17352 + /// + [Test] + public void TestSingleplayerModsDontCarryToMultiplayerScreens() + { + PushAndConfirm(() => new PlaySongSelect()); + + // Select Mods while a "singleplayer" screen is active + var osuAutomationMod = new OsuModAutoplay(); + var expectedMods = new[] { osuAutomationMod }; + + AddStep("Toggle on the automation Mod.", () => { SelectedMods.Value = expectedMods; }); + AddAssert("", () => SelectedMods.Value == expectedMods); + + PushAndConfirm(() => new TestMultiplayerComponents()); + AddAssert("Mods are Empty After A Multiplayer Screen Loads", () => SelectedMods.Value.Count == 0); + + AddStep("Retoggle on the automation Mod.", () => { SelectedMods.Value = expectedMods; }); + AddAssert("", () => SelectedMods.Value == expectedMods); + + // TODO: Implement TestPlaylistComponents? + //PushAndConfirm(() => new TestPlaylistComponents()); + //AddAssert("Mods are Empty After Playlist Screen Loads", () => !SelectedMods.Value.Any()); + } + } +} From aaf2edace9d43e9cadfcfb874ef5d8a68be660f6 Mon Sep 17 00:00:00 2001 From: NAGILSON Date: Mon, 21 Mar 2022 22:48:08 -0400 Subject: [PATCH 118/131] remove code from old incorrect test --- .../Visual/Multiplayer/TestMultiplayerModLoading.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs index e9013af412..b5609a2841 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs @@ -6,10 +6,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.Select; -// Resolve these names to types because there is a Namespace called "Playlists" and "Multiplayer" which conflicts -using MultiplayerScreenAlias = osu.Game.Screens.OnlinePlay.Multiplayer.Multiplayer; -using PlaylistsScreenAlias = osu.Game.Screens.OnlinePlay.Playlists.Playlists; - namespace osu.Game.Tests.Visual.Multiplayer { public class TestMultiplayerModLoading : OsuGameTestScene From 33d97f53cbb5184939e8fde48d40acc3155b8925 Mon Sep 17 00:00:00 2001 From: NAGILSON Date: Mon, 21 Mar 2022 22:58:53 -0400 Subject: [PATCH 119/131] Fill in assert details, remove whitespace --- .../Visual/Multiplayer/TestMultiplayerModLoading.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs index b5609a2841..7c2353513d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs @@ -10,14 +10,12 @@ namespace osu.Game.Tests.Visual.Multiplayer { public class TestMultiplayerModLoading : OsuGameTestScene { - [SetUp] public void SetUp() => Schedule(() => { SelectedMods.Value = Array.Empty(); }); - /// /// This is a regression test that tests whether a singleplayer mod can transfer over to a multiplayer screen. /// It should not carry over from these screens, prevents regression on https://github.com/ppy/osu/pull/17352 @@ -32,13 +30,13 @@ namespace osu.Game.Tests.Visual.Multiplayer var expectedMods = new[] { osuAutomationMod }; AddStep("Toggle on the automation Mod.", () => { SelectedMods.Value = expectedMods; }); - AddAssert("", () => SelectedMods.Value == expectedMods); + AddAssert("Mods are loaded before the multiplayer screen is pushed.", () => SelectedMods.Value == expectedMods); PushAndConfirm(() => new TestMultiplayerComponents()); AddAssert("Mods are Empty After A Multiplayer Screen Loads", () => SelectedMods.Value.Count == 0); AddStep("Retoggle on the automation Mod.", () => { SelectedMods.Value = expectedMods; }); - AddAssert("", () => SelectedMods.Value == expectedMods); + AddAssert("Mods are loaded before the playlist screen is pushed", () => SelectedMods.Value == expectedMods); // TODO: Implement TestPlaylistComponents? //PushAndConfirm(() => new TestPlaylistComponents()); From 0fcb3bdba9a4591407ee1415a582ac4e1f0d3682 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Mar 2022 14:10:21 +0900 Subject: [PATCH 120/131] Fix beatmap date added not being updated on reimporting a soft deleted beatmap Addresses concerns raised in https://github.com/ppy/osu/discussions/17399. --- osu.Game.Tests/Database/BeatmapImporterTests.cs | 6 ++++++ osu.Game/Stores/BeatmapImporter.cs | 6 ++++++ osu.Game/Stores/RealmArchiveModelImporter.cs | 16 ++++++++++++++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index 9d67381b5a..9abd78039a 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -590,6 +590,8 @@ namespace osu.Game.Tests.Database Assert.IsTrue(imported.DeletePending); + var originalAddedDate = imported.DateAdded; + var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm); // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash. @@ -597,6 +599,7 @@ namespace osu.Game.Tests.Database Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID); Assert.IsFalse(imported.DeletePending); Assert.IsFalse(importedSecondTime.DeletePending); + Assert.That(importedSecondTime.DateAdded, Is.GreaterThan(originalAddedDate)); }); } @@ -646,6 +649,8 @@ namespace osu.Game.Tests.Database Assert.IsTrue(imported.DeletePending); + var originalAddedDate = imported.DateAdded; + var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm); // check the newly "imported" beatmap is actually just the restored previous import. since it matches hash. @@ -653,6 +658,7 @@ namespace osu.Game.Tests.Database Assert.IsTrue(imported.Beatmaps.First().ID == importedSecondTime.Beatmaps.First().ID); Assert.IsFalse(imported.DeletePending); Assert.IsFalse(importedSecondTime.DeletePending); + Assert.That(importedSecondTime.DateAdded, Is.GreaterThan(originalAddedDate)); }); } diff --git a/osu.Game/Stores/BeatmapImporter.cs b/osu.Game/Stores/BeatmapImporter.cs index e6b655589c..f04a0210ef 100644 --- a/osu.Game/Stores/BeatmapImporter.cs +++ b/osu.Game/Stores/BeatmapImporter.cs @@ -163,6 +163,12 @@ namespace osu.Game.Stores return existing.OnlineID == import.OnlineID && existingIds.SequenceEqual(importIds); } + protected override void UndeleteForReuse(BeatmapSetInfo existing) + { + base.UndeleteForReuse(existing); + existing.DateAdded = DateTimeOffset.UtcNow; + } + public override bool IsAvailableLocally(BeatmapSetInfo model) { return Realm.Run(realm => realm.All().Any(s => s.OnlineID == model.OnlineID)); diff --git a/osu.Game/Stores/RealmArchiveModelImporter.cs b/osu.Game/Stores/RealmArchiveModelImporter.cs index 3011bc0320..1d0e16d549 100644 --- a/osu.Game/Stores/RealmArchiveModelImporter.cs +++ b/osu.Game/Stores/RealmArchiveModelImporter.cs @@ -351,7 +351,8 @@ namespace osu.Game.Stores using (var transaction = realm.BeginWrite()) { - existing.DeletePending = false; + if (existing.DeletePending) + UndeleteForReuse(existing); transaction.Commit(); } @@ -387,7 +388,9 @@ namespace osu.Game.Stores { LogForModel(item, @$"Found existing {HumanisedModelName} for {item} (ID {existing.ID}) – skipping import."); - existing.DeletePending = false; + if (existing.DeletePending) + UndeleteForReuse(existing); + transaction.Commit(); return existing.ToLive(Realm); @@ -527,6 +530,15 @@ namespace osu.Game.Stores private bool checkAllFilesExist(TModel model) => model.Files.All(f => Files.Storage.Exists(f.File.GetStoragePath())); + /// + /// Called when an existing model is in a soft deleted state but being recovered. + /// + /// The existing model. + protected virtual void UndeleteForReuse(TModel existing) + { + existing.DeletePending = false; + } + /// /// Whether this specified path should be removed after successful import. /// From fb7f9a81db99bd547b64c26f331d1dca47c24c11 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Mar 2022 14:35:13 +0900 Subject: [PATCH 121/131] Remove unnecessary equality check in skin editor construction path --- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 1a427d5f5d..497283a820 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -68,9 +68,6 @@ namespace osu.Game.Skinning.Editor skinEditor = editor; - if (editor != skinEditor) - return; - LoadComponentAsync(editor, _ => { if (editor != skinEditor) From f95bd8916693ea04a5afb17867cfcbc85709777f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Mar 2022 14:46:57 +0900 Subject: [PATCH 122/131] Revert editor exit behaviour to exit without changes for now --- osu.Game/Overlays/Dialog/PopupDialog.cs | 7 ++++++- osu.Game/Screens/Edit/Editor.cs | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 0f953f92bb..a70a7f26cc 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -219,7 +219,12 @@ namespace osu.Game.Overlays.Dialog /// /// Programmatically clicks the first . /// - public void PerformOkAction() => Buttons.OfType().First().TriggerClick(); + public void PerformOkAction() => PerformAction(); + + /// + /// Programmatically clicks the first button of the provided type. + /// + public void PerformAction() where T : PopupDialogButton => Buttons.OfType().First().TriggerClick(); protected override bool OnKeyDown(KeyDownEvent e) { diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index dcb7e3a282..444b2fe6f9 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -28,6 +28,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Online.API; using osu.Game.Overlays; +using osu.Game.Overlays.Dialog; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; @@ -598,7 +599,7 @@ namespace osu.Game.Screens.Edit // if the dialog is already displayed, confirm exit with no save. if (dialogOverlay.CurrentDialog is PromptForSaveDialog saveDialog) { - saveDialog.PerformOkAction(); + saveDialog.PerformAction(); return true; } From 61ddf1e6cf90a9fb9041afdc9335ac57205b6b83 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Mar 2022 15:28:31 +0900 Subject: [PATCH 123/131] Disallow exiting the editor without saving (unless explicitly confirming) --- .../Visual/Editing/TestSceneEditorSaving.cs | 7 +++++++ osu.Game/Screens/Edit/Editor.cs | 13 +++++-------- osu.Game/Tests/Visual/EditorTestScene.cs | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs index d1c1558003..e75c7f25a3 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs @@ -17,6 +17,13 @@ namespace osu.Game.Tests.Visual.Editing { public class TestSceneEditorSaving : EditorSavingTestScene { + [Test] + public void TestCantExitWithoutSaving() + { + AddRepeatStep("Exit", () => InputManager.Key(Key.Escape), 10); + AddAssert("Editor is still active screen", () => Game.ScreenStack.CurrentScreen is Editor); + } + [Test] public void TestMetadata() { diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 444b2fe6f9..7254a9140f 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -98,7 +98,7 @@ namespace osu.Game.Screens.Edit private bool canSave; - private bool exitConfirmed; + protected bool ExitConfirmed { get; private set; } private string lastSavedHash; @@ -587,7 +587,7 @@ namespace osu.Game.Screens.Edit public override bool OnExiting(IScreen next) { - if (!exitConfirmed) + if (!ExitConfirmed) { // dialog overlay may not be available in visual tests. if (dialogOverlay == null) @@ -596,12 +596,9 @@ namespace osu.Game.Screens.Edit return true; } - // if the dialog is already displayed, confirm exit with no save. + // if the dialog is already displayed, block exiting until the user explicitly makes a decision. if (dialogOverlay.CurrentDialog is PromptForSaveDialog saveDialog) - { - saveDialog.PerformAction(); return true; - } if (isNewBeatmap || HasUnsavedChanges) { @@ -646,7 +643,7 @@ namespace osu.Game.Screens.Edit { Save(); - exitConfirmed = true; + ExitConfirmed = true; this.Exit(); } @@ -669,7 +666,7 @@ namespace osu.Game.Screens.Edit Beatmap.SetDefault(); } - exitConfirmed = true; + ExitConfirmed = true; this.Exit(); } diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 24015590e2..efaf6f2253 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -7,10 +7,13 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.IO.Stores; using osu.Framework.Platform; +using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Online.API; +using osu.Game.Overlays; +using osu.Game.Overlays.Dialog; using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit; @@ -93,6 +96,9 @@ namespace osu.Game.Tests.Visual protected class TestEditor : Editor { + [Resolved(canBeNull: true)] + private DialogOverlay dialogOverlay { get; set; } + public new void Undo() => base.Undo(); public new void Redo() => base.Redo(); @@ -111,6 +117,18 @@ namespace osu.Game.Tests.Visual public new bool HasUnsavedChanges => base.HasUnsavedChanges; + public override bool OnExiting(IScreen next) + { + // For testing purposes allow the screen to exit without saving on second attempt. + if (!ExitConfirmed && dialogOverlay.CurrentDialog is PromptForSaveDialog saveDialog) + { + saveDialog.PerformAction(); + return true; + } + + return base.OnExiting(next); + } + public TestEditor(EditorLoader loader = null) : base(loader) { From 804e8561607630f59380659e8cf3e85ce79eb88d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Mar 2022 17:38:43 +0900 Subject: [PATCH 124/131] Move and refactor test in line with functionality changes --- .../Multiplayer/TestMultiplayerModLoading.cs | 46 ------------------- .../Navigation/TestSceneScreenNavigation.cs | 14 ++++++ 2 files changed, 14 insertions(+), 46 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs deleted file mode 100644 index 7c2353513d..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerModLoading.cs +++ /dev/null @@ -1,46 +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 NUnit.Framework; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.Select; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - public class TestMultiplayerModLoading : OsuGameTestScene - { - [SetUp] - public void SetUp() => Schedule(() => - { - SelectedMods.Value = Array.Empty(); - }); - - /// - /// This is a regression test that tests whether a singleplayer mod can transfer over to a multiplayer screen. - /// It should not carry over from these screens, prevents regression on https://github.com/ppy/osu/pull/17352 - /// - [Test] - public void TestSingleplayerModsDontCarryToMultiplayerScreens() - { - PushAndConfirm(() => new PlaySongSelect()); - - // Select Mods while a "singleplayer" screen is active - var osuAutomationMod = new OsuModAutoplay(); - var expectedMods = new[] { osuAutomationMod }; - - AddStep("Toggle on the automation Mod.", () => { SelectedMods.Value = expectedMods; }); - AddAssert("Mods are loaded before the multiplayer screen is pushed.", () => SelectedMods.Value == expectedMods); - - PushAndConfirm(() => new TestMultiplayerComponents()); - AddAssert("Mods are Empty After A Multiplayer Screen Loads", () => SelectedMods.Value.Count == 0); - - AddStep("Retoggle on the automation Mod.", () => { SelectedMods.Value = expectedMods; }); - AddAssert("Mods are loaded before the playlist screen is pushed", () => SelectedMods.Value == expectedMods); - - // TODO: Implement TestPlaylistComponents? - //PushAndConfirm(() => new TestPlaylistComponents()); - //AddAssert("Mods are Empty After Playlist Screen Loads", () => !SelectedMods.Value.Any()); - } - } -} diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index f2e6aa1e16..7e1ff08678 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -262,6 +262,20 @@ namespace osu.Game.Tests.Visual.Navigation exitViaBackButtonAndConfirm(); } + [Test] + public void TestModsResetOnEnteringMultiplayer() + { + var osuAutomationMod = new OsuModAutoplay(); + + AddStep("Enable autoplay", () => { Game.SelectedMods.Value = new[] { osuAutomationMod }; }); + + PushAndConfirm(() => new Screens.OnlinePlay.Multiplayer.Multiplayer()); + AddUntilStep("Mods are removed", () => SelectedMods.Value.Count == 0); + + AddStep("Return to menu", () => Game.ScreenStack.CurrentScreen.Exit()); + AddUntilStep("Mods are restored", () => Game.SelectedMods.Value.Contains(osuAutomationMod)); + } + [Test] public void TestExitMultiWithEscape() { From 5631726164afcc70f323f570454c6ebe3e300b1c Mon Sep 17 00:00:00 2001 From: mcpower Date: Tue, 22 Mar 2022 20:30:54 +1100 Subject: [PATCH 125/131] Add C# extension to recommended VS Code extensions The [official C# extension] is maintained by Microsoft and enables IDE-like support for C# in VS Code. If a user opens this repository in VS Code, they will be prompted to install it if they haven't already installed it. After installation, the extension will also prompt the user to install the .NET SDK if it's not found. [official C# extension]: https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp --- .vscode/extensions.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .vscode/extensions.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000..5b7a98f4ba --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "ms-dotnettools.csharp" + ] +} From 94c5207f36f162a9a52e5234f12660c5004afbc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Mar 2022 19:04:32 +0100 Subject: [PATCH 126/131] Fix test not actually testing desired scenario anymore The test was checking the test scene's own `SelectedMods` bindable rather than the multiplayer screen's, and the former was never actually being mutated by anything. Therefore the case would pass even on `master` with the fix reverted. --- .../Visual/Navigation/TestSceneScreenNavigation.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 7e1ff08678..034c1b7581 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -269,8 +269,9 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("Enable autoplay", () => { Game.SelectedMods.Value = new[] { osuAutomationMod }; }); - PushAndConfirm(() => new Screens.OnlinePlay.Multiplayer.Multiplayer()); - AddUntilStep("Mods are removed", () => SelectedMods.Value.Count == 0); + Screens.OnlinePlay.Multiplayer.Multiplayer multiplayer = null; + PushAndConfirm(() => multiplayer = new Screens.OnlinePlay.Multiplayer.Multiplayer()); + AddUntilStep("Mods are removed", () => multiplayer.Mods.Value.Count == 0); AddStep("Return to menu", () => Game.ScreenStack.CurrentScreen.Exit()); AddUntilStep("Mods are restored", () => Game.SelectedMods.Value.Contains(osuAutomationMod)); From c8d48f89e8a7b7a30af2be41c4ef2590cc41b21e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Mar 2022 19:13:22 +0100 Subject: [PATCH 127/131] Remove unnecessary local --- .../Visual/Navigation/TestSceneScreenNavigation.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 034c1b7581..e4535b6cd6 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -269,9 +269,8 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("Enable autoplay", () => { Game.SelectedMods.Value = new[] { osuAutomationMod }; }); - Screens.OnlinePlay.Multiplayer.Multiplayer multiplayer = null; - PushAndConfirm(() => multiplayer = new Screens.OnlinePlay.Multiplayer.Multiplayer()); - AddUntilStep("Mods are removed", () => multiplayer.Mods.Value.Count == 0); + PushAndConfirm(() => new Screens.OnlinePlay.Multiplayer.Multiplayer()); + AddUntilStep("Mods are removed", () => Game.SelectedMods.Value.Count == 0); AddStep("Return to menu", () => Game.ScreenStack.CurrentScreen.Exit()); AddUntilStep("Mods are restored", () => Game.SelectedMods.Value.Contains(osuAutomationMod)); From a38bafab912108a86bea2411350f4413da450af1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Mar 2022 22:00:05 +0100 Subject: [PATCH 128/131] Remove unused using directive --- osu.Game/Screens/Edit/Editor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 7254a9140f..4d5e491c60 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -28,7 +28,6 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Online.API; using osu.Game.Overlays; -using osu.Game.Overlays.Dialog; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; From f3aad772399cb786147c3adb9b9d487beada0a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Mar 2022 22:00:24 +0100 Subject: [PATCH 129/131] Remove unused local variable --- osu.Game/Screens/Edit/Editor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 4d5e491c60..57f7429e06 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -596,7 +596,7 @@ namespace osu.Game.Screens.Edit } // if the dialog is already displayed, block exiting until the user explicitly makes a decision. - if (dialogOverlay.CurrentDialog is PromptForSaveDialog saveDialog) + if (dialogOverlay.CurrentDialog is PromptForSaveDialog) return true; if (isNewBeatmap || HasUnsavedChanges) From 51a1721bc942b71b768faae474d1a2eaa52a1dc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Mar 2022 22:10:05 +0100 Subject: [PATCH 130/131] Fix unprotected access to potentially-null DI'd dialog overlay --- osu.Game/Tests/Visual/EditorTestScene.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index efaf6f2253..51221cb8fe 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -97,6 +97,7 @@ namespace osu.Game.Tests.Visual protected class TestEditor : Editor { [Resolved(canBeNull: true)] + [CanBeNull] private DialogOverlay dialogOverlay { get; set; } public new void Undo() => base.Undo(); @@ -120,7 +121,7 @@ namespace osu.Game.Tests.Visual public override bool OnExiting(IScreen next) { // For testing purposes allow the screen to exit without saving on second attempt. - if (!ExitConfirmed && dialogOverlay.CurrentDialog is PromptForSaveDialog saveDialog) + if (!ExitConfirmed && dialogOverlay?.CurrentDialog is PromptForSaveDialog saveDialog) { saveDialog.PerformAction(); return true; From 657daf07d745626681d4998eaa84193e8dad43e2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Mar 2022 11:03:24 +0900 Subject: [PATCH 131/131] Update LocalisationAnalyser to support .net6 --- .config/dotnet-tools.json | 2 +- osu.Game/osu.Game.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 985fc09df3..4177c402aa 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -27,7 +27,7 @@ ] }, "ppy.localisationanalyser.tools": { - "version": "2021.1210.0", + "version": "2022.320.0", "commands": [ "localisation" ] diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 5e194e2aca..1c1deaae8e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -31,7 +31,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive