From f3eaa950416971ccfd10f8e492c4b8b61b53e92d Mon Sep 17 00:00:00 2001 From: Susko3 <16479013+Susko3@users.noreply.github.com> Date: Fri, 14 Jan 2022 23:16:07 +0100 Subject: [PATCH 001/211] Move input handler settings creation to `OsuGameBase` --- osu.Desktop/OsuGameDesktop.cs | 25 +++++++++++ osu.Game/OsuGameBase.cs | 21 ++++++++++ .../Settings/Sections/InputSection.cs | 41 ++----------------- 3 files changed, 49 insertions(+), 38 deletions(-) diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index b234207848..a0c2a80bb8 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -20,8 +20,15 @@ using osu.Framework.Screens; using osu.Game.Screens.Menu; using osu.Game.Updater; using osu.Desktop.Windows; +using osu.Framework.Input.Handlers; +using osu.Framework.Input.Handlers.Joystick; +using osu.Framework.Input.Handlers.Mouse; +using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Threading; using osu.Game.IO; +using osu.Game.Overlays.Settings; +using osu.Game.Overlays.Settings.Sections; +using osu.Game.Overlays.Settings.Sections.Input; namespace osu.Desktop { @@ -156,6 +163,24 @@ namespace osu.Desktop desktopWindow.DragDrop += f => fileDrop(new[] { f }); } + public override SettingsSubsection CreateSettingsSubsectionFor(InputHandler handler) + { + switch (handler) + { + case ITabletHandler th: + return new TabletSettings(th); + + case MouseHandler mh: + return new MouseSettings(mh); + + case JoystickHandler _: + return new InputSection.HandlerSection(handler); + + default: + return base.CreateSettingsSubsectionFor(handler); + } + } + private readonly List importableFiles = new List(); private ScheduledDelegate importSchedule; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 9256514a0a..0059fc2204 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -17,6 +17,8 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Performance; using osu.Framework.Graphics.Textures; using osu.Framework.Input; +using osu.Framework.Input.Handlers; +using osu.Framework.Input.Handlers.Midi; using osu.Framework.IO.Stores; using osu.Framework.Logging; using osu.Framework.Platform; @@ -35,6 +37,8 @@ using osu.Game.Online.Chat; using osu.Game.Online.Multiplayer; using osu.Game.Online.Spectator; using osu.Game.Overlays; +using osu.Game.Overlays.Settings; +using osu.Game.Overlays.Settings.Sections; using osu.Game.Resources; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -448,6 +452,23 @@ namespace osu.Game protected override Storage CreateStorage(GameHost host, Storage defaultStorage) => new OsuStorage(host, defaultStorage); + /// + /// Creates an input settings subsection for an . + /// + /// Should be overriden per-platform to provide settings for platform-specific handlers. + public virtual SettingsSubsection CreateSettingsSubsectionFor(InputHandler handler) + { + switch (handler) + { + case MidiHandler _: + return new InputSection.HandlerSection(handler); + + // return null for handlers that shouldn't have settings. + default: + return null; + } + } + private void onRulesetChanged(ValueChangedEvent r) { if (r.NewValue?.Available != true) diff --git a/osu.Game/Overlays/Settings/Sections/InputSection.cs b/osu.Game/Overlays/Settings/Sections/InputSection.cs index d282ba5318..77076ae920 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSection.cs @@ -5,10 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Handlers; -using osu.Framework.Input.Handlers.Joystick; -using osu.Framework.Input.Handlers.Midi; -using osu.Framework.Input.Handlers.Mouse; -using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Game.Localisation; @@ -22,9 +18,6 @@ namespace osu.Game.Overlays.Settings.Sections public override LocalisableString Header => InputSettingsStrings.InputSectionHeader; - [Resolved] - private GameHost host { get; set; } - public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.Solid.Keyboard @@ -36,7 +29,7 @@ namespace osu.Game.Overlays.Settings.Sections } [BackgroundDependencyLoader] - private void load() + private void load(GameHost host, OsuGameBase game) { Children = new Drawable[] { @@ -45,42 +38,14 @@ namespace osu.Game.Overlays.Settings.Sections foreach (var handler in host.AvailableInputHandlers) { - var handlerSection = createSectionFor(handler); + var handlerSection = game.CreateSettingsSubsectionFor(handler); if (handlerSection != null) Add(handlerSection); } } - private SettingsSubsection createSectionFor(InputHandler handler) - { - SettingsSubsection section; - - switch (handler) - { - // ReSharper disable once SuspiciousTypeConversion.Global (net standard fuckery) - case ITabletHandler th: - section = new TabletSettings(th); - break; - - case MouseHandler mh: - section = new MouseSettings(mh); - break; - - // whitelist the handlers which should be displayed to avoid any weird cases of users touching settings they shouldn't. - case JoystickHandler _: - case MidiHandler _: - section = new HandlerSection(handler); - break; - - default: - return null; - } - - return section; - } - - private class HandlerSection : SettingsSubsection + public class HandlerSection : SettingsSubsection { private readonly InputHandler handler; From 037e56f13eca292e9b8b4a43a0eb4da262ac0fa8 Mon Sep 17 00:00:00 2001 From: Susko3 <16479013+Susko3@users.noreply.github.com> Date: Sat, 15 Jan 2022 14:38:38 +0100 Subject: [PATCH 002/211] Add Android mouse settings --- osu.Android/AndroidMouseSettings.cs | 97 +++++++++++++++++++ osu.Android/OsuGameAndroid.cs | 22 +++++ osu.Android/osu.Android.csproj | 1 + .../Settings/Sections/Input/MouseSettings.cs | 4 +- 4 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 osu.Android/AndroidMouseSettings.cs diff --git a/osu.Android/AndroidMouseSettings.cs b/osu.Android/AndroidMouseSettings.cs new file mode 100644 index 0000000000..7dff929cd4 --- /dev/null +++ b/osu.Android/AndroidMouseSettings.cs @@ -0,0 +1,97 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Android.OS; +using osu.Framework.Allocation; +using osu.Framework.Android.Input; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Localisation; +using osu.Game.Configuration; +using osu.Game.Localisation; +using osu.Game.Overlays.Settings; +using osu.Game.Overlays.Settings.Sections.Input; + +namespace osu.Android +{ + public class AndroidMouseSettings : SettingsSubsection + { + private readonly AndroidMouseHandler mouseHandler; + + protected override LocalisableString Header => MouseSettingsStrings.Mouse; + + private Bindable handlerSensitivity; + + private Bindable localSensitivity; + + private Bindable relativeMode; + + public AndroidMouseSettings(AndroidMouseHandler mouseHandler) + { + this.mouseHandler = mouseHandler; + } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager osuConfig) + { + // use local bindable to avoid changing enabled state of game host's bindable. + handlerSensitivity = mouseHandler.Sensitivity.GetBoundCopy(); + localSensitivity = handlerSensitivity.GetUnboundCopy(); + + relativeMode = mouseHandler.UseRelativeMode.GetBoundCopy(); + + // High precision/pointer capture is only available on Android 8.0 and up + if (Build.VERSION.SdkInt >= BuildVersionCodes.O) + { + AddRange(new Drawable[] + { + new SettingsCheckbox + { + LabelText = MouseSettingsStrings.HighPrecisionMouse, + TooltipText = MouseSettingsStrings.HighPrecisionMouseTooltip, + Current = relativeMode, + Keywords = new[] { @"raw", @"input", @"relative", @"cursor", @"captured", @"pointer" }, + }, + new MouseSettings.SensitivitySetting + { + LabelText = MouseSettingsStrings.CursorSensitivity, + Current = localSensitivity, + }, + }); + } + + AddRange(new Drawable[] + { + new SettingsCheckbox + { + LabelText = MouseSettingsStrings.DisableMouseWheelVolumeAdjust, + TooltipText = MouseSettingsStrings.DisableMouseWheelVolumeAdjustTooltip, + Current = osuConfig.GetBindable(OsuSetting.MouseDisableWheel), + }, + new SettingsCheckbox + { + LabelText = MouseSettingsStrings.DisableMouseButtons, + Current = osuConfig.GetBindable(OsuSetting.MouseDisableButtons), + }, + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + relativeMode.BindValueChanged(relative => localSensitivity.Disabled = !relative.NewValue, true); + + handlerSensitivity.BindValueChanged(val => + { + bool disabled = localSensitivity.Disabled; + + localSensitivity.Disabled = false; + localSensitivity.Value = val.NewValue; + localSensitivity.Disabled = disabled; + }, true); + + localSensitivity.BindValueChanged(val => handlerSensitivity.Value = val.NewValue); + } + } +} diff --git a/osu.Android/OsuGameAndroid.cs b/osu.Android/OsuGameAndroid.cs index 050bf2b787..ba2527d71e 100644 --- a/osu.Android/OsuGameAndroid.cs +++ b/osu.Android/OsuGameAndroid.cs @@ -5,7 +5,11 @@ using System; using Android.App; using Android.OS; using osu.Framework.Allocation; +using osu.Framework.Android.Input; +using osu.Framework.Input.Handlers; +using osu.Framework.Platform; using osu.Game; +using osu.Game.Overlays.Settings; using osu.Game.Updater; using osu.Game.Utils; using Xamarin.Essentials; @@ -73,10 +77,28 @@ namespace osu.Android LoadComponentAsync(new GameplayScreenRotationLocker(), Add); } + public override void SetHost(GameHost host) + { + base.SetHost(host); + host.Window.CursorState |= CursorState.Hidden; + } + protected override UpdateManager CreateUpdateManager() => new SimpleUpdateManager(); protected override BatteryInfo CreateBatteryInfo() => new AndroidBatteryInfo(); + public override SettingsSubsection CreateSettingsSubsectionFor(InputHandler handler) + { + switch (handler) + { + case AndroidMouseHandler mh: + return new AndroidMouseSettings(mh); + + default: + return base.CreateSettingsSubsectionFor(handler); + } + } + private class AndroidBatteryInfo : BatteryInfo { public override double ChargeLevel => Battery.ChargeLevel; diff --git a/osu.Android/osu.Android.csproj b/osu.Android/osu.Android.csproj index fc50ca9fa1..90b02c527b 100644 --- a/osu.Android/osu.Android.csproj +++ b/osu.Android/osu.Android.csproj @@ -26,6 +26,7 @@ true + diff --git a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs index 4235dc0a05..6bb97c1137 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs @@ -124,7 +124,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input }, true); } - private class SensitivitySetting : SettingsSlider + public class SensitivitySetting : SettingsSlider { public SensitivitySetting() { @@ -133,7 +133,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } - private class SensitivitySlider : OsuSliderBar + public class SensitivitySlider : OsuSliderBar { public override LocalisableString TooltipText => Current.Disabled ? MouseSettingsStrings.EnableHighPrecisionForSensitivityAdjust : $"{base.TooltipText}x"; } From d4af8498af6795213d648844d1c11da99f65f4e6 Mon Sep 17 00:00:00 2001 From: Susko3 <16479013+Susko3@users.noreply.github.com> Date: Sat, 15 Jan 2022 14:48:41 +0100 Subject: [PATCH 003/211] Add iOS mouse settings Functionality is currently limited to some OsuSettings, but will expand in the future when high precision mouse is added. --- osu.iOS/IOSMouseSettings.cs | 36 ++++++++++++++++++++++++++++++++++++ osu.iOS/OsuGameIOS.cs | 15 +++++++++++++++ osu.iOS/osu.iOS.csproj | 1 + 3 files changed, 52 insertions(+) create mode 100644 osu.iOS/IOSMouseSettings.cs diff --git a/osu.iOS/IOSMouseSettings.cs b/osu.iOS/IOSMouseSettings.cs new file mode 100644 index 0000000000..1979a881f7 --- /dev/null +++ b/osu.iOS/IOSMouseSettings.cs @@ -0,0 +1,36 @@ +// 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.Localisation; +using osu.Game.Configuration; +using osu.Game.Localisation; +using osu.Game.Overlays.Settings; + +namespace osu.iOS +{ + public class IOSMouseSettings : SettingsSubsection + { + protected override LocalisableString Header => MouseSettingsStrings.Mouse; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager osuConfig) + { + Children = new Drawable[] + { + new SettingsCheckbox + { + LabelText = MouseSettingsStrings.DisableMouseWheelVolumeAdjust, + TooltipText = MouseSettingsStrings.DisableMouseWheelVolumeAdjustTooltip, + Current = osuConfig.GetBindable(OsuSetting.MouseDisableWheel), + }, + new SettingsCheckbox + { + LabelText = MouseSettingsStrings.DisableMouseButtons, + Current = osuConfig.GetBindable(OsuSetting.MouseDisableButtons), + }, + }; + } + } +} diff --git a/osu.iOS/OsuGameIOS.cs b/osu.iOS/OsuGameIOS.cs index 702aef45f5..c3f7033752 100644 --- a/osu.iOS/OsuGameIOS.cs +++ b/osu.iOS/OsuGameIOS.cs @@ -3,7 +3,10 @@ using System; using Foundation; +using osu.Framework.Input.Handlers; +using osu.Framework.iOS.Input; using osu.Game; +using osu.Game.Overlays.Settings; using osu.Game.Updater; using osu.Game.Utils; using Xamarin.Essentials; @@ -18,6 +21,18 @@ namespace osu.iOS protected override BatteryInfo CreateBatteryInfo() => new IOSBatteryInfo(); + public override SettingsSubsection CreateSettingsSubsectionFor(InputHandler handler) + { + switch (handler) + { + case IOSMouseHandler _: + return new IOSMouseSettings(); + + default: + return base.CreateSettingsSubsectionFor(handler); + } + } + private class IOSBatteryInfo : BatteryInfo { public override double ChargeLevel => Battery.ChargeLevel; diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj index 1203c3659b..b9da874f30 100644 --- a/osu.iOS/osu.iOS.csproj +++ b/osu.iOS/osu.iOS.csproj @@ -23,6 +23,7 @@ + From 7e7716f942a5ef2df2e49c8783c9f1fa829614a3 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 13 Jun 2022 15:40:11 +0900 Subject: [PATCH 004/211] Support undo/redo for control points --- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 2 +- osu.Game/Screens/Edit/EditorBeatmap.cs | 59 ++++++----- .../Edit/LegacyEditorBeatmapPatcher.cs | 100 ++++++++++++------ 3 files changed, 105 insertions(+), 56 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index ff13e61360..25551d1ef6 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -143,7 +143,7 @@ namespace osu.Game.Beatmaps.Formats protected string CleanFilename(string path) => path.Trim('"').ToStandardisedPath(); - protected enum Section + public enum Section { General, Editor, diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index c9449f3259..577a8291ad 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -71,31 +71,7 @@ namespace osu.Game.Screens.Edit public EditorBeatmap(IBeatmap playableBeatmap, ISkin beatmapSkin = null, BeatmapInfo beatmapInfo = null) { PlayableBeatmap = playableBeatmap; - - // ensure we are not working with legacy control points. - // if we leave the legacy points around they will be applied over any local changes on - // ApplyDefaults calls. this should eventually be removed once the default logic is moved to the decoder/converter. - if (PlayableBeatmap.ControlPointInfo is LegacyControlPointInfo) - { - var newControlPoints = new ControlPointInfo(); - - foreach (var controlPoint in PlayableBeatmap.ControlPointInfo.AllControlPoints) - { - switch (controlPoint) - { - case DifficultyControlPoint _: - case SampleControlPoint _: - // skip legacy types. - continue; - - default: - newControlPoints.Add(controlPoint.Time, controlPoint); - break; - } - } - - playableBeatmap.ControlPointInfo = newControlPoints; - } + PlayableBeatmap.ControlPointInfo = ConvertControlPoints(PlayableBeatmap.ControlPointInfo); this.beatmapInfo = beatmapInfo ?? playableBeatmap.BeatmapInfo; @@ -108,6 +84,39 @@ namespace osu.Game.Screens.Edit trackStartTime(obj); } + /// + /// Converts a such that the resultant is non-legacy. + /// + /// The to convert. + /// The non-legacy . is returned if already non-legacy. + public static ControlPointInfo ConvertControlPoints(ControlPointInfo incoming) + { + // ensure we are not working with legacy control points. + // if we leave the legacy points around they will be applied over any local changes on + // ApplyDefaults calls. this should eventually be removed once the default logic is moved to the decoder/converter. + if (!(incoming is LegacyControlPointInfo)) + return incoming; + + var newControlPoints = new ControlPointInfo(); + + foreach (var controlPoint in incoming.AllControlPoints) + { + switch (controlPoint) + { + case DifficultyControlPoint _: + case SampleControlPoint _: + // skip legacy types. + continue; + + default: + newControlPoints.Add(controlPoint.Time, controlPoint); + break; + } + } + + return newControlPoints; + } + public BeatmapInfo BeatmapInfo { get => beatmapInfo; diff --git a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs index 3ed2a7efe2..ba9a7ed1a3 100644 --- a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs +++ b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs @@ -7,9 +7,11 @@ using System.Diagnostics; using System.IO; using System.Text; using DiffPlex; +using DiffPlex.Model; using osu.Framework.Audio.Track; using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Formats; using osu.Game.IO; using osu.Game.Skinning; using Decoder = osu.Game.Beatmaps.Formats.Decoder; @@ -32,61 +34,99 @@ namespace osu.Game.Screens.Edit { // Diff the beatmaps var result = new Differ().CreateLineDiffs(readString(currentState), readString(newState), true, false); + IBeatmap newBeatmap = null; + + editorBeatmap.BeginChange(); + processHitObjects(result, () => newBeatmap ??= readBeatmap(newState)); + processTimingPoints(result, () => newBeatmap ??= readBeatmap(newState)); + editorBeatmap.EndChange(); + } + + private void processTimingPoints(DiffResult result, Func getNewBeatmap) + { + findChangedIndices(result, LegacyDecoder.Section.TimingPoints, out var removedIndices, out var addedIndices); + + if (removedIndices.Count == 0 && addedIndices.Count == 0) + return; + + // Due to conversion from legacy to non-legacy control points, it becomes difficult to diff control points correctly. + // So instead _all_ control points are reloaded if _any_ control point is changed. + + var newControlPoints = EditorBeatmap.ConvertControlPoints(getNewBeatmap().ControlPointInfo); + + editorBeatmap.ControlPointInfo.Clear(); + foreach (var point in newControlPoints.AllControlPoints) + editorBeatmap.ControlPointInfo.Add(point.Time, point); + } + + private void processHitObjects(DiffResult result, Func getNewBeatmap) + { + findChangedIndices(result, LegacyDecoder.Section.HitObjects, out var removedIndices, out var addedIndices); + + foreach (int removed in removedIndices) + editorBeatmap.RemoveAt(removed); + + if (addedIndices.Count > 0) + { + var newBeatmap = getNewBeatmap(); + + foreach (int i in addedIndices) + editorBeatmap.Insert(i, newBeatmap.HitObjects[i]); + } + } + + private void findChangedIndices(DiffResult result, LegacyDecoder.Section section, out List removedIndices, out List addedIndices) + { + removedIndices = new List(); + addedIndices = new List(); // Find the index of [HitObject] sections. Lines changed prior to this index are ignored. - int oldHitObjectsIndex = Array.IndexOf(result.PiecesOld, "[HitObjects]"); - int newHitObjectsIndex = Array.IndexOf(result.PiecesNew, "[HitObjects]"); + int oldSectionStartIndex = Array.IndexOf(result.PiecesOld, $"[{section}]"); + int oldSectionEndIndex = Array.FindIndex(result.PiecesOld, oldSectionStartIndex + 1, s => s.StartsWith(@"[", StringComparison.Ordinal)); - Debug.Assert(oldHitObjectsIndex >= 0); - Debug.Assert(newHitObjectsIndex >= 0); + if (oldSectionEndIndex == -1) + oldSectionEndIndex = result.PiecesOld.Length; - var toRemove = new List(); - var toAdd = new List(); + int newSectionStartIndex = Array.IndexOf(result.PiecesNew, $"[{section}]"); + int newSectionEndIndex = Array.FindIndex(result.PiecesNew, newSectionStartIndex + 1, s => s.StartsWith(@"[", StringComparison.Ordinal)); + + if (newSectionEndIndex == -1) + newSectionEndIndex = result.PiecesOld.Length; + + Debug.Assert(oldSectionStartIndex >= 0); + Debug.Assert(newSectionStartIndex >= 0); foreach (var block in result.DiffBlocks) { - // Removed hitobjects + // Removed indices for (int i = 0; i < block.DeleteCountA; i++) { - int hoIndex = block.DeleteStartA + i - oldHitObjectsIndex - 1; + int objectIndex = block.DeleteStartA + i; - if (hoIndex < 0) + if (objectIndex <= oldSectionStartIndex || objectIndex >= oldSectionEndIndex) continue; - toRemove.Add(hoIndex); + removedIndices.Add(objectIndex - oldSectionStartIndex - 1); } - // Added hitobjects + // Added indices for (int i = 0; i < block.InsertCountB; i++) { - int hoIndex = block.InsertStartB + i - newHitObjectsIndex - 1; + int objectIndex = block.InsertStartB + i; - if (hoIndex < 0) + if (objectIndex <= newSectionStartIndex || objectIndex >= newSectionEndIndex) continue; - toAdd.Add(hoIndex); + addedIndices.Add(objectIndex - newSectionStartIndex - 1); } } // Sort the indices to ensure that removal + insertion indices don't get jumbled up post-removal or post-insertion. // This isn't strictly required, but the differ makes no guarantees about order. - toRemove.Sort(); - toAdd.Sort(); + removedIndices.Sort(); + addedIndices.Sort(); - editorBeatmap.BeginChange(); - - // Apply the changes. - for (int i = toRemove.Count - 1; i >= 0; i--) - editorBeatmap.RemoveAt(toRemove[i]); - - if (toAdd.Count > 0) - { - IBeatmap newBeatmap = readBeatmap(newState); - foreach (int i in toAdd) - editorBeatmap.Insert(i, newBeatmap.HitObjects[i]); - } - - editorBeatmap.EndChange(); + removedIndices.Reverse(); } private string readString(byte[] state) => Encoding.UTF8.GetString(state); From 776e7c0c718e531874247c5c5dca8c0294cd2a04 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 13 Jun 2022 15:40:18 +0900 Subject: [PATCH 005/211] Work around performance issues --- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index f498aa917e..015e7f5bc1 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -137,8 +137,12 @@ namespace osu.Game.Screens.Edit.Timing controlPointGroups.BindTo(Beatmap.ControlPointInfo.Groups); controlPointGroups.BindCollectionChanged((sender, args) => { - table.ControlGroups = controlPointGroups; - changeHandler?.SaveState(); + // This AddOnce() works around performance issues from the LegacyEditorBeatmapPatcher re-initialising all control points every undo & redo. + Scheduler.AddOnce(() => + { + table.ControlGroups = controlPointGroups; + changeHandler?.SaveState(); + }); }, true); } From 5a18547342d1c7a242052fb28ecc72159e128f0d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 13 Jun 2022 15:58:11 +0900 Subject: [PATCH 006/211] Compare by `char` Co-authored-by: Berkan Diler --- osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs index ba9a7ed1a3..c668778be2 100644 --- a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs +++ b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs @@ -82,13 +82,13 @@ namespace osu.Game.Screens.Edit // Find the index of [HitObject] sections. Lines changed prior to this index are ignored. int oldSectionStartIndex = Array.IndexOf(result.PiecesOld, $"[{section}]"); - int oldSectionEndIndex = Array.FindIndex(result.PiecesOld, oldSectionStartIndex + 1, s => s.StartsWith(@"[", StringComparison.Ordinal)); + int oldSectionEndIndex = Array.FindIndex(result.PiecesOld, oldSectionStartIndex + 1, s => s.StartsWith('[')); if (oldSectionEndIndex == -1) oldSectionEndIndex = result.PiecesOld.Length; int newSectionStartIndex = Array.IndexOf(result.PiecesNew, $"[{section}]"); - int newSectionEndIndex = Array.FindIndex(result.PiecesNew, newSectionStartIndex + 1, s => s.StartsWith(@"[", StringComparison.Ordinal)); + int newSectionEndIndex = Array.FindIndex(result.PiecesNew, newSectionStartIndex + 1, s => s.StartsWith('[')); if (newSectionEndIndex == -1) newSectionEndIndex = result.PiecesOld.Length; From 285e5abb417e43fb8b95054edeba2d2a05d6e90d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 13 Jun 2022 16:55:46 +0900 Subject: [PATCH 007/211] Fix incorrect fallback value --- osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs index c668778be2..939d319405 100644 --- a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs +++ b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs @@ -91,7 +91,7 @@ namespace osu.Game.Screens.Edit int newSectionEndIndex = Array.FindIndex(result.PiecesNew, newSectionStartIndex + 1, s => s.StartsWith('[')); if (newSectionEndIndex == -1) - newSectionEndIndex = result.PiecesOld.Length; + newSectionEndIndex = result.PiecesNew.Length; Debug.Assert(oldSectionStartIndex >= 0); Debug.Assert(newSectionStartIndex >= 0); From a8286bdf0486b5c18e480afd2facf77c24714b58 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 13 Jun 2022 16:56:08 +0900 Subject: [PATCH 008/211] Fix assertion failures --- osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs index 939d319405..b56d990d75 100644 --- a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs +++ b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs @@ -82,14 +82,18 @@ namespace osu.Game.Screens.Edit // Find the index of [HitObject] sections. Lines changed prior to this index are ignored. int oldSectionStartIndex = Array.IndexOf(result.PiecesOld, $"[{section}]"); - int oldSectionEndIndex = Array.FindIndex(result.PiecesOld, oldSectionStartIndex + 1, s => s.StartsWith('[')); + if (oldSectionStartIndex == -1) + return; + int oldSectionEndIndex = Array.FindIndex(result.PiecesOld, oldSectionStartIndex + 1, s => s.StartsWith('[')); if (oldSectionEndIndex == -1) oldSectionEndIndex = result.PiecesOld.Length; int newSectionStartIndex = Array.IndexOf(result.PiecesNew, $"[{section}]"); - int newSectionEndIndex = Array.FindIndex(result.PiecesNew, newSectionStartIndex + 1, s => s.StartsWith('[')); + if (newSectionStartIndex == -1) + return; + int newSectionEndIndex = Array.FindIndex(result.PiecesNew, newSectionStartIndex + 1, s => s.StartsWith('[')); if (newSectionEndIndex == -1) newSectionEndIndex = result.PiecesNew.Length; From c178e5d5923cdbcc6ace0adad7b475c3865f1a66 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 13 Jun 2022 16:58:43 +0900 Subject: [PATCH 009/211] Add explanatory comment --- osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs index b56d990d75..66ece8fcfa 100644 --- a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs +++ b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs @@ -130,6 +130,8 @@ namespace osu.Game.Screens.Edit removedIndices.Sort(); addedIndices.Sort(); + // The expected usage of this returned list is to iterate from the start to the end of the list, such that + // these indices need to appear in reverse order for the usage to not have to deal with decrementing indices. removedIndices.Reverse(); } From f680f4d26bce5cc1d3fbc07946a8256d200b6aab Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 13 Jun 2022 17:36:32 +0900 Subject: [PATCH 010/211] Apply refactorings from review --- .../Screens/Edit/LegacyEditorBeatmapPatcher.cs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs index 66ece8fcfa..00cb95dd79 100644 --- a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs +++ b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Text; using DiffPlex; @@ -63,8 +62,8 @@ namespace osu.Game.Screens.Edit { findChangedIndices(result, LegacyDecoder.Section.HitObjects, out var removedIndices, out var addedIndices); - foreach (int removed in removedIndices) - editorBeatmap.RemoveAt(removed); + for (int i = removedIndices.Count - 1; i >= 0; i--) + editorBeatmap.RemoveAt(removedIndices[i]); if (addedIndices.Count > 0) { @@ -80,7 +79,7 @@ namespace osu.Game.Screens.Edit removedIndices = new List(); addedIndices = new List(); - // Find the index of [HitObject] sections. Lines changed prior to this index are ignored. + // Find the start and end indices of the relevant section headers in both the old and the new beatmap file. Lines changed outside of the modified ranges are ignored. int oldSectionStartIndex = Array.IndexOf(result.PiecesOld, $"[{section}]"); if (oldSectionStartIndex == -1) return; @@ -97,9 +96,6 @@ namespace osu.Game.Screens.Edit if (newSectionEndIndex == -1) newSectionEndIndex = result.PiecesNew.Length; - Debug.Assert(oldSectionStartIndex >= 0); - Debug.Assert(newSectionStartIndex >= 0); - foreach (var block in result.DiffBlocks) { // Removed indices @@ -129,10 +125,6 @@ namespace osu.Game.Screens.Edit // This isn't strictly required, but the differ makes no guarantees about order. removedIndices.Sort(); addedIndices.Sort(); - - // The expected usage of this returned list is to iterate from the start to the end of the list, such that - // these indices need to appear in reverse order for the usage to not have to deal with decrementing indices. - removedIndices.Reverse(); } private string readString(byte[] state) => Encoding.UTF8.GetString(state); From 737197591d812d0abdbf733d05bd4e411b050a9a Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Mon, 13 Jun 2022 17:49:56 +0100 Subject: [PATCH 011/211] Change doubletap algorithm --- .../Difficulty/Evaluators/SpeedEvaluator.cs | 18 ++++++++++++------ .../Difficulty/Skills/Speed.cs | 3 ++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs index 85203dd157..e68e7a8653 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Utils; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; @@ -31,14 +30,21 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators // derive strainTime for calculation var osuCurrObj = (OsuDifficultyHitObject)current; var osuPrevObj = current.Index > 0 ? (OsuDifficultyHitObject)current.Previous(0) : null; + var osuNextObj = (OsuDifficultyHitObject)current.Next(0); double strainTime = osuCurrObj.StrainTime; double greatWindowFull = greatWindow * 2; - double speedWindowRatio = strainTime / greatWindowFull; + double doubletapness = 1; - // Aim to nerf cheesy rhythms (Very fast consecutive doubles with large deltatimes between) - if (osuPrevObj != null && strainTime < greatWindowFull && osuPrevObj.StrainTime > strainTime) - strainTime = Interpolation.Lerp(osuPrevObj.StrainTime, strainTime, speedWindowRatio); + // Nerf doubletappable doubles. + if (osuNextObj != null) + { + double currDeltaTime = Math.Max(1, osuCurrObj.DeltaTime); + double nextDeltaTime = Math.Max(1, osuNextObj.DeltaTime); + double speedRatio = Math.Min(1, currDeltaTime / nextDeltaTime); + double windowRatio = Math.Min(1, currDeltaTime / greatWindowFull); + doubletapness = Math.Pow(speedRatio, 1 - windowRatio); + } // Cap deltatime to the OD 300 hitwindow. // 0.93 is derived from making sure 260bpm OD8 streams aren't nerfed harshly, whilst 0.92 limits the effect of the cap. @@ -53,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators double travelDistance = osuPrevObj?.TravelDistance ?? 0; double distance = Math.Min(single_spacing_threshold, travelDistance + osuCurrObj.MinimumJumpDistance); - return (speedBonus + speedBonus * Math.Pow(distance / single_spacing_threshold, 3.5)) / strainTime; + return (speedBonus + speedBonus * Math.Pow(distance / single_spacing_threshold, 3.5)) * doubletapness / strainTime; } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 055e1cb66e..3e4e55262c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -5,6 +5,7 @@ using System; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Evaluators; +using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; namespace osu.Game.Rulesets.Osu.Difficulty.Skills { @@ -35,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override double StrainValueAt(DifficultyHitObject current) { - currentStrain *= strainDecay(current.DeltaTime); + currentStrain *= strainDecay(((OsuDifficultyHitObject)current).StrainTime); currentStrain += SpeedEvaluator.EvaluateDifficultyOf(current, greatWindow) * skillMultiplier; currentRhythm = RhythmEvaluator.EvaluateDifficultyOf(current, greatWindow); From 2634e569440d8ada58be6995f07929d5d42a1ae9 Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Tue, 14 Jun 2022 16:16:12 +0100 Subject: [PATCH 012/211] Further adjustments --- .../Difficulty/Evaluators/SpeedEvaluator.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs index e68e7a8653..3be4d621eb 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs @@ -41,8 +41,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { double currDeltaTime = Math.Max(1, osuCurrObj.DeltaTime); double nextDeltaTime = Math.Max(1, osuNextObj.DeltaTime); - double speedRatio = Math.Min(1, currDeltaTime / nextDeltaTime); - double windowRatio = Math.Min(1, currDeltaTime / greatWindowFull); + double deltaDifference = Math.Abs(nextDeltaTime - currDeltaTime); + double speedRatio = Math.Min(1, currDeltaTime / deltaDifference); + double windowRatio = Math.Pow(Math.Min(1, currDeltaTime / greatWindowFull), 2); doubletapness = Math.Pow(speedRatio, 1 - windowRatio); } From f3f0960335303bcdc8a53a491fe02fd12580dff2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 15 Jun 2022 09:02:48 +0300 Subject: [PATCH 013/211] Use unified filename for background and track during editor import --- .../Editing/TestSceneEditorBeatmapCreation.cs | 3 ++ .../Screens/Edit/Setup/ResourcesSection.cs | 29 +++++++++++-------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index b109234fec..841f50e7bd 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -101,6 +101,9 @@ namespace osu.Game.Tests.Visual.Editing File.Delete(temp); Directory.Delete(extractedFolder, true); + // ensure audio file is copied to beatmap as "audio.mp3" rather than original filename. + Assert.That(Beatmap.Value.Metadata.AudioFile == "audio.mp3"); + return success; }); diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 1e97218074..9d4e72d1f3 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -64,26 +64,28 @@ namespace osu.Game.Screens.Edit.Setup public bool ChangeBackgroundImage(string path) { - var info = new FileInfo(path); + var source = new FileInfo(path); - if (!info.Exists) + if (!source.Exists) return false; var set = working.Value.BeatmapSetInfo; + var destination = new FileInfo($@"bg{source.Extension}"); + // remove the previous background for now. // in the future we probably want to check if this is being used elsewhere (other difficulties?) - var oldFile = set.Files.FirstOrDefault(f => f.Filename == working.Value.Metadata.BackgroundFile); + var oldFile = set.Files.FirstOrDefault(f => Path.GetFileNameWithoutExtension(f.Filename) == destination.Name); - using (var stream = info.OpenRead()) + using (var stream = source.OpenRead()) { if (oldFile != null) beatmaps.DeleteFile(set, oldFile); - beatmaps.AddFile(set, stream, info.Name); + beatmaps.AddFile(set, stream, destination.Name); } - working.Value.Metadata.BackgroundFile = info.Name; + working.Value.Metadata.BackgroundFile = destination.Name; header.Background.UpdateBackground(); return true; @@ -91,25 +93,28 @@ namespace osu.Game.Screens.Edit.Setup public bool ChangeAudioTrack(string path) { - var info = new FileInfo(path); + var source = new FileInfo(path); - if (!info.Exists) + if (!source.Exists) return false; var set = working.Value.BeatmapSetInfo; + var destination = new FileInfo($@"audio{source.Extension}"); + // remove the previous audio track for now. // in the future we probably want to check if this is being used elsewhere (other difficulties?) - var oldFile = set.Files.FirstOrDefault(f => f.Filename == working.Value.Metadata.AudioFile); + var oldFile = set.Files.FirstOrDefault(f => Path.GetFileNameWithoutExtension(f.Filename) == destination.Name); - using (var stream = info.OpenRead()) + using (var stream = source.OpenRead()) { if (oldFile != null) beatmaps.DeleteFile(set, oldFile); - beatmaps.AddFile(set, stream, info.Name); + + beatmaps.AddFile(set, stream, destination.Name); } - working.Value.Metadata.AudioFile = info.Name; + working.Value.Metadata.AudioFile = destination.Name; music.ReloadCurrentTrack(); From 6a8cf514e0f18291d6d136db3f565dadf31740d1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 15 Jun 2022 09:52:12 +0300 Subject: [PATCH 014/211] Update background/track file chooser to not display filename --- .../UserInterfaceV2/LabelledComponent.cs | 2 +- ...elledTextBox.cs => LabelledFileChooser.cs} | 15 +++++--- .../Screens/Edit/Setup/ResourcesSection.cs | 37 ++++++++++++------- 3 files changed, 35 insertions(+), 19 deletions(-) rename osu.Game/Screens/Edit/Setup/{FileChooserLabelledTextBox.cs => LabelledFileChooser.cs} (86%) diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs index dd6a902989..77267e453c 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs @@ -15,7 +15,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 { } - public Bindable Current + public virtual Bindable Current { get => Component.Current; set => Component.Current = value; diff --git a/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs similarity index 86% rename from osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs rename to osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs index fd916894ea..745c989b3b 100644 --- a/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs +++ b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs @@ -21,10 +21,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Setup { - /// - /// A labelled textbox which reveals an inline file chooser when clicked. - /// - internal class FileChooserLabelledTextBox : LabelledTextBoxWithPopover, ICanAcceptFiles + internal class LabelledFileChooser : LabelledTextBoxWithPopover, ICanAcceptFiles { private readonly string[] handledExtensions; @@ -35,7 +32,15 @@ namespace osu.Game.Screens.Edit.Setup [Resolved] private OsuGameBase game { get; set; } = null!; - public FileChooserLabelledTextBox(params string[] handledExtensions) + private readonly BindableWithCurrent current = new BindableWithCurrent(); + + public override Bindable Current + { + get => current.Current; + set => current.Current = value; + } + + public LabelledFileChooser(params string[] handledExtensions) { this.handledExtensions = handledExtensions; } diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 9d4e72d1f3..36edb5dd83 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -8,15 +8,14 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Beatmaps; -using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Overlays; namespace osu.Game.Screens.Edit.Setup { internal class ResourcesSection : SetupSection { - private LabelledTextBox audioTrackTextBox; - private LabelledTextBox backgroundTextBox; + private LabelledFileChooser audioTrackChooser; + private LabelledFileChooser backgroundChooser; public override LocalisableString Title => "Resources"; @@ -40,26 +39,24 @@ namespace osu.Game.Screens.Edit.Setup { Children = new Drawable[] { - backgroundTextBox = new FileChooserLabelledTextBox(".jpg", ".jpeg", ".png") + backgroundChooser = new LabelledFileChooser(".jpg", ".jpeg", ".png") { Label = "Background", FixedLabelWidth = LABEL_WIDTH, - PlaceholderText = "Click to select a background image", Current = { Value = working.Value.Metadata.BackgroundFile }, TabbableContentContainer = this }, - audioTrackTextBox = new FileChooserLabelledTextBox(".mp3", ".ogg") + audioTrackChooser = new LabelledFileChooser(".mp3", ".ogg") { Label = "Audio Track", FixedLabelWidth = LABEL_WIDTH, - PlaceholderText = "Click to select a track", Current = { Value = working.Value.Metadata.AudioFile }, TabbableContentContainer = this }, }; - backgroundTextBox.Current.BindValueChanged(backgroundChanged); - audioTrackTextBox.Current.BindValueChanged(audioTrackChanged); + backgroundChooser.Current.BindValueChanged(backgroundChanged, true); + audioTrackChooser.Current.BindValueChanged(audioTrackChanged, true); } public bool ChangeBackgroundImage(string path) @@ -124,14 +121,28 @@ namespace osu.Game.Screens.Edit.Setup private void backgroundChanged(ValueChangedEvent filePath) { - if (!ChangeBackgroundImage(filePath.NewValue)) - backgroundTextBox.Current.Value = filePath.OldValue; + backgroundChooser.PlaceholderText = string.IsNullOrEmpty(filePath.NewValue) + ? "Click to select a background image" + : "Click to replace the background image"; + + if (filePath.NewValue != filePath.OldValue) + { + if (!ChangeBackgroundImage(filePath.NewValue)) + backgroundChooser.Current.Value = filePath.OldValue; + } } private void audioTrackChanged(ValueChangedEvent filePath) { - if (!ChangeAudioTrack(filePath.NewValue)) - audioTrackTextBox.Current.Value = filePath.OldValue; + audioTrackChooser.PlaceholderText = string.IsNullOrEmpty(filePath.NewValue) + ? "Click to select a track" + : "Click to replace the track"; + + if (filePath.NewValue != filePath.OldValue) + { + if (!ChangeAudioTrack(filePath.NewValue)) + audioTrackChooser.Current.Value = filePath.OldValue; + } } } } From d89c80ace2df4bdb7e26e5543d692e0ffc053261 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 15 Jun 2022 18:44:15 +0900 Subject: [PATCH 015/211] Block operations during beatmap selection in match --- .../Multiplayer/MultiplayerMatchSongSelect.cs | 43 +++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 929c3ee321..b2355a9021 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -1,6 +1,9 @@ // 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.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; @@ -18,11 +21,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer public class MultiplayerMatchSongSelect : OnlinePlaySongSelect { [Resolved] - private MultiplayerClient client { get; set; } + private MultiplayerClient client { get; set; } = null!; + + [Resolved] + private OngoingOperationTracker operationTracker { get; set; } = null!; private readonly long? itemToEdit; - private LoadingLayer loadingLayer; + private LoadingLayer loadingLayer = null!; + private IDisposable? selectionOperation; /// /// Construct a new instance of multiplayer song select. @@ -31,7 +38,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer /// The item to be edited. May be null, in which case a new item will be added to the playlist. /// An optional initial beatmap selection to perform. /// An optional initial ruleset selection to perform. - public MultiplayerMatchSongSelect(Room room, long? itemToEdit = null, WorkingBeatmap beatmap = null, RulesetInfo ruleset = null) + public MultiplayerMatchSongSelect(Room room, long? itemToEdit = null, WorkingBeatmap? beatmap = null, RulesetInfo? ruleset = null) : base(room) { this.itemToEdit = itemToEdit; @@ -58,6 +65,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer // Otherwise, update the playlist directly in preparation for it to be submitted to the API on match creation. if (client.Room != null) { + selectionOperation = operationTracker.BeginOperation(); + loadingLayer.Show(); var multiplayerItem = new MultiplayerPlaylistItem @@ -72,18 +81,28 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Task task = itemToEdit != null ? client.EditPlaylistItem(multiplayerItem) : client.AddPlaylistItem(multiplayerItem); - task.FireAndForget(onSuccess: () => Schedule(() => + task.FireAndForget(onSuccess: () => { - loadingLayer.Hide(); + selectionOperation.Dispose(); - // If an error or server side trigger occurred this screen may have already exited by external means. - if (this.IsCurrentScreen()) - this.Exit(); - }), onError: _ => Schedule(() => + Schedule(() => + { + loadingLayer.Hide(); + + // If an error or server side trigger occurred this screen may have already exited by external means. + if (this.IsCurrentScreen()) + this.Exit(); + }); + }, onError: _ => { - loadingLayer.Hide(); - Carousel.AllowSelection = true; - })); + selectionOperation.Dispose(); + + Schedule(() => + { + loadingLayer.Hide(); + Carousel.AllowSelection = true; + }); + }); } else { From 1ff070f5ff3722ee464c1196f987f678b725aa21 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 15 Jun 2022 17:45:31 +0300 Subject: [PATCH 016/211] Decouple `LabelledFileChooser` from `LabelledTextBoxWithPopover` --- .../Screens/Edit/Setup/LabelledFileChooser.cs | 33 +++++++++++++++++-- .../Screens/Edit/Setup/ResourcesSection.cs | 4 +-- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs index 745c989b3b..2cb3af61c8 100644 --- a/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs +++ b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs @@ -14,14 +14,20 @@ using osu.Framework.Extensions; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Localisation; using osu.Game.Database; using osu.Game.Graphics.UserInterfaceV2; using osuTK; namespace osu.Game.Screens.Edit.Setup { - internal class LabelledFileChooser : LabelledTextBoxWithPopover, ICanAcceptFiles + /// + /// A labelled drawable displaying file chooser on click, with placeholder text support. + /// todo: this should probably not use PopoverTextBox just to display placeholder text, but is the best way for now. + /// + internal class LabelledFileChooser : LabelledDrawable, IHasCurrentValue, ICanAcceptFiles, IHasPopover { private readonly string[] handledExtensions; @@ -34,13 +40,25 @@ namespace osu.Game.Screens.Edit.Setup private readonly BindableWithCurrent current = new BindableWithCurrent(); - public override Bindable Current + public Bindable Current { get => current.Current; set => current.Current = value; } + public LocalisableString Text + { + get => Component.PlaceholderText; + set => Component.PlaceholderText = value; + } + + public CompositeDrawable TabbableContentContainer + { + set => Component.TabbableContentContainer = value; + } + public LabelledFileChooser(params string[] handledExtensions) + : base(false) { this.handledExtensions = handledExtensions; } @@ -78,7 +96,16 @@ namespace osu.Game.Screens.Edit.Setup game.UnregisterImportHandler(this); } - public override Popover GetPopover() => new FileChooserPopover(handledExtensions, currentFile); + protected override LabelledTextBoxWithPopover.PopoverTextBox CreateComponent() => new LabelledTextBoxWithPopover.PopoverTextBox + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + CornerRadius = CORNER_RADIUS, + OnFocused = this.ShowPopover, + }; + + public Popover GetPopover() => new FileChooserPopover(handledExtensions, currentFile); private class FileChooserPopover : OsuPopover { diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 36edb5dd83..b4e350b94b 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -121,7 +121,7 @@ namespace osu.Game.Screens.Edit.Setup private void backgroundChanged(ValueChangedEvent filePath) { - backgroundChooser.PlaceholderText = string.IsNullOrEmpty(filePath.NewValue) + backgroundChooser.Text = string.IsNullOrEmpty(filePath.NewValue) ? "Click to select a background image" : "Click to replace the background image"; @@ -134,7 +134,7 @@ namespace osu.Game.Screens.Edit.Setup private void audioTrackChanged(ValueChangedEvent filePath) { - audioTrackChooser.PlaceholderText = string.IsNullOrEmpty(filePath.NewValue) + audioTrackChooser.Text = string.IsNullOrEmpty(filePath.NewValue) ? "Click to select a track" : "Click to replace the track"; From 5d74d92fcf030d6c98fb8941ea3159914b09a6dd Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 15 Jun 2022 19:28:43 +0300 Subject: [PATCH 017/211] Revert `virtual` current bindable --- osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs index 77267e453c..dd6a902989 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs @@ -15,7 +15,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 { } - public virtual Bindable Current + public Bindable Current { get => Component.Current; set => Component.Current = value; From 2c35b1404b877767e2c39ac6218a05c3e6b1572c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 15 Jun 2022 19:29:09 +0300 Subject: [PATCH 018/211] Use `FileInfo` as current bindable type --- .../Editing/TestSceneEditorBeatmapCreation.cs | 2 +- .../Screens/Edit/Setup/LabelledFileChooser.cs | 21 +++++------ .../Screens/Edit/Setup/ResourcesSection.cs | 36 +++++++++---------- 3 files changed, 27 insertions(+), 32 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index 841f50e7bd..6bcd947f2f 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -96,7 +96,7 @@ namespace osu.Game.Tests.Visual.Editing using (var zip = ZipArchive.Open(temp)) zip.WriteToDirectory(extractedFolder); - bool success = setup.ChildrenOfType().First().ChangeAudioTrack(Path.Combine(extractedFolder, "03. Renatus - Soleily 192kbps.mp3")); + bool success = setup.ChildrenOfType().First().ChangeAudioTrack(new FileInfo(Path.Combine(extractedFolder, "03. Renatus - Soleily 192kbps.mp3"))); File.Delete(temp); Directory.Delete(extractedFolder, true); diff --git a/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs index 2cb3af61c8..6c56320666 100644 --- a/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs +++ b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs @@ -27,20 +27,18 @@ namespace osu.Game.Screens.Edit.Setup /// A labelled drawable displaying file chooser on click, with placeholder text support. /// todo: this should probably not use PopoverTextBox just to display placeholder text, but is the best way for now. /// - internal class LabelledFileChooser : LabelledDrawable, IHasCurrentValue, ICanAcceptFiles, IHasPopover + internal class LabelledFileChooser : LabelledDrawable, IHasCurrentValue, ICanAcceptFiles, IHasPopover { private readonly string[] handledExtensions; public IEnumerable HandledExtensions => handledExtensions; - private readonly Bindable currentFile = new Bindable(); - [Resolved] private OsuGameBase game { get; set; } = null!; - private readonly BindableWithCurrent current = new BindableWithCurrent(); + private readonly BindableWithCurrent current = new BindableWithCurrent(); - public Bindable Current + public Bindable Current { get => current.Current; set => current.Current = value; @@ -68,21 +66,18 @@ namespace osu.Game.Screens.Edit.Setup base.LoadComplete(); game.RegisterImportHandler(this); - currentFile.BindValueChanged(onFileSelected); + Current.BindValueChanged(onFileSelected); } private void onFileSelected(ValueChangedEvent file) { - if (file.NewValue == null) - return; - - this.HidePopover(); - Current.Value = file.NewValue.FullName; + if (file.NewValue != null) + this.HidePopover(); } Task ICanAcceptFiles.Import(params string[] paths) { - Schedule(() => currentFile.Value = new FileInfo(paths.First())); + Schedule(() => Current.Value = new FileInfo(paths.First())); return Task.CompletedTask; } @@ -105,7 +100,7 @@ namespace osu.Game.Screens.Edit.Setup OnFocused = this.ShowPopover, }; - public Popover GetPopover() => new FileChooserPopover(handledExtensions, currentFile); + public Popover GetPopover() => new FileChooserPopover(handledExtensions, Current); private class FileChooserPopover : OsuPopover { diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index b4e350b94b..2471886d9b 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -43,26 +43,28 @@ namespace osu.Game.Screens.Edit.Setup { Label = "Background", FixedLabelWidth = LABEL_WIDTH, - Current = { Value = working.Value.Metadata.BackgroundFile }, TabbableContentContainer = this }, audioTrackChooser = new LabelledFileChooser(".mp3", ".ogg") { Label = "Audio Track", FixedLabelWidth = LABEL_WIDTH, - Current = { Value = working.Value.Metadata.AudioFile }, TabbableContentContainer = this }, }; + if (!string.IsNullOrEmpty(working.Value.Metadata.BackgroundFile)) + backgroundChooser.Current.Value = new FileInfo(working.Value.Metadata.BackgroundFile); + + if (!string.IsNullOrEmpty(working.Value.Metadata.AudioFile)) + audioTrackChooser.Current.Value = new FileInfo(working.Value.Metadata.AudioFile); + backgroundChooser.Current.BindValueChanged(backgroundChanged, true); audioTrackChooser.Current.BindValueChanged(audioTrackChanged, true); } - public bool ChangeBackgroundImage(string path) + public bool ChangeBackgroundImage(FileInfo source) { - var source = new FileInfo(path); - if (!source.Exists) return false; @@ -88,10 +90,8 @@ namespace osu.Game.Screens.Edit.Setup return true; } - public bool ChangeAudioTrack(string path) + public bool ChangeAudioTrack(FileInfo source) { - var source = new FileInfo(path); - if (!source.Exists) return false; @@ -119,29 +119,29 @@ namespace osu.Game.Screens.Edit.Setup return true; } - private void backgroundChanged(ValueChangedEvent filePath) + private void backgroundChanged(ValueChangedEvent file) { - backgroundChooser.Text = string.IsNullOrEmpty(filePath.NewValue) + backgroundChooser.Text = file.NewValue == null ? "Click to select a background image" : "Click to replace the background image"; - if (filePath.NewValue != filePath.OldValue) + if (file.NewValue != file.OldValue) { - if (!ChangeBackgroundImage(filePath.NewValue)) - backgroundChooser.Current.Value = filePath.OldValue; + if (!ChangeBackgroundImage(file.NewValue)) + backgroundChooser.Current.Value = file.OldValue; } } - private void audioTrackChanged(ValueChangedEvent filePath) + private void audioTrackChanged(ValueChangedEvent file) { - audioTrackChooser.Text = string.IsNullOrEmpty(filePath.NewValue) + audioTrackChooser.Text = file.NewValue == null ? "Click to select a track" : "Click to replace the track"; - if (filePath.NewValue != filePath.OldValue) + if (file.NewValue != file.OldValue) { - if (!ChangeAudioTrack(filePath.NewValue)) - audioTrackChooser.Current.Value = filePath.OldValue; + if (!ChangeAudioTrack(file.NewValue)) + audioTrackChooser.Current.Value = file.OldValue; } } } From f1081db953887ba597675c772772d5a8ca94acff Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 16 Jun 2022 18:48:32 +0300 Subject: [PATCH 019/211] Fix background/track implicitly renamed on initial load --- .../Screens/Edit/Setup/ResourcesSection.cs | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 2471886d9b..5054f7a393 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -59,8 +59,10 @@ namespace osu.Game.Screens.Edit.Setup if (!string.IsNullOrEmpty(working.Value.Metadata.AudioFile)) audioTrackChooser.Current.Value = new FileInfo(working.Value.Metadata.AudioFile); - backgroundChooser.Current.BindValueChanged(backgroundChanged, true); - audioTrackChooser.Current.BindValueChanged(audioTrackChanged, true); + backgroundChooser.Current.BindValueChanged(backgroundChanged); + audioTrackChooser.Current.BindValueChanged(audioTrackChanged); + + updatePlaceholderText(); } public bool ChangeBackgroundImage(FileInfo source) @@ -121,28 +123,29 @@ namespace osu.Game.Screens.Edit.Setup private void backgroundChanged(ValueChangedEvent file) { - backgroundChooser.Text = file.NewValue == null - ? "Click to select a background image" - : "Click to replace the background image"; + if (!ChangeBackgroundImage(file.NewValue)) + backgroundChooser.Current.Value = file.OldValue; - if (file.NewValue != file.OldValue) - { - if (!ChangeBackgroundImage(file.NewValue)) - backgroundChooser.Current.Value = file.OldValue; - } + updatePlaceholderText(); } private void audioTrackChanged(ValueChangedEvent file) { - audioTrackChooser.Text = file.NewValue == null + if (!ChangeAudioTrack(file.NewValue)) + audioTrackChooser.Current.Value = file.OldValue; + + updatePlaceholderText(); + } + + private void updatePlaceholderText() + { + audioTrackChooser.Text = audioTrackChooser.Current.Value == null ? "Click to select a track" : "Click to replace the track"; - if (file.NewValue != file.OldValue) - { - if (!ChangeAudioTrack(file.NewValue)) - audioTrackChooser.Current.Value = file.OldValue; - } + backgroundChooser.Text = backgroundChooser.Current.Value == null + ? "Click to select a background image" + : "Click to replace the background image"; } } } From 6aee6895863be43435e648161c0c3e831cae5507 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 16 Jun 2022 18:50:28 +0300 Subject: [PATCH 020/211] Fix previous file lookup not using metadata properties --- osu.Game/Screens/Edit/Setup/ResourcesSection.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 5054f7a393..1a37f539e8 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -76,7 +76,7 @@ namespace osu.Game.Screens.Edit.Setup // remove the previous background for now. // in the future we probably want to check if this is being used elsewhere (other difficulties?) - var oldFile = set.Files.FirstOrDefault(f => Path.GetFileNameWithoutExtension(f.Filename) == destination.Name); + var oldFile = set.Files.FirstOrDefault(f => f.Filename == working.Value.Metadata.BackgroundFile); using (var stream = source.OpenRead()) { @@ -103,7 +103,7 @@ namespace osu.Game.Screens.Edit.Setup // remove the previous audio track for now. // in the future we probably want to check if this is being used elsewhere (other difficulties?) - var oldFile = set.Files.FirstOrDefault(f => Path.GetFileNameWithoutExtension(f.Filename) == destination.Name); + var oldFile = set.Files.FirstOrDefault(f => f.Filename == working.Value.Metadata.AudioFile); using (var stream = source.OpenRead()) { From 52538dc7083f2063149c8f08a249921c3c429acc Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 16 Jun 2022 19:46:04 +0300 Subject: [PATCH 021/211] Refactor `LatencyCursorContainer` to become a cursor container --- .../LatencyCursorContainer.cs | 48 +++++++++---------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs b/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs index e4c2b504cb..ecd3837512 100644 --- a/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs +++ b/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs @@ -2,55 +2,51 @@ // 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.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Framework.Input.States; -using osu.Game.Overlays; using osuTK; using osuTK.Input; namespace osu.Game.Screens.Utility.SampleComponents { - public class LatencyCursorContainer : LatencySampleComponent + public class LatencyCursorContainer : CursorContainer { - private Circle cursor = null!; + protected override Drawable CreateCursor() => new LatencyCursor(); - [Resolved] - private OverlayColourProvider overlayColourProvider { get; set; } = null!; + public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; public LatencyCursorContainer() { - Masking = true; + State.Value = Visibility.Hidden; } - protected override void LoadComplete() + protected override bool OnMouseMove(MouseMoveEvent e) { - base.LoadComplete(); - - InternalChild = cursor = new Circle - { - Size = new Vector2(40), - Origin = Anchor.Centre, - Colour = overlayColourProvider.Colour2, - }; + // CursorContainer implements IRequireHighFrequencyMousePosition, which bypasses limited rate updating, therefore scheduling is required. + // We can alternatively solve this by a PassThroughInputManager layer inside LatencyArea, + // but that would mean including input lag to this test, which may not be desired. + Schedule(() => base.OnMouseMove(e)); + return false; } - protected override bool OnHover(HoverEvent e) => false; - - protected override void UpdateAtLimitedRate(InputState inputState) + private class LatencyCursor : LatencySampleComponent { - cursor.Colour = inputState.Mouse.IsPressed(MouseButton.Left) ? overlayColourProvider.Content1 : overlayColourProvider.Colour2; - - if (IsActive.Value) + public LatencyCursor() { - cursor.Position = ToLocalSpace(inputState.Mouse.Position); - cursor.Alpha = 1; + AutoSizeAxes = Axes.Both; + Origin = Anchor.Centre; + + InternalChild = new Circle { Size = new Vector2(40) }; } - else + + protected override void UpdateAtLimitedRate(InputState inputState) { - cursor.Alpha = 0; + Colour = inputState.Mouse.IsPressed(MouseButton.Left) ? OverlayColourProvider.Content1 : OverlayColourProvider.Colour2; } } } From ed6817ae6a68b2385b8f0591453367d88a423459 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 16 Jun 2022 19:46:31 +0300 Subject: [PATCH 022/211] Allow switching between latency and menu cursor using `IProvideCursor` --- osu.Game/Screens/Utility/LatencyArea.cs | 14 ++++++++++---- osu.Game/Screens/Utility/LatencyCertifierScreen.cs | 2 -- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Utility/LatencyArea.cs b/osu.Game/Screens/Utility/LatencyArea.cs index 21688f0b0c..86cdbd39b9 100644 --- a/osu.Game/Screens/Utility/LatencyArea.cs +++ b/osu.Game/Screens/Utility/LatencyArea.cs @@ -8,8 +8,10 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; +using osu.Game.Graphics.Cursor; using osu.Game.Overlays; using osu.Game.Screens.Utility.SampleComponents; using osuTK.Input; @@ -17,7 +19,7 @@ using osuTK.Input; namespace osu.Game.Screens.Utility { [Cached] - public class LatencyArea : CompositeDrawable + public class LatencyArea : CompositeDrawable, IProvideCursor { [Resolved] private OverlayColourProvider overlayColourProvider { get; set; } = null!; @@ -36,6 +38,10 @@ namespace osu.Game.Screens.Utility public readonly Bindable VisualMode = new Bindable(); + public CursorContainer? Cursor { get; private set; } + + public bool ProvidingUserCursor => IsActiveArea.Value; + public LatencyArea(Key key, int? targetFrameRate) { this.key = key; @@ -87,7 +93,7 @@ namespace osu.Game.Screens.Utility { RelativeSizeAxes = Axes.Both, }, - new LatencyCursorContainer + Cursor = new LatencyCursorContainer { RelativeSizeAxes = Axes.Both, }, @@ -101,7 +107,7 @@ namespace osu.Game.Screens.Utility { RelativeSizeAxes = Axes.Both, }, - new LatencyCursorContainer + Cursor = new LatencyCursorContainer { RelativeSizeAxes = Axes.Both, }, @@ -115,7 +121,7 @@ namespace osu.Game.Screens.Utility { RelativeSizeAxes = Axes.Both, }, - new LatencyCursorContainer + Cursor = new LatencyCursorContainer { RelativeSizeAxes = Axes.Both, }, diff --git a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs index 8210e6825a..f8587e166c 100644 --- a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs +++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs @@ -41,8 +41,6 @@ namespace osu.Game.Screens.Utility public override bool HideOverlaysOnEnter => true; - public override bool CursorVisible => mainArea.Count == 0; - public override float BackgroundParallaxAmount => 0; private readonly LinkFlowContainer explanatoryText; From beb03316400ddbffecdf84943fb5e6f0a486d165 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 16 Jun 2022 19:56:56 +0300 Subject: [PATCH 023/211] Let latency certifier buttons steal hover from area --- osu.Game/Screens/Utility/ButtonWithKeyBind.cs | 2 ++ osu.Game/Screens/Utility/LatencyArea.cs | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Utility/ButtonWithKeyBind.cs b/osu.Game/Screens/Utility/ButtonWithKeyBind.cs index ef87e0bca7..ad60baafab 100644 --- a/osu.Game/Screens/Utility/ButtonWithKeyBind.cs +++ b/osu.Game/Screens/Utility/ButtonWithKeyBind.cs @@ -38,6 +38,8 @@ namespace osu.Game.Screens.Utility return base.OnKeyDown(e); } + protected override bool OnHover(HoverEvent e) => true; + [Resolved] private OverlayColourProvider overlayColourProvider { get; set; } = null!; diff --git a/osu.Game/Screens/Utility/LatencyArea.cs b/osu.Game/Screens/Utility/LatencyArea.cs index 86cdbd39b9..da37cab334 100644 --- a/osu.Game/Screens/Utility/LatencyArea.cs +++ b/osu.Game/Screens/Utility/LatencyArea.cs @@ -62,6 +62,10 @@ namespace osu.Game.Screens.Utility Colour = overlayColourProvider.Background6, RelativeSizeAxes = Axes.Both, }, + visualContent = new Container + { + RelativeSizeAxes = Axes.Both, + }, new ButtonWithKeyBind(key) { Text = "Feels better", @@ -71,10 +75,6 @@ namespace osu.Game.Screens.Utility Origin = Anchor.TopCentre, Action = () => ReportUserBest?.Invoke(), }, - visualContent = new Container - { - RelativeSizeAxes = Axes.Both, - }, }; IsActiveArea.BindValueChanged(active => From 8e088140b2c7709a8e5a49aa1efcec8c19815db9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 16 Jun 2022 20:09:10 +0300 Subject: [PATCH 024/211] Reword comment since `IRequireHighFrequencyMousePosition` isn't the issue --- .../Screens/Utility/SampleComponents/LatencyCursorContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs b/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs index ecd3837512..656aa6a8b3 100644 --- a/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs +++ b/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs @@ -27,7 +27,7 @@ namespace osu.Game.Screens.Utility.SampleComponents protected override bool OnMouseMove(MouseMoveEvent e) { - // CursorContainer implements IRequireHighFrequencyMousePosition, which bypasses limited rate updating, therefore scheduling is required. + // Scheduling is required to ensure updating of cursor position happens in limited rate. // We can alternatively solve this by a PassThroughInputManager layer inside LatencyArea, // but that would mean including input lag to this test, which may not be desired. Schedule(() => base.OnMouseMove(e)); From f7a27b412a18e8db958266e49df116c3ebfb8d7f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 16 Jun 2022 20:35:30 +0300 Subject: [PATCH 025/211] Revert "Let latency certifier buttons steal hover from area" This reverts commit beb03316400ddbffecdf84943fb5e6f0a486d165. --- osu.Game/Screens/Utility/ButtonWithKeyBind.cs | 2 -- osu.Game/Screens/Utility/LatencyArea.cs | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Utility/ButtonWithKeyBind.cs b/osu.Game/Screens/Utility/ButtonWithKeyBind.cs index ad60baafab..ef87e0bca7 100644 --- a/osu.Game/Screens/Utility/ButtonWithKeyBind.cs +++ b/osu.Game/Screens/Utility/ButtonWithKeyBind.cs @@ -38,8 +38,6 @@ namespace osu.Game.Screens.Utility return base.OnKeyDown(e); } - protected override bool OnHover(HoverEvent e) => true; - [Resolved] private OverlayColourProvider overlayColourProvider { get; set; } = null!; diff --git a/osu.Game/Screens/Utility/LatencyArea.cs b/osu.Game/Screens/Utility/LatencyArea.cs index da37cab334..86cdbd39b9 100644 --- a/osu.Game/Screens/Utility/LatencyArea.cs +++ b/osu.Game/Screens/Utility/LatencyArea.cs @@ -62,10 +62,6 @@ namespace osu.Game.Screens.Utility Colour = overlayColourProvider.Background6, RelativeSizeAxes = Axes.Both, }, - visualContent = new Container - { - RelativeSizeAxes = Axes.Both, - }, new ButtonWithKeyBind(key) { Text = "Feels better", @@ -75,6 +71,10 @@ namespace osu.Game.Screens.Utility Origin = Anchor.TopCentre, Action = () => ReportUserBest?.Invoke(), }, + visualContent = new Container + { + RelativeSizeAxes = Axes.Both, + }, }; IsActiveArea.BindValueChanged(active => From db02cb81c5aac24b82f08986d8c43a28ad24d208 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 16 Jun 2022 20:48:17 +0300 Subject: [PATCH 026/211] Fix file chooser path not opening home directory initially --- osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs index 6c56320666..ab83c2a2e4 100644 --- a/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs +++ b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs @@ -36,6 +36,8 @@ namespace osu.Game.Screens.Edit.Setup [Resolved] private OsuGameBase game { get; set; } = null!; + private string? chooserPath; + private readonly BindableWithCurrent current = new BindableWithCurrent(); public Bindable Current @@ -73,6 +75,8 @@ namespace osu.Game.Screens.Edit.Setup { if (file.NewValue != null) this.HidePopover(); + + chooserPath = file.NewValue?.DirectoryName; } Task ICanAcceptFiles.Import(params string[] paths) @@ -100,16 +104,16 @@ namespace osu.Game.Screens.Edit.Setup OnFocused = this.ShowPopover, }; - public Popover GetPopover() => new FileChooserPopover(handledExtensions, Current); + public Popover GetPopover() => new FileChooserPopover(handledExtensions, Current, chooserPath); private class FileChooserPopover : OsuPopover { - public FileChooserPopover(string[] handledExtensions, Bindable currentFile) + public FileChooserPopover(string[] handledExtensions, Bindable currentFile, string? chooserPath) { Child = new Container { Size = new Vector2(600, 400), - Child = new OsuFileSelector(currentFile.Value?.DirectoryName, handledExtensions) + Child = new OsuFileSelector(chooserPath, handledExtensions) { RelativeSizeAxes = Axes.Both, CurrentFile = { BindTarget = currentFile } From 6ff6a3f5b3395e32288bc04bab964410eb260dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 16 Jun 2022 21:51:31 +0200 Subject: [PATCH 027/211] Rename and document `chooserPath` --- osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs index ab83c2a2e4..5a2ac7424c 100644 --- a/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs +++ b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs @@ -17,6 +17,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; +using osu.Framework.Platform; using osu.Game.Database; using osu.Game.Graphics.UserInterfaceV2; using osuTK; @@ -36,7 +37,14 @@ namespace osu.Game.Screens.Edit.Setup [Resolved] private OsuGameBase game { get; set; } = null!; - private string? chooserPath; + /// + /// The initial path to use when displaying the . + /// + /// + /// Uses a value before the first selection is made + /// to ensure that the first selection starts at . + /// + private string? initialChooserPath; private readonly BindableWithCurrent current = new BindableWithCurrent(); @@ -76,7 +84,7 @@ namespace osu.Game.Screens.Edit.Setup if (file.NewValue != null) this.HidePopover(); - chooserPath = file.NewValue?.DirectoryName; + initialChooserPath = file.NewValue?.DirectoryName; } Task ICanAcceptFiles.Import(params string[] paths) @@ -104,7 +112,7 @@ namespace osu.Game.Screens.Edit.Setup OnFocused = this.ShowPopover, }; - public Popover GetPopover() => new FileChooserPopover(handledExtensions, Current, chooserPath); + public Popover GetPopover() => new FileChooserPopover(handledExtensions, Current, initialChooserPath); private class FileChooserPopover : OsuPopover { From 1f78a4fadd36ebfd1145ea162d6b47826cec664c Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 17 Jun 2022 16:56:09 +0900 Subject: [PATCH 028/211] New audio feedback for metronome --- .../Screens/Edit/Timing/MetronomeDisplay.cs | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index 2ecd66a05f..33325951e5 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -33,7 +33,9 @@ namespace osu.Game.Screens.Edit.Timing private IAdjustableClock metronomeClock; - private Sample clunk; + private Sample tick; + private Sample tickDownbeat; + private Sample latch; [Resolved] private OverlayColourProvider overlayColourProvider { get; set; } @@ -43,7 +45,9 @@ namespace osu.Game.Screens.Edit.Timing [BackgroundDependencyLoader] private void load(AudioManager audio) { - clunk = audio.Samples.Get(@"Multiplayer/countdown-tick"); + tick = audio.Samples.Get(@"UI/metronome-tick"); + tickDownbeat = audio.Samples.Get(@"UI/metronome-tick-downbeat"); + latch = audio.Samples.Get(@"UI/metronome-latch"); const float taper = 25; const float swing_vertical_offset = -23; @@ -248,14 +252,27 @@ namespace osu.Game.Screens.Edit.Timing if (BeatSyncSource.Clock?.IsRunning != true && isSwinging) { swing.ClearTransforms(true); + stick.FadeColour(overlayColourProvider.Colour2, 1000, Easing.OutQuint); + isSwinging = false; + + // instantly latch if pendulum arm is close enough to center (to prevent awkward delayed playback of latch sound) + if (Precision.AlmostEquals(swing.Rotation, 0, 1)) + { + swing.RotateTo(0); + latch?.Play(); + return; + } using (swing.BeginDelayedSequence(350)) { swing.RotateTo(0, 1000, Easing.OutQuint); - stick.FadeColour(overlayColourProvider.Colour2, 1000, Easing.OutQuint); + swing.Delay(250).Schedule(() => + { + // prevent playing latch sound if metronome has started back up again + if (!isSwinging) + latch?.Play(); + }); } - - isSwinging = false; } } @@ -286,13 +303,13 @@ namespace osu.Game.Screens.Edit.Timing if (!EnableClicking) return; - var channel = clunk?.GetChannel(); + var channel = beatIndex % timingPoint.TimeSignature.Numerator == 0 ? tickDownbeat?.GetChannel() : tick?.GetChannel(); - if (channel != null) - { - channel.Frequency.Value = RNG.NextDouble(0.98f, 1.02f); - channel.Play(); - } + if (channel == null) + return; + + channel.Frequency.Value = RNG.NextDouble(0.98f, 1.02f); + channel.Play(); }); } } From 869db5254019fcb924ac7bfb8578beb0e02bac20 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 17 Jun 2022 16:55:35 +0900 Subject: [PATCH 029/211] Tie loading layer to ongoing operation state --- .../Multiplayer/OnlineMultiplayerClient.cs | 8 +++--- .../Multiplayer/MultiplayerMatchSongSelect.cs | 26 +++++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index a3423d4189..ae1ac5fa47 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -202,14 +202,16 @@ namespace osu.Game.Online.Multiplayer return connection.InvokeAsync(nameof(IMultiplayerServer.AddPlaylistItem), item); } - public override Task EditPlaylistItem(MultiplayerPlaylistItem item) + public override async Task EditPlaylistItem(MultiplayerPlaylistItem item) { if (!IsConnected.Value) - return Task.CompletedTask; + return; Debug.Assert(connection != null); - return connection.InvokeAsync(nameof(IMultiplayerServer.EditPlaylistItem), item); + await Task.Delay(10000); + + await connection.InvokeAsync(nameof(IMultiplayerServer.EditPlaylistItem), item); } public override Task RemovePlaylistItem(long playlistItemId) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index b2355a9021..10479054e3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -7,6 +7,7 @@ using System; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; @@ -26,6 +27,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [Resolved] private OngoingOperationTracker operationTracker { get; set; } = null!; + private readonly IBindable operationInProgress = new Bindable(); private readonly long? itemToEdit; private LoadingLayer loadingLayer = null!; @@ -59,16 +61,33 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer AddInternal(loadingLayer = new LoadingLayer(true)); } + protected override void LoadComplete() + { + base.LoadComplete(); + + operationInProgress.BindTo(operationTracker.InProgress); + operationInProgress.BindValueChanged(_ => updateLoadingLayer(), true); + } + + private void updateLoadingLayer() + { + if (operationInProgress.Value) + loadingLayer.Show(); + else + loadingLayer.Hide(); + } + protected override void SelectItem(PlaylistItem item) { + if (operationInProgress.Value) + return; + // If the client is already in a room, update via the client. // Otherwise, update the playlist directly in preparation for it to be submitted to the API on match creation. if (client.Room != null) { selectionOperation = operationTracker.BeginOperation(); - loadingLayer.Show(); - var multiplayerItem = new MultiplayerPlaylistItem { ID = itemToEdit ?? 0, @@ -87,8 +106,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Schedule(() => { - loadingLayer.Hide(); - // If an error or server side trigger occurred this screen may have already exited by external means. if (this.IsCurrentScreen()) this.Exit(); @@ -99,7 +116,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Schedule(() => { - loadingLayer.Hide(); Carousel.AllowSelection = true; }); }); From 48ffd6aeb5c131a120a9c82e889348ebf3d21dfb Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Fri, 17 Jun 2022 11:28:58 -0400 Subject: [PATCH 030/211] stop component transform when skineditor is hidden --- .../Skinning/Editor/SkinSelectionHandler.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs index 2e2122f7c2..2496d7c657 100644 --- a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs +++ b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs @@ -11,6 +11,7 @@ using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Graphics.Containers; using osu.Framework.Utils; using osu.Game.Extensions; using osu.Game.Graphics.UserInterface; @@ -25,8 +26,17 @@ namespace osu.Game.Skinning.Editor [Resolved] private SkinEditor skinEditor { get; set; } + /// + /// Whether the 's state allows selected blueprints to undergo transformations. + /// Used to prevent operations from being performed on unloaded blueprints. + /// + private bool allowHandling => skinEditor.State.Value == Visibility.Visible; + public override bool HandleRotation(float angle) { + if (!allowHandling) + return false; + if (SelectedBlueprints.Count == 1) { // for single items, rotate around the origin rather than the selection centre. @@ -53,6 +63,9 @@ namespace osu.Game.Skinning.Editor public override bool HandleScale(Vector2 scale, Anchor anchor) { + if (!allowHandling) + return false; + // convert scale to screen space scale = ToScreenSpace(scale) - ToScreenSpace(Vector2.Zero); @@ -130,6 +143,9 @@ namespace osu.Game.Skinning.Editor public override bool HandleFlip(Direction direction, bool flipOverOrigin) { + if (!allowHandling) + return false; + var selectionQuad = getSelectionQuad(); Vector2 scaleFactor = direction == Direction.Horizontal ? new Vector2(-1, 1) : new Vector2(1, -1); @@ -150,6 +166,9 @@ namespace osu.Game.Skinning.Editor public override bool HandleMovement(MoveSelectionEvent moveEvent) { + if (!allowHandling) + return false; + foreach (var c in SelectedBlueprints) { var item = c.Item; From f3793c880911c8049ab645c02e0e38607ec2f5b0 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 17 Jun 2022 21:02:18 +0300 Subject: [PATCH 031/211] Add lightweight `TournamentPlayer` model --- .../Models/TournamentPlayer.cs | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 osu.Game.Tournament/Models/TournamentPlayer.cs diff --git a/osu.Game.Tournament/Models/TournamentPlayer.cs b/osu.Game.Tournament/Models/TournamentPlayer.cs new file mode 100644 index 0000000000..6fd2f178e1 --- /dev/null +++ b/osu.Game.Tournament/Models/TournamentPlayer.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.Game.Database; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Users; + +namespace osu.Game.Tournament.Models +{ + /// + /// A tournament player, containing simple information about the player. + /// + [Serializable] + public class TournamentPlayer : IUser + { + public int Id { get; set; } + + public string Username { get; set; } = string.Empty; + + /// + /// The player's country. + /// + public Country? Country { get; set; } + + /// + /// The player's global rank, or null if not available. + /// + public int? Rank { get; set; } + + /// + /// A URL to the player's profile cover. + /// + public string CoverUrl { get; set; } = string.Empty; + + public APIUser ToUser() + { + var user = new APIUser + { + Id = Id, + Username = Username, + Country = Country, + CoverUrl = CoverUrl, + }; + + user.Statistics = new UserStatistics + { + User = user, + GlobalRank = Rank + }; + + return user; + } + + int IHasOnlineID.OnlineID => Id; + + bool IUser.IsBot => false; + } +} From b977ce79959fbda38114cc5da3e1703c95eba7e7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 17 Jun 2022 21:03:33 +0300 Subject: [PATCH 032/211] Replace tournament player storage type with lightweight model --- .../TestSceneDrawableTournamentTeam.cs | 15 ++++----- .../TestSceneTournamentMatchChatDisplay.cs | 14 ++++---- .../TournamentTestScene.cs | 22 ++++++------- .../Components/DrawableTeamWithPlayers.cs | 3 +- osu.Game.Tournament/Models/TournamentTeam.cs | 5 ++- .../Screens/Editors/TeamEditorScreen.cs | 33 +++++++++---------- .../Screens/TeamIntro/SeedingScreen.cs | 2 +- osu.Game.Tournament/TournamentGameBase.cs | 23 ++++++------- 8 files changed, 54 insertions(+), 63 deletions(-) diff --git a/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs b/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs index 9ade9965c5..3cf65b1990 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs @@ -5,7 +5,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Tests.Visual; using osu.Game.Tournament.Components; using osu.Game.Tournament.Models; @@ -26,13 +25,13 @@ namespace osu.Game.Tournament.Tests.Components FullName = { Value = "Australia" }, Players = { - new APIUser { Username = "ASecretBox" }, - new APIUser { Username = "Dereban" }, - new APIUser { Username = "mReKk" }, - new APIUser { Username = "uyghti" }, - new APIUser { Username = "Parkes" }, - new APIUser { Username = "Shiroha" }, - new APIUser { Username = "Jordan The Bear" }, + new TournamentPlayer { Username = "ASecretBox" }, + new TournamentPlayer { Username = "Dereban" }, + new TournamentPlayer { Username = "mReKk" }, + new TournamentPlayer { Username = "uyghti" }, + new TournamentPlayer { Username = "Parkes" }, + new TournamentPlayer { Username = "Shiroha" }, + new TournamentPlayer { Username = "Jordan The Bear" }, } }; diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs index 4a4def10b5..3eac240be5 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs @@ -27,13 +27,13 @@ namespace osu.Game.Tournament.Tests.Components Colour = "f2ca34" }; - private readonly APIUser redUser = new APIUser + private readonly TournamentPlayer redPlayer = new TournamentPlayer { Username = "BanchoBot", Id = 3, }; - private readonly APIUser blueUser = new APIUser + private readonly TournamentPlayer bluePlayer = new TournamentPlayer { Username = "Zallius", Id = 4, @@ -59,11 +59,11 @@ namespace osu.Game.Tournament.Tests.Components { Team1 = { - Value = new TournamentTeam { Players = new BindableList { redUser } } + Value = new TournamentTeam { Players = new BindableList { redPlayer } } }, Team2 = { - Value = new TournamentTeam { Players = new BindableList { blueUser } } + Value = new TournamentTeam { Players = new BindableList { bluePlayer } } } }; @@ -82,19 +82,19 @@ namespace osu.Game.Tournament.Tests.Components AddStep("message from team red", () => testChannel.AddNewMessages(new Message(nextMessageId()) { - Sender = redUser, + Sender = redPlayer.ToUser(), Content = "I am team red." })); AddStep("message from team red", () => testChannel.AddNewMessages(new Message(nextMessageId()) { - Sender = redUser, + Sender = redPlayer.ToUser(), Content = "I plan to win!" })); AddStep("message from team blue", () => testChannel.AddNewMessages(new Message(nextMessageId()) { - Sender = blueUser, + Sender = bluePlayer.ToUser(), Content = "Not on my watch. Prepare to eat saaaaaaaaaand. Lots and lots of saaaaaaand." })); diff --git a/osu.Game.Tournament.Tests/TournamentTestScene.cs b/osu.Game.Tournament.Tests/TournamentTestScene.cs index d631d028bb..47ab3023e4 100644 --- a/osu.Game.Tournament.Tests/TournamentTestScene.cs +++ b/osu.Game.Tournament.Tests/TournamentTestScene.cs @@ -15,8 +15,6 @@ using osu.Game.Tests.Visual; using osu.Game.Tournament.IO; using osu.Game.Tournament.IPC; using osu.Game.Tournament.Models; -using osu.Game.Users; -using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tournament.Tests { @@ -123,11 +121,11 @@ namespace osu.Game.Tournament.Tests }, Players = { - new APIUser { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 12 } }, - new APIUser { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 16 } }, - new APIUser { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 20 } }, - new APIUser { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 24 } }, - new APIUser { Username = "Hello", Statistics = new UserStatistics { GlobalRank = 30 } }, + new TournamentPlayer { Username = "Hello", Rank = 12 }, + new TournamentPlayer { Username = "Hello", Rank = 16 }, + new TournamentPlayer { Username = "Hello", Rank = 20 }, + new TournamentPlayer { Username = "Hello", Rank = 24 }, + new TournamentPlayer { Username = "Hello", Rank = 30 }, } } }, @@ -140,11 +138,11 @@ namespace osu.Game.Tournament.Tests FullName = { Value = "United States" }, Players = { - new APIUser { Username = "Hello" }, - new APIUser { Username = "Hello" }, - new APIUser { Username = "Hello" }, - new APIUser { Username = "Hello" }, - new APIUser { Username = "Hello" }, + new TournamentPlayer { Username = "Hello" }, + new TournamentPlayer { Username = "Hello" }, + new TournamentPlayer { Username = "Hello" }, + new TournamentPlayer { Username = "Hello" }, + new TournamentPlayer { Username = "Hello" }, } } }, diff --git a/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs b/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs index 21de2bb0eb..fd62c53741 100644 --- a/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs +++ b/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs @@ -7,7 +7,6 @@ using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Tournament.Models; using osuTK; using osuTK.Graphics; @@ -56,7 +55,7 @@ namespace osu.Game.Tournament.Components }, }; - TournamentSpriteText createPlayerText(APIUser p) => + TournamentSpriteText createPlayerText(TournamentPlayer p) => new TournamentSpriteText { Text = p.Username, diff --git a/osu.Game.Tournament/Models/TournamentTeam.cs b/osu.Game.Tournament/Models/TournamentTeam.cs index 051f1a6d80..420b47da66 100644 --- a/osu.Game.Tournament/Models/TournamentTeam.cs +++ b/osu.Game.Tournament/Models/TournamentTeam.cs @@ -7,7 +7,6 @@ using System; using System.Linq; using Newtonsoft.Json; using osu.Framework.Bindables; -using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Tournament.Models { @@ -38,7 +37,7 @@ namespace osu.Game.Tournament.Models { get { - int[] ranks = Players.Select(p => p.Statistics?.GlobalRank) + int[] ranks = Players.Select(p => p.Rank) .Where(i => i.HasValue) .Select(i => i.Value) .ToArray(); @@ -59,7 +58,7 @@ namespace osu.Game.Tournament.Models }; [JsonProperty] - public BindableList Players { get; set; } = new BindableList(); + public BindableList Players { get; set; } = new BindableList(); public TournamentTeam() { diff --git a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs index 005d8f36bb..942f861770 100644 --- a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs @@ -15,7 +15,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Online.API; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Settings; using osu.Game.Tournament.Components; using osu.Game.Tournament.Models; @@ -202,14 +201,14 @@ namespace osu.Game.Tournament.Screens.Editors public void CreateNew() { - var user = new APIUser(); - team.Players.Add(user); - flow.Add(new PlayerRow(team, user)); + var player = new TournamentPlayer(); + team.Players.Add(player); + flow.Add(new PlayerRow(team, player)); } public class PlayerRow : CompositeDrawable { - private readonly APIUser user; + private readonly TournamentPlayer player; [Resolved] protected IAPIProvider API { get; private set; } @@ -217,13 +216,13 @@ namespace osu.Game.Tournament.Screens.Editors [Resolved] private TournamentGameBase game { get; set; } - private readonly Bindable userId = new Bindable(); + private readonly Bindable playerId = new Bindable(); private readonly Container drawableContainer; - public PlayerRow(TournamentTeam team, APIUser user) + public PlayerRow(TournamentTeam team, TournamentPlayer player) { - this.user = user; + this.player = player; Margin = new MarginPadding(10); @@ -254,7 +253,7 @@ namespace osu.Game.Tournament.Screens.Editors LabelText = "User ID", RelativeSizeAxes = Axes.None, Width = 200, - Current = userId, + Current = playerId, }, drawableContainer = new Container { @@ -272,7 +271,7 @@ namespace osu.Game.Tournament.Screens.Editors Action = () => { Expire(); - team.Players.Remove(user); + team.Players.Remove(player); }, } }; @@ -281,27 +280,27 @@ namespace osu.Game.Tournament.Screens.Editors [BackgroundDependencyLoader] private void load() { - userId.Value = user.Id; - userId.BindValueChanged(id => + playerId.Value = player.Id; + playerId.BindValueChanged(id => { - user.Id = id.NewValue ?? 0; + player.Id = id.NewValue ?? 0; if (id.NewValue != id.OldValue) - user.Username = string.Empty; + player.Username = string.Empty; - if (!string.IsNullOrEmpty(user.Username)) + if (!string.IsNullOrEmpty(player.Username)) { updatePanel(); return; } - game.PopulateUser(user, updatePanel, updatePanel); + game.PopulatePlayer(player, updatePanel, updatePanel); }, true); } private void updatePanel() { - drawableContainer.Child = new UserGridPanel(user) { Width = 300 }; + drawableContainer.Child = new UserGridPanel(player.ToUser()) { Width = 300 }; } } } diff --git a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs index b9559015d6..df6e8e816e 100644 --- a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs +++ b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs @@ -257,7 +257,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro }; foreach (var p in team.Players) - fill.Add(new RowDisplay(p.Username, p.Statistics?.GlobalRank?.ToString("\\##,0") ?? "-")); + fill.Add(new RowDisplay(p.Username, p.Rank?.ToString("\\##,0") ?? "-")); } internal class RowDisplay : CompositeDrawable diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 2d6d5a01e4..3fa6bca0be 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -22,7 +22,6 @@ using osu.Game.Tournament.IO; using osu.Game.Tournament.IPC; using osu.Game.Tournament.Models; using osuTK.Input; -using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tournament { @@ -187,9 +186,7 @@ namespace osu.Game.Tournament { var playersRequiringPopulation = ladder.Teams .SelectMany(t => t.Players) - .Where(p => string.IsNullOrEmpty(p.Username) - || p.Statistics?.GlobalRank == null - || p.Statistics?.CountryRank == null).ToList(); + .Where(p => string.IsNullOrEmpty(p.Username) || p.Rank == null).ToList(); if (playersRequiringPopulation.Count == 0) return false; @@ -197,7 +194,7 @@ namespace osu.Game.Tournament for (int i = 0; i < playersRequiringPopulation.Count; i++) { var p = playersRequiringPopulation[i]; - PopulateUser(p, immediate: true); + PopulatePlayer(p, immediate: true); updateLoadProgressMessage($"Populating user stats ({i} / {playersRequiringPopulation.Count})"); } @@ -259,9 +256,9 @@ namespace osu.Game.Tournament private void updateLoadProgressMessage(string s) => Schedule(() => initialisationText.Text = s); - public void PopulateUser(APIUser user, Action success = null, Action failure = null, bool immediate = false) + public void PopulatePlayer(TournamentPlayer player, Action success = null, Action failure = null, bool immediate = false) { - var req = new GetUserRequest(user.Id, ladder.Ruleset.Value); + var req = new GetUserRequest(player.Id, ladder.Ruleset.Value); if (immediate) { @@ -273,7 +270,7 @@ namespace osu.Game.Tournament req.Success += res => { populate(); }; req.Failure += _ => { - user.Id = 1; + player.Id = 1; failure?.Invoke(); }; @@ -287,12 +284,12 @@ namespace osu.Game.Tournament if (res == null) return; - user.Id = res.Id; + player.Id = res.Id; - user.Username = res.Username; - user.Statistics = res.Statistics; - user.Country = res.Country; - user.Cover = res.Cover; + player.Username = res.Username; + player.CoverUrl = res.CoverUrl; + player.Country = res.Country; + player.Rank = res.Statistics?.GlobalRank; success?.Invoke(); } From c4d69405bfd5e38d348cabe89112489b14d51c5b Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Fri, 17 Jun 2022 21:18:16 +0100 Subject: [PATCH 033/211] Adjust speed ratio fraction to avoid division by 0 --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs index 3be4d621eb..7782aa90f3 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators double currDeltaTime = Math.Max(1, osuCurrObj.DeltaTime); double nextDeltaTime = Math.Max(1, osuNextObj.DeltaTime); double deltaDifference = Math.Abs(nextDeltaTime - currDeltaTime); - double speedRatio = Math.Min(1, currDeltaTime / deltaDifference); + double speedRatio = currDeltaTime / Math.Max(currDeltaTime, deltaDifference); double windowRatio = Math.Pow(Math.Min(1, currDeltaTime / greatWindowFull), 2); doubletapness = Math.Pow(speedRatio, 1 - windowRatio); } From 200b23c6894b35d5a13b90c62f1ffc82c573be45 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 18 Jun 2022 01:30:54 +0300 Subject: [PATCH 034/211] Add lightweight `TournamentBeatmap` model --- .../Models/TournamentBeatmap.cs | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 osu.Game.Tournament/Models/TournamentBeatmap.cs diff --git a/osu.Game.Tournament/Models/TournamentBeatmap.cs b/osu.Game.Tournament/Models/TournamentBeatmap.cs new file mode 100644 index 0000000000..274fddc490 --- /dev/null +++ b/osu.Game.Tournament/Models/TournamentBeatmap.cs @@ -0,0 +1,99 @@ +// 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.Extensions.ObjectExtensions; +using osu.Game.Beatmaps; +using osu.Game.Extensions; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Rulesets; + +namespace osu.Game.Tournament.Models +{ + public class TournamentBeatmap : IBeatmapInfo, IBeatmapSetOnlineInfo + { + public int OnlineID { get; set; } + + public string DifficultyName { get; set; } = string.Empty; + + public double BPM { get; set; } + + public double Length { get; set; } + + public double StarRating { get; set; } + + public IBeatmapMetadataInfo Metadata { get; set; } = new BeatmapMetadata(); + + public IBeatmapDifficultyInfo Difficulty { get; set; } = new BeatmapDifficulty(); + + public BeatmapSetOnlineCovers Covers { get; set; } + + public TournamentBeatmap() + { + } + + public TournamentBeatmap(APIBeatmap beatmap) + { + OnlineID = beatmap.OnlineID; + DifficultyName = beatmap.DifficultyName; + BPM = beatmap.BPM; + Length = beatmap.Length; + StarRating = beatmap.StarRating; + Metadata = beatmap.Metadata; + Difficulty = beatmap.Difficulty; + Covers = beatmap.BeatmapSet.AsNonNull().Covers; + } + + public bool Equals(IBeatmapInfo? other) => other is TournamentBeatmap b && this.MatchesOnlineID(b); + + #region IBeatmapInfo/IBeatmapSetOnlineInfo explicit implementation + + IBeatmapSetInfo IBeatmapInfo.BeatmapSet => throw new NotImplementedException(); + + string IBeatmapSetOnlineInfo.Preview => throw new NotImplementedException(); + + double IBeatmapSetOnlineInfo.BPM => throw new NotImplementedException(); + + int IBeatmapSetOnlineInfo.PlayCount => throw new NotImplementedException(); + + int IBeatmapSetOnlineInfo.FavouriteCount => throw new NotImplementedException(); + + bool IBeatmapSetOnlineInfo.HasFavourited => throw new NotImplementedException(); + + BeatmapSetOnlineAvailability IBeatmapSetOnlineInfo.Availability => throw new NotImplementedException(); + + BeatmapSetOnlineGenre IBeatmapSetOnlineInfo.Genre => throw new NotImplementedException(); + + BeatmapSetOnlineLanguage IBeatmapSetOnlineInfo.Language => throw new NotImplementedException(); + + int? IBeatmapSetOnlineInfo.TrackId => throw new NotImplementedException(); + + int[] IBeatmapSetOnlineInfo.Ratings => throw new NotImplementedException(); + + BeatmapSetHypeStatus IBeatmapSetOnlineInfo.HypeStatus => throw new NotImplementedException(); + + BeatmapSetNominationStatus IBeatmapSetOnlineInfo.NominationStatus => throw new NotImplementedException(); + + string IBeatmapInfo.Hash => throw new NotImplementedException(); + + string IBeatmapInfo.MD5Hash => throw new NotImplementedException(); + + IRulesetInfo IBeatmapInfo.Ruleset => throw new NotImplementedException(); + + DateTimeOffset IBeatmapSetOnlineInfo.Submitted => throw new NotImplementedException(); + + DateTimeOffset? IBeatmapSetOnlineInfo.Ranked => throw new NotImplementedException(); + + DateTimeOffset? IBeatmapSetOnlineInfo.LastUpdated => throw new NotImplementedException(); + + BeatmapOnlineStatus IBeatmapSetOnlineInfo.Status => throw new NotImplementedException(); + + bool IBeatmapSetOnlineInfo.HasExplicitContent => throw new NotImplementedException(); + + bool IBeatmapSetOnlineInfo.HasVideo => throw new NotImplementedException(); + + bool IBeatmapSetOnlineInfo.HasStoryboard => throw new NotImplementedException(); + + #endregion + } +} From 9f97d1a7db59e119adca33449f960794f1bed0a2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 18 Jun 2022 01:34:09 +0300 Subject: [PATCH 035/211] Replace tournament beatmap storage type with lightweight model --- osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs | 2 +- .../Components/TestSceneTournamentBeatmapPanel.cs | 3 ++- .../Components/TestSceneTournamentModDisplay.cs | 3 ++- osu.Game.Tournament.Tests/TournamentTestScene.cs | 8 ++++---- osu.Game.Tournament/Components/SongBar.cs | 6 +++--- osu.Game.Tournament/Components/TournamentBeatmapPanel.cs | 7 +++---- osu.Game.Tournament/IPC/FileBasedIPC.cs | 2 +- osu.Game.Tournament/IPC/MatchIPCInfo.cs | 4 ++-- osu.Game.Tournament/Models/RoundBeatmap.cs | 3 +-- osu.Game.Tournament/Models/SeedingBeatmap.cs | 3 +-- osu.Game.Tournament/Screens/BeatmapInfoScreen.cs | 4 ++-- osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs | 2 +- .../Screens/Editors/SeedingEditorScreen.cs | 2 +- osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs | 3 +-- osu.Game.Tournament/TournamentGameBase.cs | 8 ++++---- 15 files changed, 29 insertions(+), 31 deletions(-) diff --git a/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs b/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs index f90269ae60..992baa48a3 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs @@ -42,7 +42,7 @@ namespace osu.Game.Tournament.Tests.Components beatmap.Length = 123456; beatmap.BPM = 133; - songBar.Beatmap = beatmap; + songBar.Beatmap = new TournamentBeatmap(beatmap); }); AddStep("set mods to HR", () => songBar.Mods = LegacyMods.HardRock); AddStep("set mods to DT", () => songBar.Mods = LegacyMods.DoubleTime); diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentBeatmapPanel.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentBeatmapPanel.cs index 1030aae903..adfe048ce4 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentBeatmapPanel.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentBeatmapPanel.cs @@ -10,6 +10,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Tests.Visual; using osu.Game.Tournament.Components; +using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Tests.Components { @@ -32,7 +33,7 @@ namespace osu.Game.Tournament.Tests.Components private void success(APIBeatmap beatmap) { - Add(new TournamentBeatmapPanel(beatmap) + Add(new TournamentBeatmapPanel(new TournamentBeatmap(beatmap)) { Anchor = Anchor.Centre, Origin = Anchor.Centre diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs index fdd5578228..263617ddf7 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs @@ -11,6 +11,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Tournament.Components; +using osu.Game.Tournament.Models; using osuTK; namespace osu.Game.Tournament.Tests.Components @@ -53,7 +54,7 @@ namespace osu.Game.Tournament.Tests.Components foreach (var mod in mods) { - fillFlow.Add(new TournamentBeatmapPanel(beatmap, mod.Acronym) + fillFlow.Add(new TournamentBeatmapPanel(new TournamentBeatmap(beatmap), mod.Acronym) { Anchor = Anchor.Centre, Origin = Anchor.Centre diff --git a/osu.Game.Tournament.Tests/TournamentTestScene.cs b/osu.Game.Tournament.Tests/TournamentTestScene.cs index d631d028bb..c30496812f 100644 --- a/osu.Game.Tournament.Tests/TournamentTestScene.cs +++ b/osu.Game.Tournament.Tests/TournamentTestScene.cs @@ -9,7 +9,7 @@ using osu.Framework.Allocation; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Framework.Utils; -using osu.Game.Online.API.Requests.Responses; +using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Tests.Visual; using osu.Game.Tournament.IO; @@ -154,10 +154,10 @@ namespace osu.Game.Tournament.Tests } }; - public static APIBeatmap CreateSampleBeatmap() => - new APIBeatmap + public static TournamentBeatmap CreateSampleBeatmap() => + new TournamentBeatmap { - BeatmapSet = new APIBeatmapSet + Metadata = new BeatmapMetadata { Title = "Test Title", Artist = "Test Artist", diff --git a/osu.Game.Tournament/Components/SongBar.cs b/osu.Game.Tournament/Components/SongBar.cs index ecc655da99..a9056166be 100644 --- a/osu.Game.Tournament/Components/SongBar.cs +++ b/osu.Game.Tournament/Components/SongBar.cs @@ -14,9 +14,9 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.Legacy; using osu.Game.Extensions; using osu.Game.Graphics; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Screens.Menu; +using osu.Game.Tournament.Models; using osuTK; using osuTK.Graphics; @@ -24,14 +24,14 @@ namespace osu.Game.Tournament.Components { public class SongBar : CompositeDrawable { - private APIBeatmap beatmap; + private TournamentBeatmap beatmap; public const float HEIGHT = 145 / 2f; [Resolved] private IBindable ruleset { get; set; } - public APIBeatmap Beatmap + public TournamentBeatmap Beatmap { set { diff --git a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs index 6416abe8a9..462743cc3d 100644 --- a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs +++ b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs @@ -14,7 +14,6 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Tournament.Models; using osuTK.Graphics; @@ -22,7 +21,7 @@ namespace osu.Game.Tournament.Components { public class TournamentBeatmapPanel : CompositeDrawable { - public readonly APIBeatmap Beatmap; + public readonly TournamentBeatmap Beatmap; private readonly string mod; @@ -31,7 +30,7 @@ namespace osu.Game.Tournament.Components private readonly Bindable currentMatch = new Bindable(); private Box flash; - public TournamentBeatmapPanel(APIBeatmap beatmap, string mod = null) + public TournamentBeatmapPanel(TournamentBeatmap beatmap, string mod = null) { if (beatmap == null) throw new ArgumentNullException(nameof(beatmap)); @@ -61,7 +60,7 @@ namespace osu.Game.Tournament.Components { RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(0.5f), - OnlineInfo = Beatmap.BeatmapSet, + OnlineInfo = Beatmap, }, new FillFlowContainer { diff --git a/osu.Game.Tournament/IPC/FileBasedIPC.cs b/osu.Game.Tournament/IPC/FileBasedIPC.cs index 77af3e9b58..ad564c58c3 100644 --- a/osu.Game.Tournament/IPC/FileBasedIPC.cs +++ b/osu.Game.Tournament/IPC/FileBasedIPC.cs @@ -96,7 +96,7 @@ namespace osu.Game.Tournament.IPC else { beatmapLookupRequest = new GetBeatmapRequest(new APIBeatmap { OnlineID = beatmapId }); - beatmapLookupRequest.Success += b => Beatmap.Value = b; + beatmapLookupRequest.Success += b => Beatmap.Value = new TournamentBeatmap(b); API.Queue(beatmapLookupRequest); } } diff --git a/osu.Game.Tournament/IPC/MatchIPCInfo.cs b/osu.Game.Tournament/IPC/MatchIPCInfo.cs index ef1e36f871..f438923803 100644 --- a/osu.Game.Tournament/IPC/MatchIPCInfo.cs +++ b/osu.Game.Tournament/IPC/MatchIPCInfo.cs @@ -6,13 +6,13 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Beatmaps.Legacy; -using osu.Game.Online.API.Requests.Responses; +using osu.Game.Tournament.Models; namespace osu.Game.Tournament.IPC { public class MatchIPCInfo : Component { - public Bindable Beatmap { get; } = new Bindable(); + public Bindable Beatmap { get; } = new Bindable(); public Bindable Mods { get; } = new Bindable(); public Bindable State { get; } = new Bindable(); public Bindable ChatChannel { get; } = new Bindable(); diff --git a/osu.Game.Tournament/Models/RoundBeatmap.cs b/osu.Game.Tournament/Models/RoundBeatmap.cs index 90e31ba352..65ef77e53d 100644 --- a/osu.Game.Tournament/Models/RoundBeatmap.cs +++ b/osu.Game.Tournament/Models/RoundBeatmap.cs @@ -4,7 +4,6 @@ #nullable disable using Newtonsoft.Json; -using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Tournament.Models { @@ -14,6 +13,6 @@ namespace osu.Game.Tournament.Models public string Mods; [JsonProperty("BeatmapInfo")] - public APIBeatmap Beatmap; + public TournamentBeatmap Beatmap; } } diff --git a/osu.Game.Tournament/Models/SeedingBeatmap.cs b/osu.Game.Tournament/Models/SeedingBeatmap.cs index c854488319..03beb7ca9a 100644 --- a/osu.Game.Tournament/Models/SeedingBeatmap.cs +++ b/osu.Game.Tournament/Models/SeedingBeatmap.cs @@ -5,7 +5,6 @@ using Newtonsoft.Json; using osu.Framework.Bindables; -using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Tournament.Models { @@ -14,7 +13,7 @@ namespace osu.Game.Tournament.Models public int ID; [JsonProperty("BeatmapInfo")] - public APIBeatmap Beatmap; + public TournamentBeatmap Beatmap; public long Score; diff --git a/osu.Game.Tournament/Screens/BeatmapInfoScreen.cs b/osu.Game.Tournament/Screens/BeatmapInfoScreen.cs index 296267a4bc..763f576afe 100644 --- a/osu.Game.Tournament/Screens/BeatmapInfoScreen.cs +++ b/osu.Game.Tournament/Screens/BeatmapInfoScreen.cs @@ -7,9 +7,9 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Beatmaps.Legacy; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Tournament.Components; using osu.Game.Tournament.IPC; +using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Screens { @@ -39,7 +39,7 @@ namespace osu.Game.Tournament.Screens SongBar.Mods = mods.NewValue; } - private void beatmapChanged(ValueChangedEvent beatmap) + private void beatmapChanged(ValueChangedEvent beatmap) { SongBar.FadeInFromZero(300, Easing.OutQuint); SongBar.Beatmap = beatmap.NewValue; diff --git a/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs index 214ae65289..1b670f4b69 100644 --- a/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs @@ -239,7 +239,7 @@ namespace osu.Game.Tournament.Screens.Editors req.Success += res => { - Model.Beatmap = res; + Model.Beatmap = new TournamentBeatmap(res); updatePanel(); }; diff --git a/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs index 1377c11225..1bc929604d 100644 --- a/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs @@ -241,7 +241,7 @@ namespace osu.Game.Tournament.Screens.Editors req.Success += res => { - Model.Beatmap = res; + Model.Beatmap = new TournamentBeatmap(res); updatePanel(); }; diff --git a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs index 7ac4510ae5..5eb2142fae 100644 --- a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs +++ b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Framework.Threading; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Tournament.Components; using osu.Game.Tournament.IPC; using osu.Game.Tournament.Models; @@ -107,7 +106,7 @@ namespace osu.Game.Tournament.Screens.MapPool ipc.Beatmap.BindValueChanged(beatmapChanged); } - private void beatmapChanged(ValueChangedEvent beatmap) + private void beatmapChanged(ValueChangedEvent beatmap) { if (CurrentMatch.Value == null || CurrentMatch.Value.PicksBans.Count(p => p.Type == ChoiceType.Ban) < 2) return; diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 2d6d5a01e4..eb04d098f7 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -211,7 +211,7 @@ namespace osu.Game.Tournament { var beatmapsRequiringPopulation = ladder.Rounds .SelectMany(r => r.Beatmaps) - .Where(b => string.IsNullOrEmpty(b.Beatmap?.BeatmapSet?.Title) && b.ID > 0).ToList(); + .Where(b => b.Beatmap?.OnlineID == 0 && b.ID > 0).ToList(); if (beatmapsRequiringPopulation.Count == 0) return false; @@ -222,7 +222,7 @@ namespace osu.Game.Tournament var req = new GetBeatmapRequest(new APIBeatmap { OnlineID = b.ID }); API.Perform(req); - b.Beatmap = req.Response ?? new APIBeatmap(); + b.Beatmap = new TournamentBeatmap(req.Response ?? new APIBeatmap()); updateLoadProgressMessage($"Populating round beatmaps ({i} / {beatmapsRequiringPopulation.Count})"); } @@ -238,7 +238,7 @@ namespace osu.Game.Tournament var beatmapsRequiringPopulation = ladder.Teams .SelectMany(r => r.SeedingResults) .SelectMany(r => r.Beatmaps) - .Where(b => string.IsNullOrEmpty(b.Beatmap?.BeatmapSet?.Title) && b.ID > 0).ToList(); + .Where(b => b.Beatmap?.OnlineID == 0 && b.ID > 0).ToList(); if (beatmapsRequiringPopulation.Count == 0) return false; @@ -249,7 +249,7 @@ namespace osu.Game.Tournament var req = new GetBeatmapRequest(new APIBeatmap { OnlineID = b.ID }); API.Perform(req); - b.Beatmap = req.Response ?? new APIBeatmap(); + b.Beatmap = new TournamentBeatmap(req.Response ?? new APIBeatmap()); updateLoadProgressMessage($"Populating seeding beatmaps ({i} / {beatmapsRequiringPopulation.Count})"); } From 60903be566c46aeb0481f2b10c1fd5096e8887ac Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 18 Jun 2022 01:46:37 +0300 Subject: [PATCH 036/211] Standardise naming for online ID Rather than continuing with `ID` or `Id`, this should follow the new standards and use `OnlineID` instead. Only updating this since it's a newly introduced class. --- .../Components/TestSceneTournamentMatchChatDisplay.cs | 4 ++-- osu.Game.Tournament/Models/TournamentPlayer.cs | 9 ++++----- osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs | 4 ++-- osu.Game.Tournament/TournamentGameBase.cs | 6 +++--- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs index 3eac240be5..a95ae4b8ba 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs @@ -30,13 +30,13 @@ namespace osu.Game.Tournament.Tests.Components private readonly TournamentPlayer redPlayer = new TournamentPlayer { Username = "BanchoBot", - Id = 3, + OnlineID = 3, }; private readonly TournamentPlayer bluePlayer = new TournamentPlayer { Username = "Zallius", - Id = 4, + OnlineID = 4, }; [Cached] diff --git a/osu.Game.Tournament/Models/TournamentPlayer.cs b/osu.Game.Tournament/Models/TournamentPlayer.cs index 6fd2f178e1..976936ab07 100644 --- a/osu.Game.Tournament/Models/TournamentPlayer.cs +++ b/osu.Game.Tournament/Models/TournamentPlayer.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Game.Database; +using Newtonsoft.Json; using osu.Game.Online.API.Requests.Responses; using osu.Game.Users; @@ -14,7 +14,8 @@ namespace osu.Game.Tournament.Models [Serializable] public class TournamentPlayer : IUser { - public int Id { get; set; } + [JsonProperty(@"id")] + public int OnlineID { get; set; } public string Username { get; set; } = string.Empty; @@ -37,7 +38,7 @@ namespace osu.Game.Tournament.Models { var user = new APIUser { - Id = Id, + Id = OnlineID, Username = Username, Country = Country, CoverUrl = CoverUrl, @@ -52,8 +53,6 @@ namespace osu.Game.Tournament.Models return user; } - int IHasOnlineID.OnlineID => Id; - bool IUser.IsBot => false; } } diff --git a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs index 942f861770..f29c45c949 100644 --- a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs @@ -280,10 +280,10 @@ namespace osu.Game.Tournament.Screens.Editors [BackgroundDependencyLoader] private void load() { - playerId.Value = player.Id; + playerId.Value = player.OnlineID; playerId.BindValueChanged(id => { - player.Id = id.NewValue ?? 0; + player.OnlineID = id.NewValue ?? 0; if (id.NewValue != id.OldValue) player.Username = string.Empty; diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 3fa6bca0be..f53e36a61e 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -258,7 +258,7 @@ namespace osu.Game.Tournament public void PopulatePlayer(TournamentPlayer player, Action success = null, Action failure = null, bool immediate = false) { - var req = new GetUserRequest(player.Id, ladder.Ruleset.Value); + var req = new GetUserRequest(player.OnlineID, ladder.Ruleset.Value); if (immediate) { @@ -270,7 +270,7 @@ namespace osu.Game.Tournament req.Success += res => { populate(); }; req.Failure += _ => { - player.Id = 1; + player.OnlineID = 1; failure?.Invoke(); }; @@ -284,7 +284,7 @@ namespace osu.Game.Tournament if (res == null) return; - player.Id = res.Id; + player.OnlineID = res.Id; player.Username = res.Username; player.CoverUrl = res.CoverUrl; From 4c47996130de73ed0d4f87be47c4e65c064111ed Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 18 Jun 2022 02:33:26 +0300 Subject: [PATCH 037/211] `TournamentPlayer` -> `TournamentUser` --- .../TestSceneDrawableTournamentTeam.cs | 14 ++++++------ .../TestSceneTournamentMatchChatDisplay.cs | 14 ++++++------ .../TournamentTestScene.cs | 20 ++++++++--------- .../Components/DrawableTeamWithPlayers.cs | 2 +- osu.Game.Tournament/Models/TournamentTeam.cs | 2 +- ...{TournamentPlayer.cs => TournamentUser.cs} | 6 ++--- .../Screens/Editors/TeamEditorScreen.cs | 22 +++++++++---------- osu.Game.Tournament/TournamentGameBase.cs | 16 +++++++------- 8 files changed, 48 insertions(+), 48 deletions(-) rename osu.Game.Tournament/Models/{TournamentPlayer.cs => TournamentUser.cs} (89%) diff --git a/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs b/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs index 3cf65b1990..4ea7e8008a 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs @@ -25,13 +25,13 @@ namespace osu.Game.Tournament.Tests.Components FullName = { Value = "Australia" }, Players = { - new TournamentPlayer { Username = "ASecretBox" }, - new TournamentPlayer { Username = "Dereban" }, - new TournamentPlayer { Username = "mReKk" }, - new TournamentPlayer { Username = "uyghti" }, - new TournamentPlayer { Username = "Parkes" }, - new TournamentPlayer { Username = "Shiroha" }, - new TournamentPlayer { Username = "Jordan The Bear" }, + new TournamentUser { Username = "ASecretBox" }, + new TournamentUser { Username = "Dereban" }, + new TournamentUser { Username = "mReKk" }, + new TournamentUser { Username = "uyghti" }, + new TournamentUser { Username = "Parkes" }, + new TournamentUser { Username = "Shiroha" }, + new TournamentUser { Username = "Jordan The Bear" }, } }; diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs index a95ae4b8ba..eb8b0dfbe6 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs @@ -27,13 +27,13 @@ namespace osu.Game.Tournament.Tests.Components Colour = "f2ca34" }; - private readonly TournamentPlayer redPlayer = new TournamentPlayer + private readonly TournamentUser redUser = new TournamentUser { Username = "BanchoBot", OnlineID = 3, }; - private readonly TournamentPlayer bluePlayer = new TournamentPlayer + private readonly TournamentUser blueUser = new TournamentUser { Username = "Zallius", OnlineID = 4, @@ -59,11 +59,11 @@ namespace osu.Game.Tournament.Tests.Components { Team1 = { - Value = new TournamentTeam { Players = new BindableList { redPlayer } } + Value = new TournamentTeam { Players = new BindableList { redUser } } }, Team2 = { - Value = new TournamentTeam { Players = new BindableList { bluePlayer } } + Value = new TournamentTeam { Players = new BindableList { blueUser } } } }; @@ -82,19 +82,19 @@ namespace osu.Game.Tournament.Tests.Components AddStep("message from team red", () => testChannel.AddNewMessages(new Message(nextMessageId()) { - Sender = redPlayer.ToUser(), + Sender = redUser.ToAPIUser(), Content = "I am team red." })); AddStep("message from team red", () => testChannel.AddNewMessages(new Message(nextMessageId()) { - Sender = redPlayer.ToUser(), + Sender = redUser.ToAPIUser(), Content = "I plan to win!" })); AddStep("message from team blue", () => testChannel.AddNewMessages(new Message(nextMessageId()) { - Sender = bluePlayer.ToUser(), + Sender = blueUser.ToAPIUser(), Content = "Not on my watch. Prepare to eat saaaaaaaaaand. Lots and lots of saaaaaaand." })); diff --git a/osu.Game.Tournament.Tests/TournamentTestScene.cs b/osu.Game.Tournament.Tests/TournamentTestScene.cs index 47ab3023e4..ea7d6e7827 100644 --- a/osu.Game.Tournament.Tests/TournamentTestScene.cs +++ b/osu.Game.Tournament.Tests/TournamentTestScene.cs @@ -121,11 +121,11 @@ namespace osu.Game.Tournament.Tests }, Players = { - new TournamentPlayer { Username = "Hello", Rank = 12 }, - new TournamentPlayer { Username = "Hello", Rank = 16 }, - new TournamentPlayer { Username = "Hello", Rank = 20 }, - new TournamentPlayer { Username = "Hello", Rank = 24 }, - new TournamentPlayer { Username = "Hello", Rank = 30 }, + new TournamentUser { Username = "Hello", Rank = 12 }, + new TournamentUser { Username = "Hello", Rank = 16 }, + new TournamentUser { Username = "Hello", Rank = 20 }, + new TournamentUser { Username = "Hello", Rank = 24 }, + new TournamentUser { Username = "Hello", Rank = 30 }, } } }, @@ -138,11 +138,11 @@ namespace osu.Game.Tournament.Tests FullName = { Value = "United States" }, Players = { - new TournamentPlayer { Username = "Hello" }, - new TournamentPlayer { Username = "Hello" }, - new TournamentPlayer { Username = "Hello" }, - new TournamentPlayer { Username = "Hello" }, - new TournamentPlayer { Username = "Hello" }, + new TournamentUser { Username = "Hello" }, + new TournamentUser { Username = "Hello" }, + new TournamentUser { Username = "Hello" }, + new TournamentUser { Username = "Hello" }, + new TournamentUser { Username = "Hello" }, } } }, diff --git a/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs b/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs index fd62c53741..0bb35d534c 100644 --- a/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs +++ b/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs @@ -55,7 +55,7 @@ namespace osu.Game.Tournament.Components }, }; - TournamentSpriteText createPlayerText(TournamentPlayer p) => + TournamentSpriteText createPlayerText(TournamentUser p) => new TournamentSpriteText { Text = p.Username, diff --git a/osu.Game.Tournament/Models/TournamentTeam.cs b/osu.Game.Tournament/Models/TournamentTeam.cs index 420b47da66..9dbe23b4b3 100644 --- a/osu.Game.Tournament/Models/TournamentTeam.cs +++ b/osu.Game.Tournament/Models/TournamentTeam.cs @@ -58,7 +58,7 @@ namespace osu.Game.Tournament.Models }; [JsonProperty] - public BindableList Players { get; set; } = new BindableList(); + public BindableList Players { get; set; } = new BindableList(); public TournamentTeam() { diff --git a/osu.Game.Tournament/Models/TournamentPlayer.cs b/osu.Game.Tournament/Models/TournamentUser.cs similarity index 89% rename from osu.Game.Tournament/Models/TournamentPlayer.cs rename to osu.Game.Tournament/Models/TournamentUser.cs index 976936ab07..80e58538e5 100644 --- a/osu.Game.Tournament/Models/TournamentPlayer.cs +++ b/osu.Game.Tournament/Models/TournamentUser.cs @@ -9,10 +9,10 @@ using osu.Game.Users; namespace osu.Game.Tournament.Models { /// - /// A tournament player, containing simple information about the player. + /// A tournament player user, containing simple information about the player. /// [Serializable] - public class TournamentPlayer : IUser + public class TournamentUser : IUser { [JsonProperty(@"id")] public int OnlineID { get; set; } @@ -34,7 +34,7 @@ namespace osu.Game.Tournament.Models /// public string CoverUrl { get; set; } = string.Empty; - public APIUser ToUser() + public APIUser ToAPIUser() { var user = new APIUser { diff --git a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs index f29c45c949..11db37c8b7 100644 --- a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs @@ -201,14 +201,14 @@ namespace osu.Game.Tournament.Screens.Editors public void CreateNew() { - var player = new TournamentPlayer(); + var player = new TournamentUser(); team.Players.Add(player); flow.Add(new PlayerRow(team, player)); } public class PlayerRow : CompositeDrawable { - private readonly TournamentPlayer player; + private readonly TournamentUser user; [Resolved] protected IAPIProvider API { get; private set; } @@ -220,9 +220,9 @@ namespace osu.Game.Tournament.Screens.Editors private readonly Container drawableContainer; - public PlayerRow(TournamentTeam team, TournamentPlayer player) + public PlayerRow(TournamentTeam team, TournamentUser user) { - this.player = player; + this.user = user; Margin = new MarginPadding(10); @@ -271,7 +271,7 @@ namespace osu.Game.Tournament.Screens.Editors Action = () => { Expire(); - team.Players.Remove(player); + team.Players.Remove(user); }, } }; @@ -280,27 +280,27 @@ namespace osu.Game.Tournament.Screens.Editors [BackgroundDependencyLoader] private void load() { - playerId.Value = player.OnlineID; + playerId.Value = user.OnlineID; playerId.BindValueChanged(id => { - player.OnlineID = id.NewValue ?? 0; + user.OnlineID = id.NewValue ?? 0; if (id.NewValue != id.OldValue) - player.Username = string.Empty; + user.Username = string.Empty; - if (!string.IsNullOrEmpty(player.Username)) + if (!string.IsNullOrEmpty(user.Username)) { updatePanel(); return; } - game.PopulatePlayer(player, updatePanel, updatePanel); + game.PopulatePlayer(user, updatePanel, updatePanel); }, true); } private void updatePanel() { - drawableContainer.Child = new UserGridPanel(player.ToUser()) { Width = 300 }; + drawableContainer.Child = new UserGridPanel(user.ToAPIUser()) { Width = 300 }; } } } diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index f53e36a61e..a8d4abc5f4 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -256,9 +256,9 @@ namespace osu.Game.Tournament private void updateLoadProgressMessage(string s) => Schedule(() => initialisationText.Text = s); - public void PopulatePlayer(TournamentPlayer player, Action success = null, Action failure = null, bool immediate = false) + public void PopulatePlayer(TournamentUser user, Action success = null, Action failure = null, bool immediate = false) { - var req = new GetUserRequest(player.OnlineID, ladder.Ruleset.Value); + var req = new GetUserRequest(user.OnlineID, ladder.Ruleset.Value); if (immediate) { @@ -270,7 +270,7 @@ namespace osu.Game.Tournament req.Success += res => { populate(); }; req.Failure += _ => { - player.OnlineID = 1; + user.OnlineID = 1; failure?.Invoke(); }; @@ -284,12 +284,12 @@ namespace osu.Game.Tournament if (res == null) return; - player.OnlineID = res.Id; + user.OnlineID = res.Id; - player.Username = res.Username; - player.CoverUrl = res.CoverUrl; - player.Country = res.Country; - player.Rank = res.Statistics?.GlobalRank; + user.Username = res.Username; + user.CoverUrl = res.CoverUrl; + user.Country = res.Country; + user.Rank = res.Statistics?.GlobalRank; success?.Invoke(); } From 14cdb01fd8f90ce77ceedc45d412049457d3b6ce Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sat, 18 Jun 2022 08:49:48 +0900 Subject: [PATCH 038/211] Revert unintended change --- osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index ae1ac5fa47..a3423d4189 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -202,16 +202,14 @@ namespace osu.Game.Online.Multiplayer return connection.InvokeAsync(nameof(IMultiplayerServer.AddPlaylistItem), item); } - public override async Task EditPlaylistItem(MultiplayerPlaylistItem item) + public override Task EditPlaylistItem(MultiplayerPlaylistItem item) { if (!IsConnected.Value) - return; + return Task.CompletedTask; Debug.Assert(connection != null); - await Task.Delay(10000); - - await connection.InvokeAsync(nameof(IMultiplayerServer.EditPlaylistItem), item); + return connection.InvokeAsync(nameof(IMultiplayerServer.EditPlaylistItem), item); } public override Task RemovePlaylistItem(long playlistItemId) From 8a1d11fefb58e51e27c98e1d31c6d785dfac263b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 18 Jun 2022 04:07:21 +0300 Subject: [PATCH 039/211] Cancel previous metronome sound playback on pause --- osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index 270d544dcf..181f1ecb47 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -14,6 +15,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Threading; using osu.Framework.Timing; using osu.Framework.Utils; using osu.Game.Beatmaps.ControlPoints; @@ -37,6 +39,9 @@ namespace osu.Game.Screens.Edit.Timing private Sample clunk; + [CanBeNull] + private ScheduledDelegate clunkDelegate; + [Resolved] private OverlayColourProvider overlayColourProvider { get; set; } @@ -258,6 +263,9 @@ namespace osu.Game.Screens.Edit.Timing } isSwinging = false; + + clunkDelegate?.Cancel(); + clunkDelegate = null; } } @@ -283,7 +291,7 @@ namespace osu.Game.Screens.Edit.Timing { stick.FlashColour(overlayColourProvider.Content1, beatLength, Easing.OutQuint); - Schedule(() => + clunkDelegate = Schedule(() => { if (!EnableClicking) return; From 204348f32777fda80630530017cdb1dc9e4935fe Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 18 Jun 2022 04:39:53 +0300 Subject: [PATCH 040/211] Fix metronome playing mistimed beat sounds on editor clock resume --- osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index 181f1ecb47..670b7147b3 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -47,6 +47,11 @@ namespace osu.Game.Screens.Edit.Timing public bool EnableClicking { get; set; } = true; + public MetronomeDisplay() + { + AllowMistimedEventFiring = false; + } + [BackgroundDependencyLoader] private void load(AudioManager audio) { From 8ad96fd94baaf489233f88cad238f6044953a452 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 18 Jun 2022 10:55:24 +0900 Subject: [PATCH 041/211] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 8fcd7ef8c0..c82365d750 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index e9bf000109..d820be4bdc 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index dd344b0cd0..a8c59d676d 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + From bd5037fcad4c94cd5511f4f3146d43f2f3b76c56 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 18 Jun 2022 13:49:57 +0900 Subject: [PATCH 042/211] Fix new hitobject placements not taking on the existing sample settings Similar to velocity / difficulty points, a user expectation is that volume and sample settings will be transferred to newly placed objects from the most recent one. Closes https://github.com/ppy/osu/issues/18742. --- osu.Game/Rulesets/Edit/PlacementBlueprint.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs index 26dd6db016..3e93e576ba 100644 --- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -3,6 +3,7 @@ #nullable disable +using System.Linq; using System.Threading; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -73,6 +74,10 @@ namespace osu.Game.Rulesets.Edit /// Whether this call is committing a value for HitObject.StartTime and continuing with further adjustments. protected void BeginPlacement(bool commitStart = false) { + var nearestSampleControlPoint = beatmap.HitObjects.LastOrDefault(h => h.GetEndTime() < HitObject.StartTime)?.SampleControlPoint?.DeepClone() as SampleControlPoint; + + HitObject.SampleControlPoint = nearestSampleControlPoint ?? new SampleControlPoint(); + placementHandler.BeginPlacement(HitObject); if (commitStart) PlacementActive = PlacementState.Active; From 77e7e4ecb21a67ae685491507959f3e5491f499a Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sat, 18 Jun 2022 14:28:25 +0900 Subject: [PATCH 043/211] Fix selection being blocked after early return --- .../Multiplayer/MultiplayerMatchSongSelect.cs | 6 ++++-- .../Screens/OnlinePlay/OnlinePlaySongSelect.cs | 14 +++++++++----- .../OnlinePlay/Playlists/PlaylistsSongSelect.cs | 3 ++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 1f27a831ca..0f589a8b35 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -75,10 +75,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer loadingLayer.Hide(); } - protected override void SelectItem(PlaylistItem item) + protected override bool SelectItem(PlaylistItem item) { if (operationInProgress.Value) - return; + return false; // If the client is already in a room, update via the client. // Otherwise, update the playlist directly in preparation for it to be submitted to the API on match creation. @@ -124,6 +124,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Playlist.Add(item); this.Exit(); } + + return true; } protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs index 1552811c74..f26480909e 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs @@ -118,8 +118,6 @@ namespace osu.Game.Screens.OnlinePlay protected sealed override bool OnStart() { - itemSelected = true; - var item = new PlaylistItem(Beatmap.Value.BeatmapInfo) { RulesetID = Ruleset.Value.OnlineID, @@ -127,15 +125,21 @@ namespace osu.Game.Screens.OnlinePlay AllowedMods = FreeMods.Value.Select(m => new APIMod(m)).ToArray() }; - SelectItem(item); - return true; + if (SelectItem(item)) + { + itemSelected = true; + return true; + } + + return false; } /// /// Invoked when the user has requested a selection of a beatmap. /// /// The resultant . This item has not yet been added to the 's. - protected abstract void SelectItem(PlaylistItem item); + /// true if a selection occurred. + protected abstract bool SelectItem(PlaylistItem item); public override bool OnBackButton() { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs index 65a27a9261..73765fc661 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists CreateNewItem = createNewItem }; - protected override void SelectItem(PlaylistItem item) + protected override bool SelectItem(PlaylistItem item) { switch (Playlist.Count) { @@ -39,6 +39,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists } this.Exit(); + return true; } private void createNewItem() From 56abe54fe6331f88c014baf7e34128bc070e8cec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 18 Jun 2022 22:59:19 +0900 Subject: [PATCH 044/211] Redirect graceful exiting to standard exit flow Rather than doing a completely forced exit as we were, this will now follow a more standard flow with the ability for the user to abort along the way. This is more in line with how I wanted this to work. Note that this means a confirmation is now shown. It has been discussed in the past that this confirmation should only show when there's an ongoing action implies the user may want to cancel the exit. For now I think this is fine. Addresses https://github.com/ppy/osu/discussions/18399#discussioncomment-2811311 --- osu.Game/OsuGame.cs | 6 ++++++ osu.Game/OsuGameBase.cs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 3041761a6b..06ade5a3c9 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -637,6 +637,12 @@ namespace osu.Game Add(performFromMainMenuTask = new PerformFromMenuRunner(action, validScreens, () => ScreenStack.CurrentScreen)); } + public override void GracefullyExit() + { + // Using PerformFromScreen gives the user a chance to interrupt the exit process if needed. + PerformFromScreen(menu => menu.Exit()); + } + /// /// Wait for the game (and target component) to become loaded and then run an action. /// diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 9908697bf1..dc7513d3c8 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -419,7 +419,7 @@ namespace osu.Game /// Use to programatically exit the game as if the user was triggering via alt-f4. /// Will keep persisting until an exit occurs (exit may be blocked multiple times). /// - public void GracefullyExit() + public virtual void GracefullyExit() { if (!OnExiting()) Exit(); From a5e5172b916a1798f3b131731e48ff1b5a1a965e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 18 Jun 2022 18:28:36 +0300 Subject: [PATCH 045/211] Fix `BlueprintContainer` eating input from skin editor buttons --- .../Screens/Edit/Compose/Components/BlueprintContainer.cs | 7 ------- .../Edit/Compose/Components/ComposeBlueprintContainer.cs | 6 ++++++ .../Screens/Edit/Compose/Components/SelectionHandler.cs | 4 +++- .../Components/Timeline/TimelineBlueprintContainer.cs | 6 ++++++ 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index c7bf23865b..d38aac1173 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -108,13 +108,6 @@ namespace osu.Game.Screens.Edit.Compose.Components /// protected virtual bool AllowDeselectionDuringDrag => true; - /// - /// Positional input must be received outside the container's bounds, - /// in order to handle blueprints which are partially offscreen. - /// - /// - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; - protected override bool OnMouseDown(MouseDownEvent e) { bool selectionPerformed = performMouseDownActions(e); diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index ba43704a5f..4c37d200bc 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -39,6 +39,12 @@ namespace osu.Game.Screens.Edit.Compose.Components private PlacementBlueprint currentPlacement; private InputManager inputManager; + /// + /// Positional input must be received outside the container's bounds, + /// in order to handle composer blueprints which are partially offscreen. + /// + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; + public ComposeBlueprintContainer(HitObjectComposer composer) : base(composer) { diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 96bd352cf9..91af3fde16 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -21,6 +21,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Edit; +using osu.Game.Screens.Edit.Compose.Components.Timeline; using osuTK; using osuTK.Input; @@ -103,7 +104,8 @@ namespace osu.Game.Screens.Edit.Compose.Components /// Positional input must be received outside the container's bounds, /// in order to handle blueprints which are partially offscreen. /// - /// + /// + /// public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; /// diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index 138e28fa06..742e16d5a9 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -35,6 +35,12 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private Bindable placement; private SelectionBlueprint placementBlueprint; + /// + /// Positional input must be received outside the container's bounds, + /// in order to handle timeline blueprints which are stacked offscreen. + /// + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => timeline.ReceivePositionalInputAt(screenSpacePos); + public TimelineBlueprintContainer(HitObjectComposer composer) : base(composer) { From 47ce087694fc9c2d0fa3ec81442ed5a171b016f8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 18 Jun 2022 18:32:02 +0300 Subject: [PATCH 046/211] Actually click the gameplay scene button than `TriggerClick` --- .../Visual/Navigation/TestSceneSkinEditorNavigation.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index 78ab7947a7..7d9c08d3d2 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -148,7 +148,11 @@ namespace osu.Game.Tests.Visual.Navigation private void switchToGameplayScene() { - AddStep("Click gameplay scene button", () => skinEditor.ChildrenOfType().First(b => b.Text == "Gameplay").TriggerClick()); + AddStep("Click gameplay scene button", () => + { + InputManager.MoveMouseTo(skinEditor.ChildrenOfType().First(b => b.Text == "Gameplay")); + InputManager.Click(MouseButton.Left); + }); AddUntilStep("wait for player", () => { From b2663d9399fd5b9fd75fef0a4bdf13a33ae29632 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 19 Jun 2022 01:14:48 +0900 Subject: [PATCH 047/211] Update xmldoc to suggest that `GracefullyExit` may be overridden --- osu.Game/OsuGameBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index dc7513d3c8..4a9f74d195 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -417,7 +417,7 @@ namespace osu.Game /// /// Use to programatically exit the game as if the user was triggering via alt-f4. - /// Will keep persisting until an exit occurs (exit may be blocked multiple times). + /// By default, will keep persisting until an exit occurs (exit may be blocked multiple times). /// public virtual void GracefullyExit() { From 3902dc64f0fee5a49def28062b769ef370187d0e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 19 Jun 2022 01:34:58 +0900 Subject: [PATCH 048/211] Fix adjusting offset via button seeking to timing point's offset unexpectedly This was added with the intention of tracking the offset when already at the start (the most common case when you're using the tap timing wizard), but was also seeking when the user may be much further beyond or before it. Addresses https://github.com/ppy/osu/discussions/18741#discussioncomment-2975051. --- osu.Game/Screens/Edit/Timing/TapTimingControl.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 53c92bac20..abc73851e4 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -195,6 +195,8 @@ namespace osu.Game.Screens.Edit.Timing private void adjustOffset(double adjust) { + bool wasAtStart = editorClock.CurrentTimeAccurate == selectedGroup.Value.Time; + // VERY TEMPORARY var currentGroupItems = selectedGroup.Value.ControlPoints.ToArray(); @@ -208,7 +210,7 @@ namespace osu.Game.Screens.Edit.Timing // the control point might not necessarily exist yet, if currentGroupItems was empty. selectedGroup.Value = beatmap.ControlPointInfo.GroupAt(newOffset, true); - if (!editorClock.IsRunning) + if (!editorClock.IsRunning && wasAtStart) editorClock.Seek(newOffset); } From 50e40756c462318ddebb812fe317c57ec1a4de70 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 19 Jun 2022 12:34:14 +0900 Subject: [PATCH 049/211] Rename `GracefullyExit` to `AttemptExit` --- osu.Desktop/Updater/SquirrelUpdateManager.cs | 2 +- osu.Game.Tournament/Screens/Setup/TournamentSwitcher.cs | 2 +- osu.Game/OsuGame.cs | 2 +- osu.Game/OsuGameBase.cs | 5 +++-- .../Settings/Sections/Maintenance/MigrationSelectScreen.cs | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs index 59bc2dabb2..4e5f8d37b1 100644 --- a/osu.Desktop/Updater/SquirrelUpdateManager.cs +++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs @@ -154,7 +154,7 @@ namespace osu.Desktop.Updater Activated = () => { updateManager.PrepareUpdateAsync() - .ContinueWith(_ => updateManager.Schedule(() => game?.GracefullyExit())); + .ContinueWith(_ => updateManager.Schedule(() => game?.AttemptExit())); return true; }; } diff --git a/osu.Game.Tournament/Screens/Setup/TournamentSwitcher.cs b/osu.Game.Tournament/Screens/Setup/TournamentSwitcher.cs index fb33b3662a..447d6f44ce 100644 --- a/osu.Game.Tournament/Screens/Setup/TournamentSwitcher.cs +++ b/osu.Game.Tournament/Screens/Setup/TournamentSwitcher.cs @@ -27,7 +27,7 @@ namespace osu.Game.Tournament.Screens.Setup dropdown.Items = storage.ListTournaments(); dropdown.Current.BindValueChanged(v => Button.Enabled.Value = v.NewValue != startupTournament, true); - Action = () => game.GracefullyExit(); + Action = () => game.AttemptExit(); folderButton.Action = () => storage.PresentExternally(); ButtonText = "Close osu!"; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 06ade5a3c9..97476358b1 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -637,7 +637,7 @@ namespace osu.Game Add(performFromMainMenuTask = new PerformFromMenuRunner(action, validScreens, () => ScreenStack.CurrentScreen)); } - public override void GracefullyExit() + public override void AttemptExit() { // Using PerformFromScreen gives the user a chance to interrupt the exit process if needed. PerformFromScreen(menu => menu.Exit()); diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 4a9f74d195..1385c06640 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -418,13 +418,14 @@ namespace osu.Game /// /// Use to programatically exit the game as if the user was triggering via alt-f4. /// By default, will keep persisting until an exit occurs (exit may be blocked multiple times). + /// May be interrupted (see 's override. /// - public virtual void GracefullyExit() + public virtual void AttemptExit() { if (!OnExiting()) Exit(); else - Scheduler.AddDelayed(GracefullyExit, 2000); + Scheduler.AddDelayed(AttemptExit, 2000); } public bool Migrate(string path) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs index 7e6341cd1b..c51a4db71a 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs @@ -56,7 +56,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance dialogOverlay.Push(new ConfirmDialog("To complete this operation, osu! will close. Please open it again to use the new data location.", () => { (storage as OsuStorage)?.ChangeDataPath(target.FullName); - game.GracefullyExit(); + game.AttemptExit(); }, () => { })); }, () => { })); From de61b9e4109e693b96041f2ba0add55fe4e09394 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 17 Jun 2022 22:03:04 -0700 Subject: [PATCH 050/211] Revert "Add automated commit to git-blame-ignore-revs" This reverts commit 11bd87045ef7f18bd7cb5cf88fbd327b15f65257. --- .git-blame-ignore-revs | 2 -- 1 file changed, 2 deletions(-) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 39fa0f9f6c..8be6479043 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,4 +1,2 @@ # Normalize all the line endings 32a74f95a5c80a0ed18e693f13a47522099df5c3 -# Enabled NRT globally -f8830c6850128456266c82de83273204f8b74ac0 From 6515b249ec92964ac2e6c7711f3d336daf3ecc69 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 19 Jun 2022 12:39:58 +0900 Subject: [PATCH 051/211] Change data migration to do an immediate exit, rather than attempted exit --- .../Settings/Sections/Maintenance/MigrationSelectScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs index c51a4db71a..0d32e33d87 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs @@ -56,7 +56,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance dialogOverlay.Push(new ConfirmDialog("To complete this operation, osu! will close. Please open it again to use the new data location.", () => { (storage as OsuStorage)?.ChangeDataPath(target.FullName); - game.AttemptExit(); + game.Exit(); }, () => { })); }, () => { })); From 98d69c846c5e285e5f41984f0465325aec438699 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sun, 19 Jun 2022 17:12:19 +0900 Subject: [PATCH 052/211] Reset spectator speed at last frame --- osu.Game/Screens/Play/SpectatorPlayer.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Screens/Play/SpectatorPlayer.cs b/osu.Game/Screens/Play/SpectatorPlayer.cs index d5aec055fc..72a7d3c8a1 100644 --- a/osu.Game/Screens/Play/SpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SpectatorPlayer.cs @@ -83,6 +83,18 @@ namespace osu.Game.Screens.Play SetGameplayStartTime(score.Replay.Frames[0].Time); } + protected override void Update() + { + base.Update(); + + if (HUDOverlay.PlayerSettingsOverlay.PlaybackSettings.UserPlaybackRate.Value > 1 + && score.Replay.Frames.Count > 0 + && DrawableRuleset.FrameStableClock.CurrentTime >= score.Replay.Frames[^1].Time) + { + HUDOverlay.PlayerSettingsOverlay.PlaybackSettings.UserPlaybackRate.Value = 1; + } + } + protected override Score CreateScore(IBeatmap beatmap) => score; protected override ResultsScreen CreateResults(ScoreInfo score) From 495d747da55eab3cbfcc8331ffe5f6e73c6e3618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 19 Jun 2022 13:42:45 +0200 Subject: [PATCH 053/211] Fix mismatching braces in comment --- osu.Game/OsuGameBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 1385c06640..f0f364314c 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -418,7 +418,7 @@ namespace osu.Game /// /// Use to programatically exit the game as if the user was triggering via alt-f4. /// By default, will keep persisting until an exit occurs (exit may be blocked multiple times). - /// May be interrupted (see 's override. + /// May be interrupted (see 's override). /// public virtual void AttemptExit() { From def87ed7822031164bebbf3ef474286a3533c91a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 19 Jun 2022 19:18:29 +0200 Subject: [PATCH 054/211] Add failing test for editor gameplay test using wrong ruleset --- .../Editing/TestSceneEditorNavigation.cs | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs new file mode 100644 index 0000000000..85b50a9b21 --- /dev/null +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs @@ -0,0 +1,57 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Extensions; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Database; +using osu.Game.Rulesets.Mania; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Edit; +using osu.Game.Screens.Edit.Components.Timelines.Summary; +using osu.Game.Screens.Edit.GameplayTest; +using osu.Game.Screens.Select; +using osu.Game.Tests.Resources; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Editing +{ + public class TestSceneEditorNavigation : OsuGameTestScene + { + [Test] + public void TestEditorGameplayTestAlwaysUsesOriginalRuleset() + { + BeatmapSetInfo beatmapSet = null!; + + AddStep("import test beatmap", () => Game.BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).WaitSafely()); + AddStep("retrieve beatmap", () => beatmapSet = Game.BeatmapManager.QueryBeatmapSet(set => !set.Protected).AsNonNull().Value.Detach()); + + AddStep("present beatmap", () => Game.PresentBeatmap(beatmapSet)); + AddUntilStep("wait for song select", + () => Game.Beatmap.Value.BeatmapSetInfo.Equals(beatmapSet) + && Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect + && songSelect.IsLoaded); + AddStep("switch ruleset", () => Game.Ruleset.Value = new ManiaRuleset().RulesetInfo); + + AddStep("open editor", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).Edit(beatmapSet.Beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == 0))); + AddUntilStep("wait for editor open", () => Game.ScreenStack.CurrentScreen is Editor editor && editor.IsLoaded); + AddStep("test gameplay", () => + { + var testGameplayButton = this.ChildrenOfType().Single(); + InputManager.MoveMouseTo(testGameplayButton); + InputManager.Click(MouseButton.Left); + }); + + AddUntilStep("wait for player", () => Game.ScreenStack.CurrentScreen is EditorPlayer editorPlayer && editorPlayer.IsLoaded); + AddAssert("current ruleset is osu!", () => Game.Ruleset.Value.Equals(new OsuRuleset().RulesetInfo)); + + AddStep("exit to song select", () => Game.PerformFromScreen(_ => { }, typeof(PlaySongSelect).Yield())); + AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is PlaySongSelect); + AddAssert("previous ruleset restored", () => Game.Ruleset.Value.Equals(new ManiaRuleset().RulesetInfo)); + } + } +} From 93b3ede2a05f06a3b37ab9ce72249c1a232e0f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 19 Jun 2022 19:30:34 +0200 Subject: [PATCH 055/211] Always use beatmap ruleset in editor gameplay test mode Fixes cases where opening a convertible beatmap (so any osu! beatmap) with the game-global ruleset being set to anything but osu! would result in opening the editor gameplay test mode with the game-global ruleset rather than the beatmap's. --- osu.Game/Screens/Edit/EditorLoader.cs | 1 + osu.Game/Screens/Select/SongSelect.cs | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/EditorLoader.cs b/osu.Game/Screens/Edit/EditorLoader.cs index 702e22a272..4450367522 100644 --- a/osu.Game/Screens/Edit/EditorLoader.cs +++ b/osu.Game/Screens/Edit/EditorLoader.cs @@ -65,6 +65,7 @@ namespace osu.Game.Screens.Edit base.LoadComplete(); // will be restored via lease, see `DisallowExternalBeatmapRulesetChanges`. + Ruleset.Value = Beatmap.Value.BeatmapInfo.Ruleset; Mods.Value = Array.Empty(); } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index a17e7823a6..41fb55a856 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -786,7 +786,17 @@ namespace osu.Game.Screens.Select Ruleset.ValueChanged += r => updateSelectedRuleset(r.NewValue); - decoupledRuleset.ValueChanged += r => Ruleset.Value = r.NewValue; + decoupledRuleset.ValueChanged += r => + { + bool wasDisabled = Ruleset.Disabled; + + // a sub-screen may have taken a lease on this decoupled ruleset bindable, + // which would indirectly propagate to the game-global bindable via the `DisabledChanged` callback below. + // to make sure changes sync without crashes, lift the disable for a short while to sync, and then restore the old value. + Ruleset.Disabled = false; + Ruleset.Value = r.NewValue; + Ruleset.Disabled = wasDisabled; + }; decoupledRuleset.DisabledChanged += r => Ruleset.Disabled = r; Beatmap.BindValueChanged(workingBeatmapChanged); From 3ab8158b923d5ae8581c39d9b67b93a804de65b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 19 Jun 2022 20:08:39 +0200 Subject: [PATCH 056/211] Do not try to set ruleset from beatmap if it's a dummy --- osu.Game/Screens/Edit/EditorLoader.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/EditorLoader.cs b/osu.Game/Screens/Edit/EditorLoader.cs index 4450367522..d6af990b52 100644 --- a/osu.Game/Screens/Edit/EditorLoader.cs +++ b/osu.Game/Screens/Edit/EditorLoader.cs @@ -65,7 +65,8 @@ namespace osu.Game.Screens.Edit base.LoadComplete(); // will be restored via lease, see `DisallowExternalBeatmapRulesetChanges`. - Ruleset.Value = Beatmap.Value.BeatmapInfo.Ruleset; + if (!(Beatmap.Value is DummyWorkingBeatmap)) + Ruleset.Value = Beatmap.Value.BeatmapInfo.Ruleset; Mods.Value = Array.Empty(); } From 36df1da57fda5cbfc8c44d97f24c7d4f0d7346f3 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Sun, 19 Jun 2022 14:26:02 -0400 Subject: [PATCH 057/211] Revert "stop component transform when skineditor is hidden" This reverts commit 48ffd6aeb5c131a120a9c82e889348ebf3d21dfb. --- .../Skinning/Editor/SkinSelectionHandler.cs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs index 2496d7c657..2e2122f7c2 100644 --- a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs +++ b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs @@ -11,7 +11,6 @@ using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Graphics.Containers; using osu.Framework.Utils; using osu.Game.Extensions; using osu.Game.Graphics.UserInterface; @@ -26,17 +25,8 @@ namespace osu.Game.Skinning.Editor [Resolved] private SkinEditor skinEditor { get; set; } - /// - /// Whether the 's state allows selected blueprints to undergo transformations. - /// Used to prevent operations from being performed on unloaded blueprints. - /// - private bool allowHandling => skinEditor.State.Value == Visibility.Visible; - public override bool HandleRotation(float angle) { - if (!allowHandling) - return false; - if (SelectedBlueprints.Count == 1) { // for single items, rotate around the origin rather than the selection centre. @@ -63,9 +53,6 @@ namespace osu.Game.Skinning.Editor public override bool HandleScale(Vector2 scale, Anchor anchor) { - if (!allowHandling) - return false; - // convert scale to screen space scale = ToScreenSpace(scale) - ToScreenSpace(Vector2.Zero); @@ -143,9 +130,6 @@ namespace osu.Game.Skinning.Editor public override bool HandleFlip(Direction direction, bool flipOverOrigin) { - if (!allowHandling) - return false; - var selectionQuad = getSelectionQuad(); Vector2 scaleFactor = direction == Direction.Horizontal ? new Vector2(-1, 1) : new Vector2(1, -1); @@ -166,9 +150,6 @@ namespace osu.Game.Skinning.Editor public override bool HandleMovement(MoveSelectionEvent moveEvent) { - if (!allowHandling) - return false; - foreach (var c in SelectedBlueprints) { var item = c.Item; From a5bc769243f3b0554805fa57855704a8da3b0ac1 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Sun, 19 Jun 2022 14:34:52 -0400 Subject: [PATCH 058/211] clear skineditor selected components on hide --- osu.Game/Skinning/Editor/SkinEditor.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index f41cd63f2d..7e9f1d0e8e 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -322,6 +322,12 @@ namespace osu.Game.Skinning.Editor protected override bool OnMouseDown(MouseDownEvent e) => true; + public override void Hide() + { + base.Hide(); + SelectedComponents.Clear(); + } + protected override void PopIn() { this From 2b0e82be4004c8c2ca894f1a6666de9adf754296 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Sun, 19 Jun 2022 14:35:05 -0400 Subject: [PATCH 059/211] add test coverage --- .../TestSceneSkinEditorNavigation.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index 78ab7947a7..843d61ca3b 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -88,6 +88,31 @@ namespace osu.Game.Tests.Visual.Navigation AddAssert("value is less than default", () => hitErrorMeter.JudgementLineThickness.Value < hitErrorMeter.JudgementLineThickness.Default); } + [Test] + public void TestComponentsDeselectedOnSkinEditorHide() + { + advanceToSongSelect(); + openSkinEditor(); + switchToGameplayScene(); + AddStep("select all components", () => + { + InputManager.PressKey(Key.ControlLeft); + InputManager.Key(Key.A); + InputManager.ReleaseKey(Key.ControlLeft); + }); + + AddStep("toggle skin editor", () => + { + InputManager.PressKey(Key.ControlLeft); + InputManager.PressKey(Key.ShiftLeft); + InputManager.Key(Key.S); + InputManager.ReleaseKey(Key.ControlLeft); + InputManager.ReleaseKey(Key.ShiftLeft); + }); + + AddUntilStep("no components selected", () => skinEditor.SelectedComponents.Count == 0); + } + [Test] public void TestAutoplayCompatibleModsRetainedOnEnteringGameplay() { From 5e594e4de0c714ae6855fbf843245c30b40c0ee5 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 20 Jun 2022 06:54:15 +0300 Subject: [PATCH 060/211] Work around macOS agent regression affecting iOS CI builds --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef729a779f..c728d89ed1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,6 +126,12 @@ jobs: with: dotnet-version: "6.0.x" + # macOS agents recently have empty NuGet config files, resulting in restore failures, + # see https://github.com/actions/virtual-environments/issues/5768 + # Add the global nuget package source manually for now. + - name: Setup NuGet.Config + run: echo '' > ~/.config/NuGet/NuGet.Config + # Contrary to seemingly any other msbuild, msbuild running on macOS/Mono # cannot accept .sln(f) files as arguments. # Build just the main game for now. From 243806e810de9304e914c9d1c63d1732cafbe15e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 13:29:43 +0900 Subject: [PATCH 061/211] Move common step of toggling skin editor to own method --- .../TestSceneSkinEditorNavigation.cs | 78 +++++++++++-------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index 843d61ca3b..7185e5ce49 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -26,29 +26,6 @@ namespace osu.Game.Tests.Visual.Navigation private TestPlaySongSelect songSelect; private SkinEditor skinEditor => Game.ChildrenOfType().FirstOrDefault(); - private void advanceToSongSelect() - { - 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); - } - - private void openSkinEditor() - { - 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("skin editor loaded", () => skinEditor != null); - } - [Test] public void TestEditComponentDuringGameplay() { @@ -88,6 +65,24 @@ namespace osu.Game.Tests.Visual.Navigation AddAssert("value is less than default", () => hitErrorMeter.JudgementLineThickness.Value < hitErrorMeter.JudgementLineThickness.Default); } + [Test] + public void TestHideSkinEditorWhileDragging() + { + advanceToSongSelect(); + openSkinEditor(); + switchToGameplayScene(); + AddStep("select all components", () => + { + InputManager.PressKey(Key.ControlLeft); + InputManager.Key(Key.A); + InputManager.ReleaseKey(Key.ControlLeft); + }); + + toggleSkinEditor(); + + AddUntilStep("no components selected", () => skinEditor.SelectedComponents.Count == 0); + } + [Test] public void TestComponentsDeselectedOnSkinEditorHide() { @@ -101,14 +96,7 @@ namespace osu.Game.Tests.Visual.Navigation InputManager.ReleaseKey(Key.ControlLeft); }); - AddStep("toggle skin editor", () => - { - InputManager.PressKey(Key.ControlLeft); - InputManager.PressKey(Key.ShiftLeft); - InputManager.Key(Key.S); - InputManager.ReleaseKey(Key.ControlLeft); - InputManager.ReleaseKey(Key.ShiftLeft); - }); + toggleSkinEditor(); AddUntilStep("no components selected", () => skinEditor.SelectedComponents.Count == 0); } @@ -171,6 +159,34 @@ namespace osu.Game.Tests.Visual.Navigation AddUntilStep("mod overlay closed", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden); } + private void advanceToSongSelect() + { + 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); + } + + private void openSkinEditor() + { + toggleSkinEditor(); + AddUntilStep("skin editor loaded", () => skinEditor != null); + } + + private void toggleSkinEditor() + { + AddStep("toggle skin editor", () => + { + InputManager.PressKey(Key.ControlLeft); + InputManager.PressKey(Key.ShiftLeft); + InputManager.Key(Key.S); + InputManager.ReleaseKey(Key.ControlLeft); + InputManager.ReleaseKey(Key.ShiftLeft); + }); + } + private void switchToGameplayScene() { AddStep("Click gameplay scene button", () => skinEditor.ChildrenOfType().First(b => b.Text == "Gameplay").TriggerClick()); From 329f1a08222c6ac9017025f484c771bc1c45d7aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 13:45:50 +0900 Subject: [PATCH 062/211] Add test coverage of original fail case and improve test reliability and code quality --- .../TestSceneSkinEditorNavigation.cs | 47 +++++++++++++++---- .../Skinning/Editor/SkinComponentToolbox.cs | 2 +- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index 7185e5ce49..0c99cf15eb 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -8,7 +8,9 @@ using NUnit.Framework; using osu.Framework.Extensions; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Screens; using osu.Framework.Testing; +using osu.Framework.Threading; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; @@ -16,6 +18,7 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD.HitErrorMeters; using osu.Game.Skinning.Editor; using osu.Game.Tests.Beatmaps.IO; +using osuTK; using osuTK.Input; using static osu.Game.Tests.Visual.Navigation.TestSceneScreenNavigation; @@ -66,11 +69,14 @@ namespace osu.Game.Tests.Visual.Navigation } [Test] - public void TestHideSkinEditorWhileDragging() + public void TestComponentsDeselectedOnSkinEditorHide() { advanceToSongSelect(); openSkinEditor(); switchToGameplayScene(); + + AddUntilStep("wait for components", () => skinEditor.ChildrenOfType().Any()); + AddStep("select all components", () => { InputManager.PressKey(Key.ControlLeft); @@ -78,27 +84,50 @@ namespace osu.Game.Tests.Visual.Navigation InputManager.ReleaseKey(Key.ControlLeft); }); + AddUntilStep("components selected", () => skinEditor.SelectedComponents.Count > 0); + toggleSkinEditor(); AddUntilStep("no components selected", () => skinEditor.SelectedComponents.Count == 0); } [Test] - public void TestComponentsDeselectedOnSkinEditorHide() + public void TestSwitchScreenWhileDraggingComponent() { + Vector2 firstBlueprintCentre = Vector2.Zero; + ScheduledDelegate movementDelegate = null; + advanceToSongSelect(); + openSkinEditor(); - switchToGameplayScene(); - AddStep("select all components", () => + + AddStep("add skinnable component", () => { - InputManager.PressKey(Key.ControlLeft); - InputManager.Key(Key.A); - InputManager.ReleaseKey(Key.ControlLeft); + skinEditor.ChildrenOfType().First().TriggerClick(); }); - toggleSkinEditor(); + AddUntilStep("newly added component selected", () => skinEditor.SelectedComponents.Count == 1); - AddUntilStep("no components selected", () => skinEditor.SelectedComponents.Count == 0); + AddStep("start drag", () => + { + firstBlueprintCentre = skinEditor.ChildrenOfType().First().ScreenSpaceDrawQuad.Centre; + + InputManager.MoveMouseTo(firstBlueprintCentre); + InputManager.PressButton(MouseButton.Left); + }); + + AddStep("start movement", () => movementDelegate = Scheduler.AddDelayed(() => { InputManager.MoveMouseTo(firstBlueprintCentre += new Vector2(1)); }, 10, true)); + + toggleSkinEditor(); + AddStep("exit song select", () => songSelect.Exit()); + + AddUntilStep("wait for blueprints removed", () => !skinEditor.ChildrenOfType().Any()); + + AddStep("stop drag", () => + { + InputManager.ReleaseButton(MouseButton.Left); + movementDelegate?.Cancel(); + }); } [Test] diff --git a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs index 7de9cd5108..344a659627 100644 --- a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs +++ b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs @@ -88,7 +88,7 @@ namespace osu.Game.Skinning.Editor } } - private class ToolboxComponentButton : OsuButton + public class ToolboxComponentButton : OsuButton { protected override bool ShouldBeConsideredForInput(Drawable child) => false; From e4d0c7a0fb179ec5f8c56e1885811de7ec8525ce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 13:59:20 +0900 Subject: [PATCH 063/211] Move beatmap import step to only be required when entering gameplay --- .../Visual/Navigation/TestSceneSkinEditorNavigation.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index 0c99cf15eb..cc76e530c8 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -192,10 +192,6 @@ namespace osu.Game.Tests.Visual.Navigation { 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); } private void openSkinEditor() @@ -218,6 +214,9 @@ namespace osu.Game.Tests.Visual.Navigation private void switchToGameplayScene() { + AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely()); + AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault); + AddStep("Click gameplay scene button", () => skinEditor.ChildrenOfType().First(b => b.Text == "Gameplay").TriggerClick()); AddUntilStep("wait for player", () => From a6c8a832aaf9d9fd4cda147eef6850d1daa8ff37 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 15:14:57 +0900 Subject: [PATCH 064/211] Remove `Import(ArchiveReader)` and redirect existing usages to `Import(ImportTask)` --- .../Database/BeatmapImporterTests.cs | 27 +++------- osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 53 +++++++++---------- .../Skins/TestSceneBeatmapSkinResources.cs | 4 +- .../Skins/TestSceneSkinResources.cs | 4 +- osu.Game/Beatmaps/BeatmapManager.cs | 3 -- .../Database/RealmArchiveModelImporter.cs | 4 +- osu.Game/Screens/Menu/IntroScreen.cs | 3 +- osu.Game/Skinning/SkinManager.cs | 4 -- 8 files changed, 39 insertions(+), 63 deletions(-) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index f9cd75d8c3..841622f0db 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -15,7 +15,6 @@ using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Extensions; -using osu.Game.IO.Archives; using osu.Game.Models; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; @@ -39,10 +38,7 @@ namespace osu.Game.Tests.Database using (var importer = new BeatmapImporter(storage, realm)) using (new RealmRulesetStore(realm, storage)) { - Live? beatmapSet; - - using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream())) - beatmapSet = await importer.Import(reader); + var beatmapSet = await importer.Import(new ImportTask(TestResources.GetTestBeatmapStream(), "renatus.osz")); Assert.NotNull(beatmapSet); Debug.Assert(beatmapSet != null); @@ -83,10 +79,7 @@ namespace osu.Game.Tests.Database using (var importer = new BeatmapImporter(storage, realm)) using (new RealmRulesetStore(realm, storage)) { - Live? beatmapSet; - - using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream())) - beatmapSet = await importer.Import(reader); + var beatmapSet = await importer.Import(new ImportTask(TestResources.GetTestBeatmapStream(), "renatus.osz")); Assert.NotNull(beatmapSet); Debug.Assert(beatmapSet != null); @@ -146,11 +139,8 @@ namespace osu.Game.Tests.Database { Task.Run(async () => { - Live? beatmapSet; - - using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream())) - // ReSharper disable once AccessToDisposedClosure - beatmapSet = await importer.Import(reader); + // ReSharper disable once AccessToDisposedClosure + var beatmapSet = await importer.Import(new ImportTask(TestResources.GetTestBeatmapStream(), "renatus.osz")); Assert.NotNull(beatmapSet); Debug.Assert(beatmapSet != null); @@ -173,13 +163,8 @@ namespace osu.Game.Tests.Database using (var importer = new BeatmapImporter(storage, realm)) using (new RealmRulesetStore(realm, storage)) { - Live? imported; - - using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream())) - { - imported = await importer.Import(reader); - EnsureLoaded(realm.Realm); - } + var imported = await importer.Import(new ImportTask(TestResources.GetTestBeatmapStream(), "renatus.osz")); + EnsureLoaded(realm.Realm); Assert.AreEqual(1, realm.Realm.All().Count()); diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index 4db88cbe82..f3adb85006 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -15,7 +15,6 @@ using osu.Framework.Platform; using osu.Game.Database; using osu.Game.Extensions; using osu.Game.IO; -using osu.Game.IO.Archives; using osu.Game.Skinning; using SharpCompress.Archives.Zip; @@ -28,7 +27,7 @@ namespace osu.Game.Tests.Skins.IO [Test] public Task TestSingleImportDifferentFilename() => runSkinTest(async osu => { - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin", "skinner"), "skin.osk")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("test skin", "skinner"), "skin.osk")); // When the import filename doesn't match, it should be appended (and update the skin.ini). assertCorrectMetadata(import1, "test skin [skin]", "skinner", osu); @@ -37,7 +36,7 @@ namespace osu.Game.Tests.Skins.IO [Test] public Task TestSingleImportWeirdIniFileCase() => runSkinTest(async osu => { - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin", "skinner", iniFilename: "Skin.InI"), "skin.osk")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("test skin", "skinner", iniFilename: "Skin.InI"), "skin.osk")); // When the import filename doesn't match, it should be appended (and update the skin.ini). assertCorrectMetadata(import1, "test skin [skin]", "skinner", osu); @@ -46,7 +45,7 @@ namespace osu.Game.Tests.Skins.IO [Test] public Task TestSingleImportMissingSectionHeader() => runSkinTest(async osu => { - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin", "skinner", includeSectionHeader: false), "skin.osk")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("test skin", "skinner", includeSectionHeader: false), "skin.osk")); // When the import filename doesn't match, it should be appended (and update the skin.ini). assertCorrectMetadata(import1, "test skin [skin]", "skinner", osu); @@ -55,7 +54,7 @@ namespace osu.Game.Tests.Skins.IO [Test] public Task TestSingleImportMatchingFilename() => runSkinTest(async osu => { - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin", "skinner"), "test skin.osk")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("test skin", "skinner"), "test skin.osk")); // When the import filename matches it shouldn't be appended. assertCorrectMetadata(import1, "test skin", "skinner", osu); @@ -64,7 +63,7 @@ namespace osu.Game.Tests.Skins.IO [Test] public Task TestSingleImportNoIniFile() => runSkinTest(async osu => { - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithNonIniFile(), "test skin.osk")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithNonIniFile(), "test skin.osk")); // When the import filename matches it shouldn't be appended. assertCorrectMetadata(import1, "test skin", "Unknown", osu); @@ -73,7 +72,7 @@ namespace osu.Game.Tests.Skins.IO [Test] public Task TestEmptyImportImportsWithFilename() => runSkinTest(async osu => { - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createEmptyOsk(), "test skin.osk")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createEmptyOsk(), "test skin.osk")); // When the import filename matches it shouldn't be appended. assertCorrectMetadata(import1, "test skin", "Unknown", osu); @@ -86,8 +85,8 @@ namespace osu.Game.Tests.Skins.IO [Test] public Task TestImportTwiceWithSameMetadataAndFilename() => runSkinTest(async osu => { - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin", "skinner"), "skin.osk")); - var import2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin", "skinner"), "skin.osk")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("test skin", "skinner"), "skin.osk")); + var import2 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("test skin", "skinner"), "skin.osk")); assertImportedOnce(import1, import2); }); @@ -96,8 +95,8 @@ namespace osu.Game.Tests.Skins.IO public Task TestImportTwiceWithNoMetadataSameDownloadFilename() => runSkinTest(async osu => { // if a user downloads two skins that do have skin.ini files but don't have any creator metadata in the skin.ini, they should both import separately just for safety. - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni(string.Empty, string.Empty), "download.osk")); - var import2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni(string.Empty, string.Empty), "download.osk")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni(string.Empty, string.Empty), "download.osk")); + var import2 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni(string.Empty, string.Empty), "download.osk")); assertImportedOnce(import1, import2); }); @@ -105,10 +104,10 @@ namespace osu.Game.Tests.Skins.IO [Test] public Task TestImportUpperCasedOskArchive() => runSkinTest(async osu => { - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("name 1", "author 1"), "name 1.OsK")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("name 1", "author 1"), "name 1.OsK")); assertCorrectMetadata(import1, "name 1", "author 1", osu); - var import2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("name 1", "author 1"), "name 1.oSK")); + var import2 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("name 1", "author 1"), "name 1.oSK")); assertImportedOnce(import1, import2); }); @@ -118,7 +117,7 @@ namespace osu.Game.Tests.Skins.IO { MemoryStream exportStream = new MemoryStream(); - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("name 1", "author 1"), "custom.osk")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("name 1", "author 1"), "custom.osk")); assertCorrectMetadata(import1, "name 1 [custom]", "author 1", osu); import1.PerformRead(s => @@ -128,7 +127,7 @@ namespace osu.Game.Tests.Skins.IO string exportFilename = import1.GetDisplayString(); - var import2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(exportStream, $"{exportFilename}.osk")); + var import2 = await loadSkinIntoOsu(osu, new ImportTask(exportStream, $"{exportFilename}.osk")); assertCorrectMetadata(import2, "name 1 [custom]", "author 1", osu); assertImportedOnce(import1, import2); @@ -137,8 +136,8 @@ namespace osu.Game.Tests.Skins.IO [Test] public Task TestSameMetadataNameSameFolderName() => runSkinTest(async osu => { - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("name 1", "author 1"), "my custom skin 1")); - var import2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("name 1", "author 1"), "my custom skin 1")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("name 1", "author 1"), "my custom skin 1")); + var import2 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("name 1", "author 1"), "my custom skin 1")); assertImportedOnce(import1, import2); assertCorrectMetadata(import1, "name 1 [my custom skin 1]", "author 1", osu); @@ -151,8 +150,8 @@ namespace osu.Game.Tests.Skins.IO [Test] public Task TestImportTwiceWithSameMetadataButDifferentFilename() => runSkinTest(async osu => { - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin", "skinner"), "skin.osk")); - var import2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin", "skinner"), "skin2.osk")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("test skin", "skinner"), "skin.osk")); + var import2 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("test skin", "skinner"), "skin2.osk")); assertImportedBoth(import1, import2); }); @@ -161,8 +160,8 @@ namespace osu.Game.Tests.Skins.IO public Task TestImportTwiceWithNoMetadataDifferentDownloadFilename() => runSkinTest(async osu => { // if a user downloads two skins that do have skin.ini files but don't have any creator metadata in the skin.ini, they should both import separately just for safety. - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni(string.Empty, string.Empty), "download.osk")); - var import2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni(string.Empty, string.Empty), "download2.osk")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni(string.Empty, string.Empty), "download.osk")); + var import2 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni(string.Empty, string.Empty), "download2.osk")); assertImportedBoth(import1, import2); }); @@ -170,8 +169,8 @@ namespace osu.Game.Tests.Skins.IO [Test] public Task TestImportTwiceWithSameFilenameDifferentMetadata() => runSkinTest(async osu => { - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin v2", "skinner"), "skin.osk")); - var import2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin v2.1", "skinner"), "skin.osk")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("test skin v2", "skinner"), "skin.osk")); + var import2 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("test skin v2.1", "skinner"), "skin.osk")); assertImportedBoth(import1, import2); assertCorrectMetadata(import1, "test skin v2 [skin]", "skinner", osu); @@ -181,8 +180,8 @@ namespace osu.Game.Tests.Skins.IO [Test] public Task TestSameMetadataNameDifferentFolderName() => runSkinTest(async osu => { - var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("name 1", "author 1"), "my custom skin 1")); - var import2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("name 1", "author 1"), "my custom skin 2")); + var import1 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("name 1", "author 1"), "my custom skin 1")); + var import2 = await loadSkinIntoOsu(osu, new ImportTask(createOskWithIni("name 1", "author 1"), "my custom skin 2")); assertImportedBoth(import1, import2); assertCorrectMetadata(import1, "name 1 [my custom skin 1]", "author 1", osu); @@ -358,10 +357,10 @@ namespace osu.Game.Tests.Skins.IO } } - private async Task> loadSkinIntoOsu(OsuGameBase osu, ArchiveReader archive = null) + private async Task> loadSkinIntoOsu(OsuGameBase osu, ImportTask import = null) { var skinManager = osu.Dependencies.Get(); - return await skinManager.Import(archive); + return await skinManager.Import(import); } } } diff --git a/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs b/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs index bd7e1f8ec5..f4cea2c8cc 100644 --- a/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs +++ b/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs @@ -10,7 +10,7 @@ using osu.Framework.Extensions; using osu.Framework.Testing; using osu.Game.Audio; using osu.Game.Beatmaps; -using osu.Game.IO.Archives; +using osu.Game.Database; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual; @@ -27,7 +27,7 @@ namespace osu.Game.Tests.Skins [BackgroundDependencyLoader] private void load() { - var imported = beatmaps.Import(new ZipArchiveReader(TestResources.OpenResource("Archives/ogg-beatmap.osz"))).GetResultSafely(); + var imported = beatmaps.Import(new ImportTask(TestResources.OpenResource("Archives/ogg-beatmap.osz"), "ogg-beatmap.osz")).GetResultSafely(); imported?.PerformRead(s => { diff --git a/osu.Game.Tests/Skins/TestSceneSkinResources.cs b/osu.Game.Tests/Skins/TestSceneSkinResources.cs index 97588f4053..42c1eeb6d1 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinResources.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinResources.cs @@ -8,7 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.Testing; using osu.Game.Audio; -using osu.Game.IO.Archives; +using osu.Game.Database; using osu.Game.Skinning; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual; @@ -26,7 +26,7 @@ namespace osu.Game.Tests.Skins [BackgroundDependencyLoader] private void load() { - var imported = skins.Import(new ZipArchiveReader(TestResources.OpenResource("Archives/ogg-skin.osk"))).GetResultSafely(); + var imported = skins.Import(new ImportTask(TestResources.OpenResource("Archives/ogg-skin.osk"), "ogg-skin.osk")).GetResultSafely(); skin = imported.PerformRead(skinInfo => skins.GetSkin(skinInfo)); } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 1dd3f82426..91e1744258 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -409,9 +409,6 @@ namespace osu.Game.Beatmaps public Task?> Import(ImportTask task, bool batchImport = false, CancellationToken cancellationToken = default) => beatmapImporter.Import(task, batchImport, cancellationToken); - public Task?> Import(ArchiveReader archive, bool batchImport = false, CancellationToken cancellationToken = default) => - beatmapImporter.Import(archive, batchImport, cancellationToken); - public Live? Import(BeatmapSetInfo item, ArchiveReader? archive = null, CancellationToken cancellationToken = default) => beatmapImporter.Import(item, archive, false, cancellationToken); diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index c5e04a8a0f..84decdb3ef 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -188,7 +188,7 @@ namespace osu.Game.Database Live? import; using (ArchiveReader reader = task.GetReader()) - import = await Import(reader, batchImport, cancellationToken).ConfigureAwait(false); + import = await importFromArchive(reader, batchImport, cancellationToken).ConfigureAwait(false); // We may or may not want to delete the file depending on where it is stored. // e.g. reconstructing/repairing database with items from default storage. @@ -213,7 +213,7 @@ namespace osu.Game.Database /// The archive to be imported. /// Whether this import is part of a larger batch. /// An optional cancellation token. - public async Task?> Import(ArchiveReader archive, bool batchImport = false, CancellationToken cancellationToken = default) + private async Task?> importFromArchive(ArchiveReader archive, bool batchImport = false, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index 766b5bf2a4..c81195bbd3 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -19,7 +19,6 @@ using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Database; -using osu.Game.IO.Archives; using osu.Game.Online.API; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; @@ -141,7 +140,7 @@ namespace osu.Game.Screens.Menu { // if we detect that the theme track or beatmap is unavailable this is either first startup or things are in a bad state. // this could happen if a user has nuked their files store. for now, reimport to repair this. - var import = beatmaps.Import(new ZipArchiveReader(game.Resources.GetStream($"Tracks/{BeatmapFile}"), BeatmapFile)).GetResultSafely(); + var import = beatmaps.Import(new ImportTask(game.Resources.GetStream($"Tracks/{BeatmapFile}"), BeatmapFile)).GetResultSafely(); import?.PerformWrite(b => b.Protected = true); diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index be6528db3f..16a0d84263 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -24,7 +24,6 @@ using osu.Framework.Utils; using osu.Game.Audio; using osu.Game.Database; using osu.Game.IO; -using osu.Game.IO.Archives; using osu.Game.Overlays.Notifications; using osu.Game.Utils; @@ -275,9 +274,6 @@ namespace osu.Game.Skinning public Task> Import(ImportTask task, bool batchImport = false, CancellationToken cancellationToken = default) => skinImporter.Import(task, batchImport, cancellationToken); - public Task> Import(ArchiveReader archive, bool batchImport = false, CancellationToken cancellationToken = default) => - skinImporter.Import(archive, batchImport, cancellationToken); - #endregion public void Delete([CanBeNull] Expression> filter = null, bool silent = false) From 92f1a2958c1645dff914fc3f2b0e2a59d803da77 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 15:18:07 +0900 Subject: [PATCH 065/211] Rename `Import(TModel)` to `ImportModel` to differentiate from other import methods --- osu.Game.Tests/Database/BeatmapImporterTests.cs | 2 +- .../Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs | 4 ++-- osu.Game/Beatmaps/BeatmapManager.cs | 4 ++-- osu.Game/Database/RealmArchiveModelImporter.cs | 4 ++-- osu.Game/Scoring/ScoreManager.cs | 2 +- osu.Game/Skinning/SkinManager.cs | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index 841622f0db..d8856a2ca7 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -745,7 +745,7 @@ namespace osu.Game.Tests.Database } }; - var imported = importer.Import(toImport); + var imported = importer.ImportModel(toImport); realm.Run(r => r.Refresh()); diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs index e502a71f34..1d33a895eb 100644 --- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs @@ -227,10 +227,10 @@ namespace osu.Game.Tests.Online this.testBeatmapManager = testBeatmapManager; } - public override Live Import(BeatmapSetInfo item, ArchiveReader archive = null, bool batchImport = false, CancellationToken cancellationToken = default) + public override Live ImportModel(BeatmapSetInfo item, ArchiveReader archive = null, bool batchImport = false, CancellationToken cancellationToken = default) { testBeatmapManager.AllowImport.Task.WaitSafely(); - return (testBeatmapManager.CurrentImport = base.Import(item, archive, batchImport, cancellationToken)); + return (testBeatmapManager.CurrentImport = base.ImportModel(item, archive, batchImport, cancellationToken)); } } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 91e1744258..06a8ad5188 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -101,7 +101,7 @@ namespace osu.Game.Beatmaps foreach (BeatmapInfo b in beatmapSet.Beatmaps) b.BeatmapSet = beatmapSet; - var imported = beatmapImporter.Import(beatmapSet); + var imported = beatmapImporter.ImportModel(beatmapSet); if (imported == null) throw new InvalidOperationException("Failed to import new beatmap"); @@ -410,7 +410,7 @@ namespace osu.Game.Beatmaps beatmapImporter.Import(task, batchImport, cancellationToken); public Live? Import(BeatmapSetInfo item, ArchiveReader? archive = null, CancellationToken cancellationToken = default) => - beatmapImporter.Import(item, archive, false, cancellationToken); + beatmapImporter.ImportModel(item, archive, false, cancellationToken); public IEnumerable HandledExtensions => beatmapImporter.HandledExtensions; diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index 84decdb3ef..3d61345f34 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -236,7 +236,7 @@ namespace osu.Game.Database return null; } - var scheduledImport = Task.Factory.StartNew(() => Import(model, archive, batchImport, cancellationToken), + var scheduledImport = Task.Factory.StartNew(() => ImportModel(model, archive, batchImport, cancellationToken), cancellationToken, TaskCreationOptions.HideScheduler, batchImport ? import_scheduler_batch : import_scheduler); @@ -251,7 +251,7 @@ namespace osu.Game.Database /// An optional archive to use for model population. /// If true, imports will be skipped before they begin, given an existing model matches on hash and filenames. Should generally only be used for large batch imports, as it may defy user expectations when updating an existing model. /// An optional cancellation token. - public virtual Live? Import(TModel item, ArchiveReader? archive = null, bool batchImport = false, CancellationToken cancellationToken = default) => Realm.Run(realm => + public virtual Live? ImportModel(TModel item, ArchiveReader? archive = null, bool batchImport = false, CancellationToken cancellationToken = default) => Realm.Run(realm => { cancellationToken.ThrowIfCancellationRequested(); diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 7ccf7a58b8..44aafbec74 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -265,7 +265,7 @@ namespace osu.Game.Scoring public Task>> Import(ProgressNotification notification, params ImportTask[] tasks) => scoreImporter.Import(notification, tasks); public Live Import(ScoreInfo item, ArchiveReader archive = null, bool batchImport = false, CancellationToken cancellationToken = default) => - scoreImporter.Import(item, archive, batchImport, cancellationToken); + scoreImporter.ImportModel(item, archive, batchImport, cancellationToken); #region Implementation of IPresentImports diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 16a0d84263..38eff2f0d6 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -167,7 +167,7 @@ namespace osu.Game.Skinning Name = NamingUtils.GetNextBestName(existingSkinNames, $@"{s.Name} (modified)") }; - var result = skinImporter.Import(skinInfo); + var result = skinImporter.ImportModel(skinInfo); if (result != null) { From dd93c7359e184f1bf630dacfd9dcfaf1b6f6ff7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 15:25:43 +0900 Subject: [PATCH 066/211] Update xmldoc for `importFromArchive` method --- .../Database/RealmArchiveModelImporter.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index 3d61345f34..f3174b46b8 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -208,8 +208,11 @@ namespace osu.Game.Database } /// - /// Silently import an item from an . + /// Create and import a model based off the provided . /// + /// + /// This method also handled queueing the import task on a relevant import thread pool. + /// /// The archive to be imported. /// Whether this import is part of a larger batch. /// An optional cancellation token. @@ -225,6 +228,13 @@ namespace osu.Game.Database if (model == null) return null; + + var scheduledImport = Task.Factory.StartNew(() => ImportModel(model, archive, batchImport, cancellationToken), + cancellationToken, + TaskCreationOptions.HideScheduler, + batchImport ? import_scheduler_batch : import_scheduler); + + return await scheduledImport.ConfigureAwait(false); } catch (TaskCanceledException) { @@ -235,13 +245,6 @@ namespace osu.Game.Database LogForModel(model, @$"Model creation of {archive.Name} failed.", e); return null; } - - var scheduledImport = Task.Factory.StartNew(() => ImportModel(model, archive, batchImport, cancellationToken), - cancellationToken, - TaskCreationOptions.HideScheduler, - batchImport ? import_scheduler_batch : import_scheduler); - - return await scheduledImport.ConfigureAwait(false); } /// From 03ab6fc141ea1931bf877ca55fd5aeac4162cf3a Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 20 Jun 2022 14:56:04 +0900 Subject: [PATCH 067/211] Implement IEquatable on ControlPoint --- .../Beatmaps/ControlPoints/ControlPoint.cs | 15 ++++++++-- .../ControlPoints/ControlPointGroup.cs | 26 +++++++++++++---- .../ControlPoints/DifficultyControlPoint.cs | 15 ++++++++-- .../ControlPoints/EffectControlPoint.cs | 17 +++++++++-- .../ControlPoints/SampleControlPoint.cs | 16 +++++++++-- .../ControlPoints/TimingControlPoint.cs | 14 +++++++++- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 28 ++++++++++++++++--- 7 files changed, 109 insertions(+), 22 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs index 5f06e03509..fd06c898ab 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using Newtonsoft.Json; using osu.Game.Graphics; @@ -11,7 +9,7 @@ using osuTK.Graphics; namespace osu.Game.Beatmaps.ControlPoints { - public abstract class ControlPoint : IComparable, IDeepCloneable + public abstract class ControlPoint : IComparable, IDeepCloneable, IEquatable { /// /// The time at which the control point takes effect. @@ -48,5 +46,16 @@ namespace osu.Game.Beatmaps.ControlPoints { Time = other.Time; } + + public sealed override bool Equals(object? obj) + => obj is ControlPoint otherControlPoint + && Equals(otherControlPoint); + + public virtual bool Equals(ControlPoint? other) + => other != null + && Time == other.Time; + + // ReSharper disable once NonReadonlyMemberInGetHashCode + public override int GetHashCode() => Time.GetHashCode(); } } diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs index 9df38b01ee..db479f0e5b 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs @@ -1,18 +1,16 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Linq; using osu.Framework.Bindables; namespace osu.Game.Beatmaps.ControlPoints { - public class ControlPointGroup : IComparable + public class ControlPointGroup : IComparable, IEquatable { - public event Action ItemAdded; - public event Action ItemRemoved; + public event Action? ItemAdded; + public event Action? ItemRemoved; /// /// The time at which the control point takes effect. @@ -48,5 +46,23 @@ namespace osu.Game.Beatmaps.ControlPoints controlPoints.Remove(point); ItemRemoved?.Invoke(point); } + + public sealed override bool Equals(object? obj) + => obj is ControlPointGroup otherGroup + && Equals(otherGroup); + + public virtual bool Equals(ControlPointGroup? other) + => other != null + && Time == other.Time + && ControlPoints.SequenceEqual(other.ControlPoints); + + public override int GetHashCode() + { + HashCode hashCode = new HashCode(); + hashCode.Add(Time); + foreach (var point in controlPoints) + hashCode.Add(point); + return hashCode.ToHashCode(); + } } } diff --git a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs index 8b3d755fb6..6f624d20c9 100644 --- a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs @@ -1,8 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System; using osu.Framework.Bindables; using osu.Game.Graphics; using osuTK.Graphics; @@ -12,7 +11,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// Note that going forward, this control point type should always be assigned directly to HitObjects. /// - public class DifficultyControlPoint : ControlPoint + public class DifficultyControlPoint : ControlPoint, IEquatable { public static readonly DifficultyControlPoint DEFAULT = new DifficultyControlPoint { @@ -51,5 +50,15 @@ namespace osu.Game.Beatmaps.ControlPoints base.CopyFrom(other); } + + public override bool Equals(ControlPoint? other) + => other is DifficultyControlPoint otherDifficultyControlPoint + && Equals(otherDifficultyControlPoint); + + public bool Equals(DifficultyControlPoint? other) + => base.Equals(other) + && SliderVelocity == other.SliderVelocity; + + public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), SliderVelocity); } } diff --git a/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs index 35425972da..365d024035 100644 --- a/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs @@ -1,15 +1,14 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System; using osu.Framework.Bindables; using osu.Game.Graphics; using osuTK.Graphics; namespace osu.Game.Beatmaps.ControlPoints { - public class EffectControlPoint : ControlPoint + public class EffectControlPoint : ControlPoint, IEquatable { public static readonly EffectControlPoint DEFAULT = new EffectControlPoint { @@ -83,5 +82,17 @@ namespace osu.Game.Beatmaps.ControlPoints base.CopyFrom(other); } + + public override bool Equals(ControlPoint? other) + => other is EffectControlPoint otherEffectControlPoint + && Equals(otherEffectControlPoint); + + public bool Equals(EffectControlPoint? other) + => base.Equals(other) + && OmitFirstBarLine == other.OmitFirstBarLine + && ScrollSpeed == other.ScrollSpeed + && KiaiMode == other.KiaiMode; + + public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), OmitFirstBarLine, ScrollSpeed, KiaiMode); } } diff --git a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs index bed499ef3f..ab575dfeda 100644 --- a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs @@ -1,8 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System; using osu.Framework.Bindables; using osu.Game.Audio; using osu.Game.Graphics; @@ -13,7 +12,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// Note that going forward, this control point type should always be assigned directly to HitObjects. /// - public class SampleControlPoint : ControlPoint + public class SampleControlPoint : ControlPoint, IEquatable { public const string DEFAULT_BANK = "normal"; @@ -85,5 +84,16 @@ namespace osu.Game.Beatmaps.ControlPoints base.CopyFrom(other); } + + public override bool Equals(ControlPoint? other) + => other is SampleControlPoint otherSampleControlPoint + && Equals(otherSampleControlPoint); + + public bool Equals(SampleControlPoint? other) + => base.Equals(other) + && SampleBank == other.SampleBank + && SampleVolume == other.SampleVolume; + + public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), SampleBank, SampleVolume); } } diff --git a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs index 922439fcb8..87ef4e86d5 100644 --- a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Bindables; using osu.Game.Beatmaps.Timing; using osu.Game.Graphics; @@ -8,7 +9,7 @@ using osuTK.Graphics; namespace osu.Game.Beatmaps.ControlPoints { - public class TimingControlPoint : ControlPoint + public class TimingControlPoint : ControlPoint, IEquatable { /// /// The time signature at this control point. @@ -77,5 +78,16 @@ namespace osu.Game.Beatmaps.ControlPoints base.CopyFrom(other); } + + public override bool Equals(ControlPoint? other) + => other is TimingControlPoint otherTimingControlPoint + && Equals(otherTimingControlPoint); + + public bool Equals(TimingControlPoint? other) + => base.Equals(other) + && TimeSignature.Equals(other.TimeSignature) + && BeatLength.Equals(other.BeatLength); + + public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), TimeSignature, BeatLength); } } diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 0865561854..cc6a9126bd 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; using osu.Framework.Extensions; @@ -162,7 +160,7 @@ namespace osu.Game.Beatmaps.Formats } [Obsolete("Do not use unless you're a legacy ruleset and 100% sure.")] - public class LegacyDifficultyControlPoint : DifficultyControlPoint + public class LegacyDifficultyControlPoint : DifficultyControlPoint, IEquatable { /// /// Legacy BPM multiplier that introduces floating-point errors for rulesets that depend on it. @@ -188,9 +186,20 @@ namespace osu.Game.Beatmaps.Formats BpmMultiplier = ((LegacyDifficultyControlPoint)other).BpmMultiplier; } + + public override bool Equals(ControlPoint? other) + => other is LegacyDifficultyControlPoint otherLegacyDifficultyControlPoint + && Equals(otherLegacyDifficultyControlPoint); + + public bool Equals(LegacyDifficultyControlPoint? other) + => base.Equals(other) + && BpmMultiplier == other.BpmMultiplier; + + // ReSharper disable once NonReadonlyMemberInGetHashCode + public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), BpmMultiplier); } - internal class LegacySampleControlPoint : SampleControlPoint + internal class LegacySampleControlPoint : SampleControlPoint, IEquatable { public int CustomSampleBank; @@ -215,6 +224,17 @@ namespace osu.Game.Beatmaps.Formats CustomSampleBank = ((LegacySampleControlPoint)other).CustomSampleBank; } + + public override bool Equals(ControlPoint? other) + => other is LegacySampleControlPoint otherLegacySampleControlPoint + && Equals(otherLegacySampleControlPoint); + + public bool Equals(LegacySampleControlPoint? other) + => base.Equals(other) + && CustomSampleBank == other.CustomSampleBank; + + // ReSharper disable once NonReadonlyMemberInGetHashCode + public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), CustomSampleBank); } } } From a922ea9b0163a805c5b2108ddecd22cb6d412c4a Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 20 Jun 2022 15:28:36 +0900 Subject: [PATCH 068/211] Fix selection by directly comparing control points Previously, all control points would get replaced, which led to performance issues that was worked around in this PR. By comparing control points, we're able to get good performance without requiring the workaround. --- .../Edit/LegacyEditorBeatmapPatcher.cs | 28 +++++++++++++++---- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 8 ++---- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs index 6b18855396..01bc01bf5b 100644 --- a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs +++ b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs @@ -6,12 +6,14 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; using DiffPlex; using DiffPlex.Model; using osu.Framework.Audio.Track; using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Formats; using osu.Game.IO; using osu.Game.Skinning; @@ -50,14 +52,28 @@ namespace osu.Game.Screens.Edit if (removedIndices.Count == 0 && addedIndices.Count == 0) return; - // Due to conversion from legacy to non-legacy control points, it becomes difficult to diff control points correctly. - // So instead _all_ control points are reloaded if _any_ control point is changed. + ControlPointInfo newControlPoints = EditorBeatmap.ConvertControlPoints(getNewBeatmap().ControlPointInfo); - var newControlPoints = EditorBeatmap.ConvertControlPoints(getNewBeatmap().ControlPointInfo); + // Remove all groups from the current beatmap which don't have a corresponding equal group in the new beatmap. + foreach (var oldGroup in editorBeatmap.ControlPointInfo.Groups.ToArray()) + { + var newGroup = newControlPoints.GroupAt(oldGroup.Time); - editorBeatmap.ControlPointInfo.Clear(); - foreach (var point in newControlPoints.AllControlPoints) - editorBeatmap.ControlPointInfo.Add(point.Time, point); + if (!oldGroup.Equals(newGroup)) + editorBeatmap.ControlPointInfo.RemoveGroup(oldGroup); + } + + // Add all groups from the new beatmap which don't have a corresponding equal group in the old beatmap. + foreach (var newGroup in newControlPoints.Groups) + { + var oldGroup = editorBeatmap.ControlPointInfo.GroupAt(newGroup.Time); + + if (!newGroup.Equals(oldGroup)) + { + foreach (var point in newGroup.ControlPoints) + editorBeatmap.ControlPointInfo.Add(newGroup.Time, point); + } + } } private void processHitObjects(DiffResult result, Func getNewBeatmap) diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index 27b62f1104..60cb263a79 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -139,12 +139,8 @@ namespace osu.Game.Screens.Edit.Timing controlPointGroups.BindTo(Beatmap.ControlPointInfo.Groups); controlPointGroups.BindCollectionChanged((sender, args) => { - // This AddOnce() works around performance issues from the LegacyEditorBeatmapPatcher re-initialising all control points every undo & redo. - Scheduler.AddOnce(() => - { - table.ControlGroups = controlPointGroups; - changeHandler?.SaveState(); - }); + table.ControlGroups = controlPointGroups; + changeHandler?.SaveState(); }, true); } From 678b18dde68ab4d9ba874edfd6de73bc2b28c2e9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 15:29:56 +0900 Subject: [PATCH 069/211] Ensure any non-`MemoryStream` streams are closed as part of `ImportTask` --- osu.Game/Database/ImportTask.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Database/ImportTask.cs b/osu.Game/Database/ImportTask.cs index 0643300fc5..17ca691be3 100644 --- a/osu.Game/Database/ImportTask.cs +++ b/osu.Game/Database/ImportTask.cs @@ -62,6 +62,7 @@ namespace osu.Game.Database { // This isn't used in any current path. May need to reconsider for performance reasons (ie. if we don't expect the incoming stream to be copied out). memoryStream = new MemoryStream(stream.ReadAllBytesToArray()); + stream.Dispose(); } if (ZipUtils.IsZipArchive(memoryStream)) From 882e1c69e50bd53fe87df0525d3f5122517f10dc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 15:36:44 +0900 Subject: [PATCH 070/211] Move nested task back outside try-catch to avoid double-error --- osu.Game/Database/RealmArchiveModelImporter.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index f3174b46b8..e6956d3184 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -228,13 +228,6 @@ namespace osu.Game.Database if (model == null) return null; - - var scheduledImport = Task.Factory.StartNew(() => ImportModel(model, archive, batchImport, cancellationToken), - cancellationToken, - TaskCreationOptions.HideScheduler, - batchImport ? import_scheduler_batch : import_scheduler); - - return await scheduledImport.ConfigureAwait(false); } catch (TaskCanceledException) { @@ -245,6 +238,13 @@ namespace osu.Game.Database LogForModel(model, @$"Model creation of {archive.Name} failed.", e); return null; } + + var scheduledImport = Task.Factory.StartNew(() => ImportModel(model, archive, batchImport, cancellationToken), + cancellationToken, + TaskCreationOptions.HideScheduler, + batchImport ? import_scheduler_batch : import_scheduler); + + return await scheduledImport.ConfigureAwait(false); } /// From 4aa32038c3572fb648694a1f16302dea510a365e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 15:38:44 +0900 Subject: [PATCH 071/211] Add note about stream provided to `ImportTask` being disposed implicitly --- osu.Game/Database/ImportTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/ImportTask.cs b/osu.Game/Database/ImportTask.cs index 17ca691be3..e7f599d85f 100644 --- a/osu.Game/Database/ImportTask.cs +++ b/osu.Game/Database/ImportTask.cs @@ -33,7 +33,7 @@ namespace osu.Game.Database } /// - /// Construct a new import task from a stream. + /// Construct a new import task from a stream. The provided stream will be disposed after reading. /// public ImportTask(Stream stream, string filename) { From e82d948acc5d9ead0202f78707ff12d5069d08de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 16:06:22 +0900 Subject: [PATCH 072/211] Add test coverage of import throwing when no valid `.osu` files are found --- .../Database/BeatmapImporterTests.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index f9cd75d8c3..b018a26aec 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -291,6 +291,42 @@ namespace osu.Game.Tests.Database }); } + [Test] + public void TestImportDirectoryWithEmptyOsuFiles() + { + RunTestWithRealmAsync(async (realm, storage) => + { + using var importer = new BeatmapImporter(storage, realm); + using var store = new RealmRulesetStore(realm, storage); + + string? temp = TestResources.GetTestBeatmapForImport(); + + string extractedFolder = $"{temp}_extracted"; + Directory.CreateDirectory(extractedFolder); + + try + { + using (var zip = ZipArchive.Open(temp)) + zip.WriteToDirectory(extractedFolder); + + foreach (var file in new DirectoryInfo(extractedFolder).GetFiles("*.osu")) + { + using (file.Open(FileMode.Create)) + { + // empty file. + } + } + + var imported = await importer.Import(new ImportTask(extractedFolder)); + Assert.IsNull(imported); + } + finally + { + Directory.Delete(extractedFolder, true); + } + }); + } + [Test] public void TestImportThenImportWithReZip() { From d38defada461430817c8e99d21b49840ef769eb3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 16:07:10 +0900 Subject: [PATCH 073/211] Silence exception and provide more log output when import fails due to empty `.osu` files --- osu.Game/Beatmaps/BeatmapImporter.cs | 9 +++++++++ osu.Game/Beatmaps/Formats/Decoder.cs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapImporter.cs b/osu.Game/Beatmaps/BeatmapImporter.cs index e463492e2b..237088036c 100644 --- a/osu.Game/Beatmaps/BeatmapImporter.cs +++ b/osu.Game/Beatmaps/BeatmapImporter.cs @@ -177,8 +177,17 @@ namespace osu.Game.Beatmaps } Beatmap beatmap; + using (var stream = new LineBufferedReader(reader.GetStream(mapName))) + { + if (stream.PeekLine() == null) + { + Logger.Log($"No content found in first .osu file of beatmap archive ({reader.Name} / {mapName})", LoggingTarget.Database); + return null; + } + beatmap = Decoder.GetDecoder(stream).Decode(stream); + } return new BeatmapSetInfo { diff --git a/osu.Game/Beatmaps/Formats/Decoder.cs b/osu.Game/Beatmaps/Formats/Decoder.cs index aad29f46fb..ca1bcc97fd 100644 --- a/osu.Game/Beatmaps/Formats/Decoder.cs +++ b/osu.Game/Beatmaps/Formats/Decoder.cs @@ -74,7 +74,7 @@ namespace osu.Game.Beatmaps.Formats } if (line == null) - throw new IOException("Unknown file format (null)"); + throw new IOException("Unknown file format (no content)"); var decoder = typedDecoders.Where(d => line.StartsWith(d.Key, StringComparison.InvariantCulture)).Select(d => d.Value).FirstOrDefault(); From ca287d093621d3997e1f8abb1b1b60e33a026e94 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 20 Jun 2022 16:38:11 +0900 Subject: [PATCH 074/211] Fix group deselected when table is recreated --- osu.Game/Screens/Edit/EditorTable.cs | 5 ++--- osu.Game/Screens/Edit/Timing/ControlPointTable.cs | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorTable.cs b/osu.Game/Screens/Edit/EditorTable.cs index 8765dae384..a290cce708 100644 --- a/osu.Game/Screens/Edit/EditorTable.cs +++ b/osu.Game/Screens/Edit/EditorTable.cs @@ -97,7 +97,7 @@ namespace osu.Game.Screens.Edit [BackgroundDependencyLoader] private void load(OverlayColourProvider colours) { - hoveredBackground.Colour = colourHover = colours.Background1; + colourHover = colours.Background1; colourSelected = colours.Colour3; } @@ -105,8 +105,7 @@ namespace osu.Game.Screens.Edit { base.LoadComplete(); - // Reduce flicker of rows when offset is being changed rapidly. - // Probably need to reconsider this. + updateState(); FinishTransforms(true); } diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs index 88c738c1d2..6d46b429f0 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs @@ -44,6 +44,7 @@ namespace osu.Game.Screens.Edit.Timing { BackgroundFlow.Add(new RowBackground(group) { + Selected = group.Equals(selectedGroup?.Value), Action = () => { selectedGroup.Value = group; From 16281f4a4831cebda36a6bf669ed59ab99408b40 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 20 Jun 2022 16:52:01 +0900 Subject: [PATCH 075/211] Properly annotate method to allow null --- osu.Game/Beatmaps/ControlPoints/ControlPoint.cs | 2 +- osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs | 2 +- osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs | 2 +- osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs | 2 +- osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs | 2 +- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs index fd06c898ab..b91d609849 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs @@ -28,7 +28,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// An existing control point to compare with. /// Whether this is redundant when placed alongside . - public abstract bool IsRedundant(ControlPoint existing); + public abstract bool IsRedundant(ControlPoint? existing); /// /// Create an unbound copy of this control point. diff --git a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs index 6f624d20c9..c199d1da59 100644 --- a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs @@ -40,7 +40,7 @@ namespace osu.Game.Beatmaps.ControlPoints set => SliderVelocityBindable.Value = value; } - public override bool IsRedundant(ControlPoint existing) + public override bool IsRedundant(ControlPoint? existing) => existing is DifficultyControlPoint existingDifficulty && SliderVelocity == existingDifficulty.SliderVelocity; diff --git a/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs index 365d024035..ead07b4eaa 100644 --- a/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs @@ -67,7 +67,7 @@ namespace osu.Game.Beatmaps.ControlPoints set => KiaiModeBindable.Value = value; } - public override bool IsRedundant(ControlPoint existing) + public override bool IsRedundant(ControlPoint? existing) => !OmitFirstBarLine && existing is EffectControlPoint existingEffect && KiaiMode == existingEffect.KiaiMode diff --git a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs index ab575dfeda..78dec67937 100644 --- a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs @@ -72,7 +72,7 @@ namespace osu.Game.Beatmaps.ControlPoints public virtual HitSampleInfo ApplyTo(HitSampleInfo hitSampleInfo) => hitSampleInfo.With(newBank: hitSampleInfo.Bank ?? SampleBank, newVolume: hitSampleInfo.Volume > 0 ? hitSampleInfo.Volume : SampleVolume); - public override bool IsRedundant(ControlPoint existing) + public override bool IsRedundant(ControlPoint? existing) => existing is SampleControlPoint existingSample && SampleBank == existingSample.SampleBank && SampleVolume == existingSample.SampleVolume; diff --git a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs index 87ef4e86d5..23d4d10fd8 100644 --- a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs @@ -69,7 +69,7 @@ namespace osu.Game.Beatmaps.ControlPoints public double BPM => 60000 / BeatLength; // Timing points are never redundant as they can change the time signature. - public override bool IsRedundant(ControlPoint existing) => false; + public override bool IsRedundant(ControlPoint? existing) => false; public override void CopyFrom(ControlPoint other) { diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index cc6a9126bd..a5e6ac0a1c 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -213,7 +213,7 @@ namespace osu.Game.Beatmaps.Formats return baseInfo; } - public override bool IsRedundant(ControlPoint existing) + public override bool IsRedundant(ControlPoint? existing) => base.IsRedundant(existing) && existing is LegacySampleControlPoint existingSample && CustomSampleBank == existingSample.CustomSampleBank; From e0c82d11ab339009718b880c95697ef74ede594c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 20 Jun 2022 16:53:03 +0900 Subject: [PATCH 076/211] Convert == usages to ReferenceEquals --- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 2 +- osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs | 8 ++++---- .../Visual/UserInterface/TestSceneBeatSyncedContainer.cs | 4 ++-- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 2 +- osu.Game/Rulesets/Objects/HitObject.cs | 4 ++-- .../Timelines/Summary/Parts/ControlPointPart.cs | 2 +- .../Components/Timeline/TimelineControlPointDisplay.cs | 2 +- .../Components/Timeline/TimelineHitObjectBlueprint.cs | 6 +++--- osu.Game/Screens/Edit/EditorClock.cs | 2 +- osu.Game/Screens/Edit/Timing/ControlPointTable.cs | 3 ++- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 2 +- osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs | 2 +- 12 files changed, 20 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index 4589a8eca1..f03bcffdc8 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -374,7 +374,7 @@ namespace osu.Game.Rulesets.Osu.Mods int i = 0; double currentTime = timingPoint.Time; - while (!definitelyBigger(currentTime, mapEndTime) && controlPointInfo.TimingPointAt(currentTime) == timingPoint) + while (!definitelyBigger(currentTime, mapEndTime) && ReferenceEquals(controlPointInfo.TimingPointAt(currentTime), timingPoint)) { beats.Add(Math.Floor(currentTime)); i++; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs index cf1246ef07..e9bbf1e33d 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs @@ -117,8 +117,8 @@ namespace osu.Game.Tests.Visual.Editing // After placement these must be non-default as defaults are read-only. AddAssert("Placed object has non-default control points", () => - EditorBeatmap.HitObjects[0].SampleControlPoint != SampleControlPoint.DEFAULT && - EditorBeatmap.HitObjects[0].DifficultyControlPoint != DifficultyControlPoint.DEFAULT); + !ReferenceEquals(EditorBeatmap.HitObjects[0].SampleControlPoint, SampleControlPoint.DEFAULT) && + !ReferenceEquals(EditorBeatmap.HitObjects[0].DifficultyControlPoint, DifficultyControlPoint.DEFAULT)); ReloadEditorToSameBeatmap(); @@ -126,8 +126,8 @@ namespace osu.Game.Tests.Visual.Editing // After placement these must be non-default as defaults are read-only. AddAssert("Placed object still has non-default control points", () => - EditorBeatmap.HitObjects[0].SampleControlPoint != SampleControlPoint.DEFAULT && - EditorBeatmap.HitObjects[0].DifficultyControlPoint != DifficultyControlPoint.DEFAULT); + !ReferenceEquals(EditorBeatmap.HitObjects[0].SampleControlPoint, SampleControlPoint.DEFAULT) && + !ReferenceEquals(EditorBeatmap.HitObjects[0].DifficultyControlPoint, DifficultyControlPoint.DEFAULT)); } [Test] diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs index 27c107a2db..6cf66963a5 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs @@ -269,7 +269,7 @@ namespace osu.Game.Tests.Visual.UserInterface private TimingControlPoint getNextTimingPoint(TimingControlPoint current) { - if (timingPoints[^1] == current) + if (ReferenceEquals(timingPoints[^1], current)) return current; int index = timingPoints.IndexOf(current); // -1 means that this is a "default beat" @@ -281,7 +281,7 @@ namespace osu.Game.Tests.Visual.UserInterface { if (timingPoints.Count == 0) return 0; - if (timingPoints[^1] == current) + if (ReferenceEquals(timingPoints[^1], current)) { Debug.Assert(BeatSyncSource.Clock != null); diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 4146bbcc5e..45a935d165 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -127,7 +127,7 @@ namespace osu.Game.Graphics.Containers TimeSinceLastBeat = beatLength - TimeUntilNextBeat; - if (timingPoint == lastTimingPoint && beatIndex == lastBeat) + if (ReferenceEquals(timingPoint, lastTimingPoint) && beatIndex == lastBeat) return; // as this event is sometimes used for sound triggers where `BeginDelayedSequence` has no effect, avoid firing it if too far away from the beat. diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 30b8fe965a..d20e0616e5 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.Objects if (legacyInfo != null) DifficultyControlPoint = (DifficultyControlPoint)legacyInfo.DifficultyPointAt(StartTime).DeepClone(); - else if (DifficultyControlPoint == DifficultyControlPoint.DEFAULT) + else if (ReferenceEquals(DifficultyControlPoint, DifficultyControlPoint.DEFAULT)) DifficultyControlPoint = new DifficultyControlPoint(); DifficultyControlPoint.Time = StartTime; @@ -118,7 +118,7 @@ namespace osu.Game.Rulesets.Objects // This is done here after ApplyDefaultsToSelf as we may require custom defaults to be applied to have an accurate end time. if (legacyInfo != null) SampleControlPoint = (SampleControlPoint)legacyInfo.SamplePointAt(this.GetEndTime() + control_point_leniency).DeepClone(); - else if (SampleControlPoint == SampleControlPoint.DEFAULT) + else if (ReferenceEquals(SampleControlPoint, SampleControlPoint.DEFAULT)) SampleControlPoint = new SampleControlPoint(); SampleControlPoint.Time = this.GetEndTime() + control_point_leniency; diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs index 4e2c018330..ee82ded39d 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs @@ -49,7 +49,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts case NotifyCollectionChangedAction.Remove: foreach (var group in args.OldItems.OfType()) { - var matching = Children.SingleOrDefault(gv => gv.Group == group); + var matching = Children.SingleOrDefault(gv => ReferenceEquals(gv.Group, group)); if (matching != null) matching.Expire(); diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs index 5d5681ea2b..544c3f8369 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs @@ -40,7 +40,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline case NotifyCollectionChangedAction.Remove: foreach (var group in args.OldItems.OfType()) { - var matching = Children.SingleOrDefault(gv => gv.Group == group); + var matching = Children.SingleOrDefault(gv => ReferenceEquals(gv.Group, group)); matching?.Expire(); } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs index 34abe81ae2..32ebc9c3c1 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs @@ -205,7 +205,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline updateRepeats(repeats); } - if (difficultyControlPoint != Item.DifficultyControlPoint) + if (!ReferenceEquals(difficultyControlPoint, Item.DifficultyControlPoint)) { difficultyControlPoint = Item.DifficultyControlPoint; difficultyOverrideDisplay?.Expire(); @@ -220,7 +220,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline } } - if (sampleControlPoint != Item.SampleControlPoint) + if (!ReferenceEquals(sampleControlPoint, Item.SampleControlPoint)) { sampleControlPoint = Item.SampleControlPoint; sampleOverrideDisplay?.Expire(); @@ -393,7 +393,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline if (e.CurrentState.Keyboard.ShiftPressed) { - if (hitObject.DifficultyControlPoint == DifficultyControlPoint.DEFAULT) + if (ReferenceEquals(hitObject.DifficultyControlPoint, DifficultyControlPoint.DEFAULT)) hitObject.DifficultyControlPoint = new DifficultyControlPoint(); double newVelocity = hitObject.DifficultyControlPoint.SliderVelocity * (repeatHitObject.Duration / proposedDuration); diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs index c7df36be77..c3b29afd30 100644 --- a/osu.Game/Screens/Edit/EditorClock.cs +++ b/osu.Game/Screens/Edit/EditorClock.cs @@ -141,7 +141,7 @@ namespace osu.Game.Screens.Edit seekTime = timingPoint.Time + closestBeat * seekAmount; } - if (seekTime < timingPoint.Time && timingPoint != ControlPointInfo.TimingPoints.First()) + if (seekTime < timingPoint.Time && !ReferenceEquals(timingPoint, ControlPointInfo.TimingPoints.First())) seekTime = timingPoint.Time; SeekSmoothlyTo(seekTime); diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs index 6d46b429f0..b6e3e91c98 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs @@ -65,7 +65,8 @@ namespace osu.Game.Screens.Edit.Timing selectedGroup.BindValueChanged(group => { // TODO: This should scroll the selected row into view. - foreach (var b in BackgroundFlow) b.Selected = b.Item == group.NewValue; + foreach (var b in BackgroundFlow) + b.Selected = ReferenceEquals(b.Item, group.NewValue); }, true); } diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index 60cb263a79..c33dcc6e91 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -222,7 +222,7 @@ namespace osu.Game.Screens.Edit.Timing // Try and create matching types from the currently selected control point. var selected = selectedGroup.Value; - if (selected != null && selected != group) + if (selected != null && !ReferenceEquals(selected, group)) { foreach (var controlPoint in selected.ControlPoints) { diff --git a/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs b/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs index 67b7abb25b..1cdcfdf167 100644 --- a/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs @@ -128,7 +128,7 @@ namespace osu.Game.Screens.Edit.Timing double? offsetChange = newStartTime - selectedGroupStartTime; var nextGroup = editorBeatmap.ControlPointInfo.TimingPoints - .SkipWhile(g => g != tcp) + .SkipWhile(g => !ReferenceEquals(g, tcp)) .Skip(1) .FirstOrDefault(); From b0b3ea42ccf6330125d94da23ef26110f2a3a61a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 20 Jun 2022 10:44:14 +0200 Subject: [PATCH 077/211] Remove null default value in `ImportSkinTest` helper method --- osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index f3adb85006..8b7fcae1a9 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -357,7 +357,7 @@ namespace osu.Game.Tests.Skins.IO } } - private async Task> loadSkinIntoOsu(OsuGameBase osu, ImportTask import = null) + private async Task> loadSkinIntoOsu(OsuGameBase osu, ImportTask import) { var skinManager = osu.Dependencies.Get(); return await skinManager.Import(import); From ebcee21f6f50d640a00badab6013ea332d14338d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 17:52:42 +0900 Subject: [PATCH 078/211] Remove necessity to provide `BeatmapDifficultyCache` as a function to `ScoreManager` --- osu.Game/OsuGameBase.cs | 6 ++++-- osu.Game/Scoring/ScoreManager.cs | 12 +++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index f0f364314c..a09588516d 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -264,14 +264,16 @@ namespace osu.Game var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures); + dependencies.Cache(difficultyCache = new BeatmapDifficultyCache()); + // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup() - dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, realm, Scheduler, () => difficultyCache, LocalConfig)); + dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, realm, Scheduler, difficultyCache, LocalConfig)); dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, realm, RulesetStore, API, Audio, Resources, Host, defaultBeatmap, performOnlineLookups: true)); dependencies.Cache(BeatmapDownloader = new BeatmapModelDownloader(BeatmapManager, API)); dependencies.Cache(ScoreDownloader = new ScoreModelDownloader(ScoreManager, API)); - dependencies.Cache(difficultyCache = new BeatmapDifficultyCache()); + // Add after all the above cache operations as it depends on them. AddInternal(difficultyCache); dependencies.Cache(userCache = new UserLookupCache()); diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 44aafbec74..027e25d3b3 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -27,16 +27,16 @@ namespace osu.Game.Scoring public class ScoreManager : ModelManager, IModelImporter { private readonly Scheduler scheduler; - private readonly Func difficulties; + private readonly BeatmapDifficultyCache difficultyCache; private readonly OsuConfigManager configManager; private readonly ScoreImporter scoreImporter; public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, RealmAccess realm, Scheduler scheduler, - Func difficulties = null, OsuConfigManager configManager = null) + BeatmapDifficultyCache difficultyCache = null, OsuConfigManager configManager = null) : base(storage, realm) { this.scheduler = scheduler; - this.difficulties = difficulties; + this.difficultyCache = difficultyCache; this.configManager = configManager; scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm) @@ -65,8 +65,6 @@ namespace osu.Game.Scoring /// The given ordered by decreasing total score. public async Task OrderByTotalScoreAsync(ScoreInfo[] scores, CancellationToken cancellationToken = default) { - var difficultyCache = difficulties?.Invoke(); - if (difficultyCache != null) { // Compute difficulties asynchronously first to prevent blocking via the GetTotalScore() call below. @@ -168,11 +166,11 @@ namespace osu.Game.Scoring return score.BeatmapInfo.MaxCombo.Value; #pragma warning restore CS0618 - if (difficulties == null) + if (difficultyCache == 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); + var difficulty = await difficultyCache.GetDifficultyAsync(score.BeatmapInfo, score.Ruleset, score.Mods, cancellationToken).ConfigureAwait(false); return difficulty?.MaxCombo; } From dbae4c6f5a9f307bbb4aad65f4fa841b6523e097 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 18:21:37 +0900 Subject: [PATCH 079/211] `PostImport` -> `PresentImport` --- osu.Game/Beatmaps/BeatmapManager.cs | 4 ++-- osu.Game/Database/IPostImports.cs | 2 +- osu.Game/Database/RealmArchiveModelImporter.cs | 6 +++--- osu.Game/OsuGame.cs | 4 ++-- osu.Game/Scoring/ScoreManager.cs | 4 ++-- osu.Game/Skinning/SkinManager.cs | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 06a8ad5188..816808638f 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -454,9 +454,9 @@ namespace osu.Game.Beatmaps #region Implementation of IPostImports - public Action>>? PostImport + public Action>>? PresentImport { - set => beatmapImporter.PostImport = value; + set => beatmapImporter.PresentImport = value; } #endregion diff --git a/osu.Game/Database/IPostImports.cs b/osu.Game/Database/IPostImports.cs index 83a211f6e6..d8493d5e18 100644 --- a/osu.Game/Database/IPostImports.cs +++ b/osu.Game/Database/IPostImports.cs @@ -12,6 +12,6 @@ namespace osu.Game.Database /// /// Fired when the user requests to view the resulting import. /// - public Action>>? PostImport { set; } + public Action>>? PresentImport { set; } } } diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index e6956d3184..6d5a10682f 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -65,7 +65,7 @@ namespace osu.Game.Database /// /// Fired when the user requests to view the resulting import. /// - public Action>>? PostImport { get; set; } + public Action>>? PresentImport { get; set; } /// /// Set an endpoint for notifications to be posted to. @@ -158,12 +158,12 @@ namespace osu.Game.Database ? $"Imported {imported.First().GetDisplayString()}!" : $"Imported {imported.Count} {HumanisedModelName}s!"; - if (imported.Count > 0 && PostImport != null) + if (imported.Count > 0 && PresentImport != null) { notification.CompletionText += " Click to view."; notification.CompletionClickAction = () => { - PostImport?.Invoke(imported); + PresentImport?.Invoke(imported); return true; }; } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 97476358b1..4732a991a2 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -711,13 +711,13 @@ namespace osu.Game SkinManager.PostNotification = n => Notifications.Post(n); BeatmapManager.PostNotification = n => Notifications.Post(n); - BeatmapManager.PostImport = items => PresentBeatmap(items.First().Value); + BeatmapManager.PresentImport = items => PresentBeatmap(items.First().Value); BeatmapDownloader.PostNotification = n => Notifications.Post(n); ScoreDownloader.PostNotification = n => Notifications.Post(n); ScoreManager.PostNotification = n => Notifications.Post(n); - ScoreManager.PostImport = items => PresentScore(items.First().Value); + ScoreManager.PresentImport = items => PresentScore(items.First().Value); // make config aware of how to lookup skins for on-screen display purposes. // if this becomes a more common thing, tracked settings should be reconsidered to allow local DI. diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 44aafbec74..139675711f 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -269,9 +269,9 @@ namespace osu.Game.Scoring #region Implementation of IPresentImports - public Action>> PostImport + public Action>> PresentImport { - set => scoreImporter.PostImport = value; + set => scoreImporter.PresentImport = value; } #endregion diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 38eff2f0d6..dc0197e613 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -259,9 +259,9 @@ namespace osu.Game.Skinning #region Implementation of IModelImporter - public Action>> PostImport + public Action>> PresentImport { - set => skinImporter.PostImport = value; + set => skinImporter.PresentImport = value; } public Task Import(params string[] paths) => skinImporter.Import(paths); From 45c5013f09d5467d8087e7bd24661cf929aee91d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 18:38:02 +0900 Subject: [PATCH 080/211] Remove default value of `RealmArchiveModelImporter.HandledExtensions` Not used anywhere and probably not wanted ever. --- osu.Game/Database/RealmArchiveModelImporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index 6d5a10682f..584dda7264 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -56,7 +56,7 @@ namespace osu.Game.Database /// private static readonly ThreadedTaskScheduler import_scheduler_batch = new ThreadedTaskScheduler(import_queue_request_concurrency, nameof(RealmArchiveModelImporter)); - public virtual IEnumerable HandledExtensions => new[] { @".zip" }; + public abstract IEnumerable HandledExtensions { get; } protected readonly RealmFileStore Files; From e732c5a2d750ed0ae6687eb3277d0fc44f8c8578 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 18:38:37 +0900 Subject: [PATCH 081/211] Add `PostImport` method matching `PreImport` --- osu.Game/Database/RealmArchiveModelImporter.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index 584dda7264..27bfaf05be 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -338,6 +338,8 @@ namespace osu.Game.Database transaction.Commit(); } + PostImport(item, realm); + LogForModel(item, @"Import successfully completed!"); } catch (Exception e) @@ -473,6 +475,15 @@ namespace osu.Game.Database { } + /// + /// Perform any final actions after the import has been committed to the database. + /// + /// The model prepared for import. + /// The current realm context. + protected virtual void PostImport(TModel model, Realm realm) + { + } + /// /// Check whether an existing model already exists for a new import item. /// From ba394f283111e19ff274bae8cc4cc93a0cd46110 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Jun 2022 18:53:48 +0900 Subject: [PATCH 082/211] Remove `IPostsImports` interface (and move to `IModelImporter`) --- osu.Game/Database/IModelImporter.cs | 8 +++++++- osu.Game/Database/IPostImports.cs | 17 ----------------- 2 files changed, 7 insertions(+), 18 deletions(-) delete mode 100644 osu.Game/Database/IPostImports.cs diff --git a/osu.Game/Database/IModelImporter.cs b/osu.Game/Database/IModelImporter.cs index bf9f2f9c75..26342cb5fe 100644 --- a/osu.Game/Database/IModelImporter.cs +++ b/osu.Game/Database/IModelImporter.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.Collections.Generic; using System.Threading.Tasks; using osu.Game.Overlays.Notifications; @@ -11,7 +12,7 @@ namespace osu.Game.Database /// A class which handles importing of associated models to the game store. /// /// The model type. - public interface IModelImporter : IPostNotifications, IPostImports, ICanAcceptFiles + public interface IModelImporter : IPostNotifications, ICanAcceptFiles where TModel : class, IHasGuidPrimaryKey { /// @@ -26,5 +27,10 @@ namespace osu.Game.Database /// A user displayable name for the model type associated with this manager. /// string HumanisedModelName => $"{typeof(TModel).Name.Replace(@"Info", "").ToLower()}"; + + /// + /// Fired when the user requests to view the resulting import. + /// + public Action>>? PresentImport { set; } } } diff --git a/osu.Game/Database/IPostImports.cs b/osu.Game/Database/IPostImports.cs deleted file mode 100644 index d8493d5e18..0000000000 --- a/osu.Game/Database/IPostImports.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Collections.Generic; - -namespace osu.Game.Database -{ - public interface IPostImports - where TModel : class, IHasGuidPrimaryKey - { - /// - /// Fired when the user requests to view the resulting import. - /// - public Action>>? PresentImport { set; } - } -} From 34f1c80b7c2dbe6125510f274b42f251be0fb8dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 20 Jun 2022 20:04:21 +0200 Subject: [PATCH 083/211] Add and use `ILinkHandler` interface --- .../Graphics/Containers/LinkFlowContainer.cs | 7 +++-- .../Markdown/OsuMarkdownLinkText.cs | 5 ++-- osu.Game/Online/ILinkHandler.cs | 30 +++++++++++++++++++ osu.Game/OsuGame.cs | 3 +- 4 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Online/ILinkHandler.cs diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index a67e5ae66f..bf96695fd3 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; using osu.Framework.Platform; +using osu.Game.Online; using osu.Game.Users; namespace osu.Game.Graphics.Containers @@ -25,7 +26,7 @@ namespace osu.Game.Graphics.Containers } [Resolved(CanBeNull = true)] - private OsuGame game { get; set; } + private ILinkHandler linkHandler { get; set; } [Resolved] private GameHost host { get; set; } @@ -81,8 +82,8 @@ namespace osu.Game.Graphics.Containers { if (action != null) action(); - else if (game != null) - game.HandleLink(link); + else if (linkHandler != null) + linkHandler.HandleLink(link); // fallback to handle cases where OsuGame is not available, ie. tournament client. else if (link.Action == LinkAction.External) host.OpenUrlExternally(link.Argument.ToString()); diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownLinkText.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownLinkText.cs index dca9e3de6e..3a16eb0a0f 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownLinkText.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownLinkText.cs @@ -8,6 +8,7 @@ using Markdig.Syntax.Inlines; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers.Markdown; +using osu.Game.Online; using osu.Game.Online.Chat; using osu.Game.Overlays; @@ -16,7 +17,7 @@ namespace osu.Game.Graphics.Containers.Markdown public class OsuMarkdownLinkText : MarkdownLinkText { [Resolved(canBeNull: true)] - private OsuGame game { get; set; } + private ILinkHandler linkHandler { get; set; } private readonly string text; private readonly string title; @@ -51,7 +52,7 @@ namespace osu.Game.Graphics.Containers.Markdown }; } - protected override void OnLinkPressed() => game?.HandleLink(Url); + protected override void OnLinkPressed() => linkHandler?.HandleLink(Url); private class OsuMarkdownLinkCompiler : DrawableLinkCompiler { diff --git a/osu.Game/Online/ILinkHandler.cs b/osu.Game/Online/ILinkHandler.cs new file mode 100644 index 0000000000..1b8fad4bd9 --- /dev/null +++ b/osu.Game/Online/ILinkHandler.cs @@ -0,0 +1,30 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Game.Online.Chat; + +namespace osu.Game.Online +{ + /// + /// Handle an arbitrary URL. Displays via in-game overlays where possible. + /// Methods can be called from a non-thread-safe non-game-loaded state. + /// + [Cached] + public interface ILinkHandler + { + /// + /// Handle an arbitrary URL. Displays via in-game overlays where possible. + /// This can be called from a non-thread-safe non-game-loaded state. + /// + /// The URL to load. + void HandleLink(string url); + + /// + /// Handle a specific . + /// This can be called from a non-thread-safe non-game-loaded state. + /// + /// The link to load. + void HandleLink(LinkDetails link); + } +} diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4732a991a2..f51a18b36f 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -39,6 +39,7 @@ using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.IO; using osu.Game.Localisation; +using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Overlays; @@ -69,7 +70,7 @@ namespace osu.Game /// The full osu! experience. Builds on top of to add menus and binding logic /// for initial components that are generally retrieved via DI. /// - public class OsuGame : OsuGameBase, IKeyBindingHandler, ILocalUserPlayInfo, IPerformFromScreenRunner, IOverlayManager + public class OsuGame : OsuGameBase, IKeyBindingHandler, ILocalUserPlayInfo, IPerformFromScreenRunner, IOverlayManager, ILinkHandler { /// /// The amount of global offset to apply when a left/right anchored overlay is displayed (ie. settings or notifications). From 92011124d146be3074b8a1df18e1b0a0f8f5cb35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 20 Jun 2022 20:08:36 +0200 Subject: [PATCH 084/211] Implement IPC channel for `osu://` scheme links --- osu.Game/IPC/OsuSchemeLinkIPCChannel.cs | 49 +++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 osu.Game/IPC/OsuSchemeLinkIPCChannel.cs diff --git a/osu.Game/IPC/OsuSchemeLinkIPCChannel.cs b/osu.Game/IPC/OsuSchemeLinkIPCChannel.cs new file mode 100644 index 0000000000..33318e329c --- /dev/null +++ b/osu.Game/IPC/OsuSchemeLinkIPCChannel.cs @@ -0,0 +1,49 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Diagnostics; +using System.Threading.Tasks; +using osu.Framework.Platform; +using osu.Game.Online; + +namespace osu.Game.IPC +{ + public class OsuSchemeLinkIPCChannel : IpcChannel + { + private readonly ILinkHandler? linkHandler; + + public OsuSchemeLinkIPCChannel(IIpcHost host, ILinkHandler? linkHandler = null) + : base(host) + { + this.linkHandler = linkHandler; + + MessageReceived += msg => + { + Debug.Assert(linkHandler != null); + linkHandler.HandleLink(msg.Link); + return null; + }; + } + + public async Task HandleLinkAsync(string url) + { + if (linkHandler == null) + { + await SendMessageAsync(new OsuSchemeLinkMessage(url)).ConfigureAwait(false); + return; + } + + linkHandler.HandleLink(url); + } + } + + public class OsuSchemeLinkMessage + { + public string Link { get; } + + public OsuSchemeLinkMessage(string link) + { + Link = link; + } + } +} From 330af7ec7460c0cc49ff7a13f7597c18459650f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 20 Jun 2022 21:21:16 +0200 Subject: [PATCH 085/211] Handle `osu://` scheme links via IPC in desktop game --- osu.Desktop/OsuGameDesktop.cs | 31 +++++++++++++-------- osu.Desktop/Program.cs | 42 ++++++++++++++++++++--------- osu.Game/IPC/IPCTimeoutException.cs | 15 +++++++++++ 3 files changed, 65 insertions(+), 23 deletions(-) create mode 100644 osu.Game/IPC/IPCTimeoutException.cs diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index 6713136343..873be052d7 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; using System.Diagnostics; @@ -22,23 +20,26 @@ using osu.Game.Updater; using osu.Desktop.Windows; using osu.Framework.Threading; using osu.Game.IO; +using osu.Game.IPC; namespace osu.Desktop { internal class OsuGameDesktop : OsuGame { - public OsuGameDesktop(string[] args = null) + private OsuSchemeLinkIPCChannel? osuSchemeLinkIPCChannel; + + public OsuGameDesktop(string[]? args = null) : base(args) { } - public override StableStorage GetStorageForStableInstall() + public override StableStorage? GetStorageForStableInstall() { try { if (Host is DesktopGameHost desktopHost) { - string stablePath = getStableInstallPath(); + string? stablePath = getStableInstallPath(); if (!string.IsNullOrEmpty(stablePath)) return new StableStorage(stablePath, desktopHost); } @@ -51,11 +52,11 @@ namespace osu.Desktop return null; } - private string getStableInstallPath() + private string? getStableInstallPath() { static bool checkExists(string p) => Directory.Exists(Path.Combine(p, "Songs")) || File.Exists(Path.Combine(p, "osu!.cfg")); - string stableInstallPath; + string? stableInstallPath; if (OperatingSystem.IsWindows()) { @@ -83,15 +84,15 @@ namespace osu.Desktop } [SupportedOSPlatform("windows")] - private string getStableInstallPathFromRegistry() + private string? getStableInstallPathFromRegistry() { - using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu")) + using (RegistryKey? key = Registry.ClassesRoot.OpenSubKey("osu")) return key?.OpenSubKey(@"shell\open\command")?.GetValue(string.Empty)?.ToString()?.Split('"')[1].Replace("osu!.exe", ""); } protected override UpdateManager CreateUpdateManager() { - string packageManaged = Environment.GetEnvironmentVariable("OSU_EXTERNAL_UPDATE_PROVIDER"); + string? packageManaged = Environment.GetEnvironmentVariable("OSU_EXTERNAL_UPDATE_PROVIDER"); if (!string.IsNullOrEmpty(packageManaged)) return new NoActionUpdateManager(); @@ -118,6 +119,8 @@ namespace osu.Desktop LoadComponentAsync(new GameplayWinKeyBlocker(), Add); LoadComponentAsync(new ElevatedPrivilegesChecker(), Add); + + osuSchemeLinkIPCChannel = new OsuSchemeLinkIPCChannel(Host, this); } public override void SetHost(GameHost host) @@ -135,7 +138,7 @@ namespace osu.Desktop } private readonly List importableFiles = new List(); - private ScheduledDelegate importSchedule; + private ScheduledDelegate? importSchedule; private void fileDrop(string[] filePaths) { @@ -168,5 +171,11 @@ namespace osu.Desktop Task.Factory.StartNew(() => Import(paths), TaskCreationOptions.LongRunning); } } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + osuSchemeLinkIPCChannel?.Dispose(); + } } } diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs index 4ba9cc6a90..7a5809e915 100644 --- a/osu.Desktop/Program.cs +++ b/osu.Desktop/Program.cs @@ -11,6 +11,7 @@ using osu.Framework; using osu.Framework.Development; using osu.Framework.Logging; using osu.Framework.Platform; +using osu.Game; using osu.Game.IPC; using osu.Game.Tournament; using Squirrel; @@ -65,19 +66,8 @@ namespace osu.Desktop { if (!host.IsPrimaryInstance) { - if (args.Length > 0 && args[0].Contains('.')) // easy way to check for a file import in args - { - var importer = new ArchiveImportIPCChannel(host); - - foreach (string file in args) - { - Console.WriteLine(@"Importing {0}", file); - if (!importer.ImportAsync(Path.GetFullPath(file, cwd)).Wait(3000)) - throw new TimeoutException(@"IPC took too long to send"); - } - + if (trySendIPCMessage(host, cwd, args)) return; - } // we want to allow multiple instances to be started when in debug. if (!DebugUtils.IsDebugBuild) @@ -108,6 +98,34 @@ namespace osu.Desktop } } + private static bool trySendIPCMessage(IIpcHost host, string cwd, string[] args) + { + if (args.Length == 1 && args[0].StartsWith(OsuGameBase.OSU_PROTOCOL, StringComparison.Ordinal)) + { + var osuSchemeLinkHandler = new OsuSchemeLinkIPCChannel(host); + if (!osuSchemeLinkHandler.HandleLinkAsync(args[0]).Wait(3000)) + throw new IPCTimeoutException(osuSchemeLinkHandler.GetType()); + + return true; + } + + if (args.Length > 0 && args[0].Contains('.')) // easy way to check for a file import in args + { + var importer = new ArchiveImportIPCChannel(host); + + foreach (string file in args) + { + Console.WriteLine(@"Importing {0}", file); + if (!importer.ImportAsync(Path.GetFullPath(file, cwd)).Wait(3000)) + throw new IPCTimeoutException(importer.GetType()); + } + + return true; + } + + return false; + } + [SupportedOSPlatform("windows")] private static void setupSquirrel() { diff --git a/osu.Game/IPC/IPCTimeoutException.cs b/osu.Game/IPC/IPCTimeoutException.cs new file mode 100644 index 0000000000..d820184468 --- /dev/null +++ b/osu.Game/IPC/IPCTimeoutException.cs @@ -0,0 +1,15 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; + +namespace osu.Game.IPC +{ + public class IPCTimeoutException : TimeoutException + { + public IPCTimeoutException(Type channelType) + : base($@"IPC took too long to send message via channel {channelType}") + { + } + } +} From 21d60231b6eecb087d5d10873e80aaf208115c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 20 Jun 2022 22:10:25 +0200 Subject: [PATCH 086/211] Add limited test coverage of `osu://` scheme link IPC flow --- .../TestSceneInterProcessCommunication.cs | 86 +++++++++++++++++++ osu.Game/Tests/Visual/OsuGameTestScene.cs | 2 +- 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs b/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs new file mode 100644 index 0000000000..f5af077696 --- /dev/null +++ b/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs @@ -0,0 +1,86 @@ +// 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; +using osu.Framework.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics.Containers; +using osu.Framework.Platform; +using osu.Framework.Testing; +using osu.Game.IPC; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; + +namespace osu.Game.Tests.Visual.Navigation +{ + [TestFixture] + [Ignore("This test cannot be run headless, as it requires the game host running the nested game to have IPC bound.")] + public class TestSceneInterProcessCommunication : OsuGameTestScene + { + private HeadlessGameHost ipcSenderHost = null!; + + private OsuSchemeLinkIPCChannel osuSchemeLinkIPCReceiver = null!; + private OsuSchemeLinkIPCChannel osuSchemeLinkIPCSender = null!; + + private const int requested_beatmap_set_id = 1; + + [Resolved] + private GameHost gameHost { get; set; } = null!; + + public override void SetUpSteps() + { + base.SetUpSteps(); + AddStep("set up request handling", () => + { + ((DummyAPIAccess)API).HandleRequest = request => + { + switch (request) + { + case GetBeatmapSetRequest gbr: + + var apiBeatmapSet = CreateAPIBeatmapSet(); + apiBeatmapSet.OnlineID = requested_beatmap_set_id; + apiBeatmapSet.Beatmaps = apiBeatmapSet.Beatmaps.Append(new APIBeatmap + { + DifficultyName = "Target difficulty", + OnlineID = 75, + }).ToArray(); + gbr.TriggerSuccess(apiBeatmapSet); + return true; + } + + return false; + }; + }); + AddStep("create IPC receiver channel", () => osuSchemeLinkIPCReceiver = new OsuSchemeLinkIPCChannel(gameHost, Game)); + AddStep("create IPC sender channel", () => + { + ipcSenderHost = new HeadlessGameHost(gameHost.Name, new HostOptions { BindIPC = true }); + osuSchemeLinkIPCSender = new OsuSchemeLinkIPCChannel(ipcSenderHost); + }); + } + + [Test] + public void TestOsuSchemeLinkIPCChannel() + { + AddStep("open beatmap via IPC", () => osuSchemeLinkIPCSender.HandleLinkAsync($@"osu://s/{requested_beatmap_set_id}").WaitSafely()); + AddUntilStep("beatmap overlay displayed", () => Game.ChildrenOfType().FirstOrDefault()?.State.Value == Visibility.Visible); + AddUntilStep("beatmap overlay showing content", () => Game.ChildrenOfType().FirstOrDefault()?.Header.BeatmapSet.Value.OnlineID == requested_beatmap_set_id); + } + + public override void TearDownSteps() + { + AddStep("dispose IPC receiver", () => osuSchemeLinkIPCReceiver.Dispose()); + AddStep("dispose IPC sender", () => + { + osuSchemeLinkIPCReceiver.Dispose(); + ipcSenderHost.Dispose(); + }); + base.TearDownSteps(); + } + } +} diff --git a/osu.Game/Tests/Visual/OsuGameTestScene.cs b/osu.Game/Tests/Visual/OsuGameTestScene.cs index df0bdb0a50..b9f6183869 100644 --- a/osu.Game/Tests/Visual/OsuGameTestScene.cs +++ b/osu.Game/Tests/Visual/OsuGameTestScene.cs @@ -75,7 +75,7 @@ namespace osu.Game.Tests.Visual } [TearDownSteps] - public void TearDownSteps() + public virtual void TearDownSteps() { if (DebugUtils.IsNUnitRunning && Game != null) { From 345ae7bbc3ec287f60d5a38fb2202d674aad98b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Jun 2022 00:46:52 +0200 Subject: [PATCH 087/211] Fix build errors after implicit NRT enable --- osu.Android/AndroidMouseSettings.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android/AndroidMouseSettings.cs b/osu.Android/AndroidMouseSettings.cs index 7dff929cd4..54b787fd17 100644 --- a/osu.Android/AndroidMouseSettings.cs +++ b/osu.Android/AndroidMouseSettings.cs @@ -20,11 +20,11 @@ namespace osu.Android protected override LocalisableString Header => MouseSettingsStrings.Mouse; - private Bindable handlerSensitivity; + private Bindable handlerSensitivity = null!; - private Bindable localSensitivity; + private Bindable localSensitivity = null!; - private Bindable relativeMode; + private Bindable relativeMode = null!; public AndroidMouseSettings(AndroidMouseHandler mouseHandler) { From 6a2646168334d55582a380860aaa6e61270e6f45 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 21 Jun 2022 12:05:28 +0900 Subject: [PATCH 088/211] Compare by reference in ControlPoint.Equals() --- osu.Game/Beatmaps/ControlPoints/ControlPoint.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs index b91d609849..56a432aec4 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs @@ -52,8 +52,12 @@ namespace osu.Game.Beatmaps.ControlPoints && Equals(otherControlPoint); public virtual bool Equals(ControlPoint? other) - => other != null - && Time == other.Time; + { + if (ReferenceEquals(other, null)) return false; + if (ReferenceEquals(other, this)) return true; + + return Time == other.Time; + } // ReSharper disable once NonReadonlyMemberInGetHashCode public override int GetHashCode() => Time.GetHashCode(); From 9763a583924d0a68d3c70e07a144d480f8bf9b01 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 21 Jun 2022 12:05:52 +0900 Subject: [PATCH 089/211] Change to use ReferenceEquals --- osu.Game/Screens/Edit/Timing/ControlPointTable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs index b6e3e91c98..b923957273 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.Edit.Timing { BackgroundFlow.Add(new RowBackground(group) { - Selected = group.Equals(selectedGroup?.Value), + Selected = ReferenceEquals(group, selectedGroup?.Value), Action = () => { selectedGroup.Value = group; From 93ce6fc98149a28ecc45de1a6dfba7be38fc6ec7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 21 Jun 2022 12:11:44 +0900 Subject: [PATCH 090/211] Remove redundant diff processing --- osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs index 01bc01bf5b..b4647c2b64 100644 --- a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs +++ b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs @@ -41,17 +41,12 @@ namespace osu.Game.Screens.Edit editorBeatmap.BeginChange(); processHitObjects(result, () => newBeatmap ??= readBeatmap(newState)); - processTimingPoints(result, () => newBeatmap ??= readBeatmap(newState)); + processTimingPoints(() => newBeatmap ??= readBeatmap(newState)); editorBeatmap.EndChange(); } - private void processTimingPoints(DiffResult result, Func getNewBeatmap) + private void processTimingPoints(Func getNewBeatmap) { - findChangedIndices(result, LegacyDecoder.Section.TimingPoints, out var removedIndices, out var addedIndices); - - if (removedIndices.Count == 0 && addedIndices.Count == 0) - return; - ControlPointInfo newControlPoints = EditorBeatmap.ConvertControlPoints(getNewBeatmap().ControlPointInfo); // Remove all groups from the current beatmap which don't have a corresponding equal group in the new beatmap. From b3e5642dfdd7298bebfb51d0a9b17211c940d80c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 21 Jun 2022 12:23:41 +0900 Subject: [PATCH 091/211] Use WaitingOnFrames instead --- osu.Game/Screens/Play/SpectatorPlayer.cs | 26 +++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Play/SpectatorPlayer.cs b/osu.Game/Screens/Play/SpectatorPlayer.cs index 72a7d3c8a1..797787b194 100644 --- a/osu.Game/Screens/Play/SpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SpectatorPlayer.cs @@ -45,6 +45,20 @@ namespace osu.Game.Screens.Play }); } + protected override void LoadComplete() + { + base.LoadComplete(); + + DrawableRuleset.FrameStableClock.WaitingOnFrames.BindValueChanged(waiting => + { + if (GameplayClockContainer is MasterGameplayClockContainer master) + { + if (master.UserPlaybackRate.Value > 1 && waiting.NewValue) + master.UserPlaybackRate.Value = 1; + } + }, true); + } + protected override void StartGameplay() { base.StartGameplay(); @@ -83,18 +97,6 @@ namespace osu.Game.Screens.Play SetGameplayStartTime(score.Replay.Frames[0].Time); } - protected override void Update() - { - base.Update(); - - if (HUDOverlay.PlayerSettingsOverlay.PlaybackSettings.UserPlaybackRate.Value > 1 - && score.Replay.Frames.Count > 0 - && DrawableRuleset.FrameStableClock.CurrentTime >= score.Replay.Frames[^1].Time) - { - HUDOverlay.PlayerSettingsOverlay.PlaybackSettings.UserPlaybackRate.Value = 1; - } - } - protected override Score CreateScore(IBeatmap beatmap) => score; protected override ResultsScreen CreateResults(ScoreInfo score) From 046b848bcd1c37a18b8ddf2141642a28668f5a6e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 21 Jun 2022 12:53:06 +0900 Subject: [PATCH 092/211] Split group selection to separate method --- osu.Game/Screens/Edit/Timing/ControlPointTable.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs index b923957273..b5c162ab11 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs @@ -44,7 +44,6 @@ namespace osu.Game.Screens.Edit.Timing { BackgroundFlow.Add(new RowBackground(group) { - Selected = ReferenceEquals(group, selectedGroup?.Value), Action = () => { selectedGroup.Value = group; @@ -55,6 +54,8 @@ namespace osu.Game.Screens.Edit.Timing Columns = createHeaders(); Content = value.Select(createContent).ToArray().ToRectangular(); + + updateSelectedGroup(); } } @@ -65,11 +66,17 @@ namespace osu.Game.Screens.Edit.Timing selectedGroup.BindValueChanged(group => { // TODO: This should scroll the selected row into view. - foreach (var b in BackgroundFlow) - b.Selected = ReferenceEquals(b.Item, group.NewValue); + updateSelectedGroup(); }, true); } + private void updateSelectedGroup() + { + // TODO: This should scroll the selected row into view. + foreach (var b in BackgroundFlow) + b.Selected = ReferenceEquals(b.Item, selectedGroup?.Value); + } + private TableColumn[] createHeaders() { var columns = new List From c61e90d7685a9709a74ebcf077b99f66da09a6a3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Jun 2022 13:07:50 +0900 Subject: [PATCH 093/211] Change editor seek-while-playing modifier to be BPM agnostic --- osu.Game/Screens/Edit/Editor.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index d0d4c0ba1e..7a9dae33b4 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -798,10 +798,11 @@ namespace osu.Game.Screens.Edit if (trackPlaying) { - // generally users are not looking to perform tiny seeks when the track is playing, - // so seeks should always be by one full beat, bypassing the beatDivisor. + // generally users are not looking to perform tiny seeks when the track is playing. // this multiplication undoes the division that will be applied in the underlying seek operation. - amount *= beatDivisor.Value; + // scale by BPM to keep the seek amount constant across all BPMs. + var timingPoint = editorBeatmap.ControlPointInfo.TimingPointAt(clock.CurrentTimeAccurate); + amount *= beatDivisor.Value * (timingPoint.BPM / 120); } if (direction < 1) From 10efb4bc6c0976866261c584aa10885162727bca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Jun 2022 14:08:30 +0900 Subject: [PATCH 094/211] Fix incorrect disposal in teardown steps --- .../Visual/Navigation/TestSceneInterProcessCommunication.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs b/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs index f5af077696..1c2b1fe37d 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs @@ -77,7 +77,7 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("dispose IPC receiver", () => osuSchemeLinkIPCReceiver.Dispose()); AddStep("dispose IPC sender", () => { - osuSchemeLinkIPCReceiver.Dispose(); + osuSchemeLinkIPCSender.Dispose(); ipcSenderHost.Dispose(); }); base.TearDownSteps(); From 88f450e1d0b3e0beb982f74cb1fa4936694098fb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Jun 2022 14:40:21 +0900 Subject: [PATCH 095/211] Remove accidental `nullable enable` spec --- .../Screens/Utility/SampleComponents/LatencyCursorContainer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs b/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs index 656aa6a8b3..aaf837eb60 100644 --- a/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs +++ b/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable enable - using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; From 42701757c340037116441a31b80c2aff9ff2a866 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Jun 2022 14:52:57 +0900 Subject: [PATCH 096/211] Fix latch reset logic --- osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index 33325951e5..cdfdc096d4 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Threading; using osu.Framework.Timing; using osu.Framework.Utils; using osu.Game.Beatmaps.ControlPoints; @@ -219,6 +220,8 @@ namespace osu.Game.Screens.Edit.Timing private readonly BindableInt interpolatedBpm = new BindableInt(); + private ScheduledDelegate latchDelegate; + protected override void LoadComplete() { base.LoadComplete(); @@ -266,12 +269,9 @@ namespace osu.Game.Screens.Edit.Timing using (swing.BeginDelayedSequence(350)) { swing.RotateTo(0, 1000, Easing.OutQuint); - swing.Delay(250).Schedule(() => - { - // prevent playing latch sound if metronome has started back up again - if (!isSwinging) - latch?.Play(); - }); + + using (swing.BeginDelayedSequence(250)) + latchDelegate = Schedule(() => latch?.Play()); } } } @@ -287,6 +287,9 @@ namespace osu.Game.Screens.Edit.Timing isSwinging = true; + latchDelegate?.Cancel(); + latchDelegate = null; + float currentAngle = swing.Rotation; float targetAngle = currentAngle > 0 ? -angle : angle; From 7b46d383186eb28e3bfd43cbfd2971fd37cb69a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Jun 2022 15:02:43 +0900 Subject: [PATCH 097/211] Move colour fade back to where it was --- osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index 5a6a478ca1..4aed7527af 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -266,7 +266,6 @@ namespace osu.Game.Screens.Edit.Timing if (BeatSyncSource.Clock?.IsRunning != true && isSwinging) { swing.ClearTransforms(true); - stick.FadeColour(overlayColourProvider.Colour2, 1000, Easing.OutQuint); isSwinging = false; @@ -284,6 +283,7 @@ namespace osu.Game.Screens.Edit.Timing using (swing.BeginDelayedSequence(350)) { swing.RotateTo(0, 1000, Easing.OutQuint); + stick.FadeColour(overlayColourProvider.Colour2, 1000, Easing.OutQuint); using (swing.BeginDelayedSequence(250)) latchDelegate = Schedule(() => latch?.Play()); From 16a9e1881503dbb10f8d4cf885c76ec1a46ef7b6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Jun 2022 15:02:53 +0900 Subject: [PATCH 098/211] Adjust timing of latch to be more in sync with visuals --- osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index 4aed7527af..62580ac527 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -280,12 +280,12 @@ namespace osu.Game.Screens.Edit.Timing return; } - using (swing.BeginDelayedSequence(350)) + using (BeginDelayedSequence(350)) { swing.RotateTo(0, 1000, Easing.OutQuint); stick.FadeColour(overlayColourProvider.Colour2, 1000, Easing.OutQuint); - using (swing.BeginDelayedSequence(250)) + using (BeginDelayedSequence(380)) latchDelegate = Schedule(() => latch?.Play()); } } From 82c4d855d493f6a36cba8b2c7436a1ecf92c059e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Jun 2022 15:05:17 +0900 Subject: [PATCH 099/211] Rename sample variable to be easier to discern from other fields --- .../Screens/Edit/Timing/MetronomeDisplay.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index 62580ac527..22a15a291e 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -37,12 +37,12 @@ namespace osu.Game.Screens.Edit.Timing private IAdjustableClock metronomeClock; - private Sample tick; - private Sample tickDownbeat; - private Sample latch; + private Sample sampleTick; + private Sample sampleTickDownbeat; + private Sample sampleLatch; [CanBeNull] - private ScheduledDelegate clunkDelegate; + private ScheduledDelegate tickPlaybackDelegate; [Resolved] private OverlayColourProvider overlayColourProvider { get; set; } @@ -57,9 +57,9 @@ namespace osu.Game.Screens.Edit.Timing [BackgroundDependencyLoader] private void load(AudioManager audio) { - tick = audio.Samples.Get(@"UI/metronome-tick"); - tickDownbeat = audio.Samples.Get(@"UI/metronome-tick-downbeat"); - latch = audio.Samples.Get(@"UI/metronome-latch"); + sampleTick = audio.Samples.Get(@"UI/metronome-tick"); + sampleTickDownbeat = audio.Samples.Get(@"UI/metronome-tick-downbeat"); + sampleLatch = audio.Samples.Get(@"UI/metronome-latch"); const float taper = 25; const float swing_vertical_offset = -23; @@ -269,14 +269,14 @@ namespace osu.Game.Screens.Edit.Timing isSwinging = false; - clunkDelegate?.Cancel(); - clunkDelegate = null; + tickPlaybackDelegate?.Cancel(); + tickPlaybackDelegate = null; // instantly latch if pendulum arm is close enough to center (to prevent awkward delayed playback of latch sound) if (Precision.AlmostEquals(swing.Rotation, 0, 1)) { swing.RotateTo(0); - latch?.Play(); + sampleLatch?.Play(); return; } @@ -286,7 +286,7 @@ namespace osu.Game.Screens.Edit.Timing stick.FadeColour(overlayColourProvider.Colour2, 1000, Easing.OutQuint); using (BeginDelayedSequence(380)) - latchDelegate = Schedule(() => latch?.Play()); + latchDelegate = Schedule(() => sampleLatch?.Play()); } } } @@ -316,12 +316,12 @@ namespace osu.Game.Screens.Edit.Timing { stick.FlashColour(overlayColourProvider.Content1, beatLength, Easing.OutQuint); - clunkDelegate = Schedule(() => + tickPlaybackDelegate = Schedule(() => { if (!EnableClicking) return; - var channel = beatIndex % timingPoint.TimeSignature.Numerator == 0 ? tickDownbeat?.GetChannel() : tick?.GetChannel(); + var channel = beatIndex % timingPoint.TimeSignature.Numerator == 0 ? sampleTickDownbeat?.GetChannel() : sampleTick?.GetChannel(); if (channel == null) return; From a40ad6f784aa5b16722017176e2c221b226b4908 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Jun 2022 15:07:35 +0900 Subject: [PATCH 100/211] Add slight transform when resetting arm from almost-zero --- osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index 22a15a291e..37fc38404f 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -275,7 +275,7 @@ namespace osu.Game.Screens.Edit.Timing // instantly latch if pendulum arm is close enough to center (to prevent awkward delayed playback of latch sound) if (Precision.AlmostEquals(swing.Rotation, 0, 1)) { - swing.RotateTo(0); + swing.RotateTo(0, 60, Easing.OutQuint); sampleLatch?.Play(); return; } From f74b4ac2771edbeee3eebae2148db8a0f8a18508 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Jun 2022 17:15:25 +0900 Subject: [PATCH 101/211] Fix blocking overhead when calling `WriteAsync` --- osu.Game/Database/RealmAccess.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 865a8b5021..d02f8fe6b2 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -385,11 +385,22 @@ namespace osu.Game.Database /// Write changes to realm asynchronously, guaranteeing order of execution. /// /// The work to run. - public async Task WriteAsync(Action action) + public Task WriteAsync(Action action) { - total_writes_async.Value++; - using (var realm = getRealmInstance()) - await realm.WriteAsync(() => action(realm)); + // Regardless of calling Realm.GetInstance of Realm.GetInstanceAsync, there is a blocking overhead on retrieval. + // Adding a forced Task.Run resolves this. + + return Task.Run(async () => + { + total_writes_async.Value++; + + // Not attempting to use Realm.GetInstanceAsync as there's seemingly no benefit to us (for now) and it adds complexity due to locking + // concerns in getRealmInstance(). On a quick check, it looks to be more suited to cases where realm is connecting to an online sync + // server, which we don't use. May want to report upstream or revisit in the future. + using (var realm = getRealmInstance()) + // ReSharper disable once AccessToDisposedClosure (WriteAsync should be marked as [InstantHandle]). + await realm.WriteAsync(() => action(realm)); + }); } /// From 043aa82a3195a9724256332e82b90c6d139493e3 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 21 Jun 2022 18:09:00 +0900 Subject: [PATCH 102/211] Add test --- .../TestSceneSliderFollowCircleInput.cs | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs new file mode 100644 index 0000000000..7a6e19575e --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs @@ -0,0 +1,120 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Screens; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Replays; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Replays; +using osu.Game.Rulesets.Replays; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; +using osu.Game.Screens.Play; +using osu.Game.Tests.Visual; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + [HeadlessTest] + public class TestSceneSliderFollowCircleInput : RateAdjustedBeatmapTestScene + { + private List? judgementResults; + private ScoreAccessibleReplayPlayer? currentPlayer; + + [Test] + public void TestMaximumDistanceTrackingWithoutMovement( + [Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)] + float circleSize, + [Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)] + double velocity) + { + const double time_slider_start = 1000; + + float circleRadius = OsuHitObject.OBJECT_RADIUS * (1.0f - 0.7f * (circleSize - 5) / 5) / 2; + float followCircleRadius = circleRadius * 1.2f; + + performTest(new Beatmap + { + HitObjects = + { + new Slider + { + StartTime = time_slider_start, + Position = new Vector2(0, 0), + DifficultyControlPoint = new DifficultyControlPoint { SliderVelocity = velocity }, + Path = new SliderPath(PathType.Linear, new[] + { + Vector2.Zero, + new Vector2(followCircleRadius, 0), + }, followCircleRadius), + }, + }, + BeatmapInfo = + { + Difficulty = new BeatmapDifficulty + { + CircleSize = circleSize, + SliderTickRate = 1 + }, + Ruleset = new OsuRuleset().RulesetInfo + }, + }, new List + { + new OsuReplayFrame { Position = new Vector2(-circleRadius + 1, 0), Actions = { OsuAction.LeftButton }, Time = time_slider_start }, + }); + + AddAssert("Tracking kept", assertMaxJudge); + } + + private bool assertMaxJudge() => judgementResults?.Any() == true && judgementResults.All(t => t.Type == t.Judgement.MaxResult); + + private void performTest(Beatmap beatmap, List frames) + { + AddStep("load player", () => + { + Beatmap.Value = CreateWorkingBeatmap(beatmap); + + var p = new ScoreAccessibleReplayPlayer(new Score { Replay = new Replay { Frames = frames } }); + + p.OnLoadComplete += _ => + { + p.ScoreProcessor.NewJudgement += result => + { + if (currentPlayer == p) judgementResults?.Add(result); + }; + }; + + LoadScreen(currentPlayer = p); + judgementResults = new List(); + }); + + AddUntilStep("Beatmap at 0", () => Beatmap.Value.Track.CurrentTime == 0); + AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen()); + AddUntilStep("Wait for completion", () => currentPlayer?.ScoreProcessor.HasCompleted.Value == true); + } + + private class ScoreAccessibleReplayPlayer : ReplayPlayer + { + public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; + + protected override bool PauseOnFocusLost => false; + + public ScoreAccessibleReplayPlayer(Score score) + : base(score, new PlayerConfiguration + { + AllowPause = false, + ShowResults = false, + }) + { + } + } + } +} From ede5ca31a1a40bda61922301f625997ca687ae48 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 21 Jun 2022 18:09:23 +0900 Subject: [PATCH 103/211] Always track final follow circle size --- osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs | 7 ------ .../Skinning/Default/SliderBall.cs | 25 ++++++++----------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs index 8a15d730cd..00009f4c3d 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs @@ -30,9 +30,6 @@ namespace osu.Game.Rulesets.Osu.Mods [SettingSource("Apply classic note lock", "Applies note lock to the full hit window.")] public Bindable ClassicNoteLock { get; } = new BindableBool(true); - [SettingSource("Use fixed slider follow circle hit area", "Makes the slider follow circle track its final size at all times.")] - public Bindable FixedFollowCircleHitArea { get; } = new BindableBool(true); - [SettingSource("Always play a slider's tail sample", "Always plays a slider's tail sample regardless of whether it was hit or not.")] public Bindable AlwaysPlayTailSample { get; } = new BindableBool(true); @@ -62,10 +59,6 @@ namespace osu.Game.Rulesets.Osu.Mods { switch (obj) { - case DrawableSlider slider: - slider.Ball.InputTracksVisualSize = !FixedFollowCircleHitArea.Value; - break; - case DrawableSliderHead head: head.TrackFollowCircle = !NoSliderHeadMovement.Value; break; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SliderBall.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SliderBall.cs index d2ea8f1660..389e9343e7 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SliderBall.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SliderBall.cs @@ -34,13 +34,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default set => ball.Colour = value; } - /// - /// Whether to track accurately to the visual size of this . - /// If false, tracking will be performed at the final scale at all times. - /// - public bool InputTracksVisualSize = true; - private readonly Drawable followCircle; + private readonly Drawable fullSizeFollowCircle; private readonly DrawableSlider drawableSlider; private readonly Drawable ball; @@ -62,6 +57,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default Alpha = 0, Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderFollowCircle), _ => new DefaultFollowCircle()), }, + fullSizeFollowCircle = new CircularContainer + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true + }, ball = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderBall), _ => new DefaultSliderBall()) { Anchor = Anchor.Centre, @@ -104,14 +106,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default tracking = value; - if (InputTracksVisualSize) - followCircle.ScaleTo(tracking ? 2.4f : 1f, 300, Easing.OutQuint); - else - { - // We need to always be tracking the final size, at both endpoints. For now, this is achieved by removing the scale duration. - followCircle.ScaleTo(tracking ? 2.4f : 1f); - } + fullSizeFollowCircle.Scale = new Vector2(tracking ? 2.4f : 1f); + followCircle.ScaleTo(tracking ? 2.4f : 1f, 300, Easing.OutQuint); followCircle.FadeTo(tracking ? 1f : 0, 300, Easing.OutQuint); } } @@ -170,7 +167,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default // in valid time range Time.Current >= drawableSlider.HitObject.StartTime && Time.Current < drawableSlider.HitObject.EndTime && // in valid position range - lastScreenSpaceMousePosition.HasValue && followCircle.ReceivePositionalInputAt(lastScreenSpaceMousePosition.Value) && + lastScreenSpaceMousePosition.HasValue && fullSizeFollowCircle.ReceivePositionalInputAt(lastScreenSpaceMousePosition.Value) && // valid action (actions?.Any(isValidTrackingAction) ?? false); From 2e3d8d7e5d347a45e6cf97476beb7444f82dd1fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Jun 2022 18:13:14 +0900 Subject: [PATCH 104/211] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index c82365d750..caea787e22 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index d820be4bdc..652dc2740f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index a8c59d676d..0c3c38f9f0 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From 73124d2b1fb09523ac8b16ea1d86c6cd1ef3cb1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Jun 2022 12:49:01 +0200 Subject: [PATCH 105/211] Encapsulate mod hotkey selection logic in strategy pattern --- .../UserInterface/TestSceneModColumn.cs | 2 +- .../Overlays/Mods/Input/IModHotkeyHandler.cs | 22 +++++++ .../Overlays/Mods/Input/ModHotkeyHandler.cs | 30 ++++++++++ .../Mods/Input/NoopModHotkeyHandler.cs | 17 ++++++ .../Mods/Input/SequentialModHotkeyHandler.cs | 58 +++++++++++++++++++ osu.Game/Overlays/Mods/ModColumn.cs | 21 +++---- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 13 ++--- .../Overlays/Mods/UserModSelectOverlay.cs | 10 +--- .../OnlinePlay/FreeModSelectOverlay.cs | 3 +- 9 files changed, 145 insertions(+), 31 deletions(-) create mode 100644 osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs create mode 100644 osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs create mode 100644 osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs create mode 100644 osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs index 50817bf804..f98f39d445 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs @@ -139,7 +139,7 @@ namespace osu.Game.Tests.Visual.UserInterface { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(30), - Child = column = new ModColumn(ModType.DifficultyReduction, true, new[] { Key.Q, Key.W, Key.E, Key.R, Key.T, Key.Y, Key.U, Key.I, Key.O, Key.P }) + Child = column = new ModColumn(ModType.DifficultyReduction, true) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs new file mode 100644 index 0000000000..aec16ff764 --- /dev/null +++ b/osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osuTK.Input; + +namespace osu.Game.Overlays.Mods.Input +{ + /// + /// Encapsulates strategies of handling mod hotkeys on the . + /// + public interface IModHotkeyHandler + { + /// + /// Attempt to handle a press of the supplied as a selection of one of the mods in . + /// + /// The key that was pressed by the user. + /// The list of currently available mods. + /// Whether the was handled as a mod selection/deselection. + bool HandleHotkeyPressed(Key hotkey, IEnumerable availableMods); + } +} diff --git a/osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs new file mode 100644 index 0000000000..22de557979 --- /dev/null +++ b/osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs @@ -0,0 +1,30 @@ +// 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.Mods; + +namespace osu.Game.Overlays.Mods.Input +{ + /// + /// Static factory class for s. + /// + public static class ModHotkeyHandler + { + /// + /// Creates an appropriate for the given . + /// + public static IModHotkeyHandler Create(ModType modType) + { + switch (modType) + { + case ModType.DifficultyReduction: + case ModType.DifficultyIncrease: + case ModType.Automation: + return SequentialModHotkeyHandler.Create(modType); + + default: + return new NoopModHotkeyHandler(); + } + } + } +} diff --git a/osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs new file mode 100644 index 0000000000..81152226da --- /dev/null +++ b/osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osuTK.Input; + +namespace osu.Game.Overlays.Mods.Input +{ + /// + /// A no-op implementation of . + /// Used when a column is not handling any hotkeys at all. + /// + public class NoopModHotkeyHandler : IModHotkeyHandler + { + public bool HandleHotkeyPressed(Key hotkey, IEnumerable availableMods) => false; + } +} diff --git a/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs new file mode 100644 index 0000000000..45cfa60fff --- /dev/null +++ b/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs @@ -0,0 +1,58 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Game.Rulesets.Mods; +using osuTK.Input; + +namespace osu.Game.Overlays.Mods.Input +{ + /// + /// This implementation of receives a sequence of s, + /// and maps the sequence of keys onto the items it is provided in . + /// In this case, particular mods are not bound to particular keys, the hotkeys are a byproduct of mod ordering. + /// + public class SequentialModHotkeyHandler : IModHotkeyHandler + { + public static SequentialModHotkeyHandler Create(ModType modType) + { + switch (modType) + { + case ModType.DifficultyReduction: + return new SequentialModHotkeyHandler(new[] { Key.Q, Key.W, Key.E, Key.R, Key.T, Key.Y, Key.U, Key.I, Key.O, Key.P }); + + case ModType.DifficultyIncrease: + return new SequentialModHotkeyHandler(new[] { Key.A, Key.S, Key.D, Key.F, Key.G, Key.H, Key.J, Key.K, Key.L }); + + case ModType.Automation: + return new SequentialModHotkeyHandler(new[] { Key.Z, Key.X, Key.C, Key.V, Key.B, Key.N, Key.M }); + + default: + throw new ArgumentOutOfRangeException(nameof(modType), modType, $"Cannot create {nameof(SequentialModHotkeyHandler)} for provided mod type"); + } + } + + private readonly Key[] toggleKeys; + + private SequentialModHotkeyHandler(Key[] keys) + { + toggleKeys = keys; + } + + public bool HandleHotkeyPressed(Key hotkey, IEnumerable availableMods) + { + int index = Array.IndexOf(toggleKeys, hotkey); + if (index < 0) + return false; + + var modState = availableMods.ElementAtOrDefault(index); + if (modState == null || modState.Filtered.Value) + return false; + + modState.Active.Toggle(); + return true; + } + } +} diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index 563e9a8d55..998437a0a0 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -21,10 +21,10 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; +using osu.Game.Overlays.Mods.Input; using osu.Game.Rulesets.Mods; using osuTK; using osuTK.Graphics; -using osuTK.Input; namespace osu.Game.Overlays.Mods { @@ -70,7 +70,7 @@ namespace osu.Game.Overlays.Mods protected virtual ModPanel CreateModPanel(ModState mod) => new ModPanel(mod); - private readonly Key[]? toggleKeys; + private readonly IModHotkeyHandler hotkeyHandler; private readonly TextFlowContainer headerText; private readonly Box headerBackground; @@ -86,10 +86,10 @@ namespace osu.Game.Overlays.Mods private const float header_height = 42; - public ModColumn(ModType modType, bool allowBulkSelection, Key[]? toggleKeys = null) + public ModColumn(ModType modType, bool allowBulkSelection) { ModType = modType; - this.toggleKeys = toggleKeys; + hotkeyHandler = ModHotkeyHandler.Create(modType); Width = 320; RelativeSizeAxes = Axes.Y; @@ -425,17 +425,10 @@ namespace osu.Game.Overlays.Mods protected override bool OnKeyDown(KeyDownEvent e) { - if (e.ControlPressed || e.AltPressed || e.SuperPressed) return false; - if (toggleKeys == null) return false; + if (e.ControlPressed || e.AltPressed || e.SuperPressed || e.Repeat) + return false; - int index = Array.IndexOf(toggleKeys, e.Key); - if (index < 0) return false; - - var modState = availableMods.ElementAtOrDefault(index); - if (modState == null || modState.Filtered.Value) return false; - - modState.Active.Toggle(); - return true; + return hotkeyHandler.HandleHotkeyPressed(e.Key, availableMods); } #endregion diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index ad02f079a5..811db393d6 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -21,7 +21,6 @@ using osu.Game.Localisation; using osu.Game.Rulesets.Mods; using osu.Game.Utils; using osuTK; -using osuTK.Input; namespace osu.Game.Overlays.Mods { @@ -68,7 +67,7 @@ namespace osu.Game.Overlays.Mods /// protected virtual bool AllowCustomisation => true; - protected virtual ModColumn CreateModColumn(ModType modType, Key[]? toggleKeys = null) => new ModColumn(modType, false, toggleKeys); + protected virtual ModColumn CreateModColumn(ModType modType) => new ModColumn(modType, false); protected virtual IReadOnlyList ComputeNewModsFromSelection(IReadOnlyList oldSelection, IReadOnlyList newSelection) => newSelection; @@ -160,9 +159,9 @@ namespace osu.Game.Overlays.Mods Padding = new MarginPadding { Bottom = 10 }, Children = new[] { - createModColumnContent(ModType.DifficultyReduction, new[] { Key.Q, Key.W, Key.E, Key.R, Key.T, Key.Y, Key.U, Key.I, Key.O, Key.P }), - createModColumnContent(ModType.DifficultyIncrease, new[] { Key.A, Key.S, Key.D, Key.F, Key.G, Key.H, Key.J, Key.K, Key.L }), - createModColumnContent(ModType.Automation, new[] { Key.Z, Key.X, Key.C, Key.V, Key.B, Key.N, Key.M }), + createModColumnContent(ModType.DifficultyReduction), + createModColumnContent(ModType.DifficultyIncrease), + createModColumnContent(ModType.Automation), createModColumnContent(ModType.Conversion), createModColumnContent(ModType.Fun) } @@ -264,9 +263,9 @@ namespace osu.Game.Overlays.Mods column.DeselectAll(); } - private ColumnDimContainer createModColumnContent(ModType modType, Key[]? toggleKeys = null) + private ColumnDimContainer createModColumnContent(ModType modType) { - var column = CreateModColumn(modType, toggleKeys).With(column => + var column = CreateModColumn(modType).With(column => { // spacing applied here rather than via `columnFlow.Spacing` to avoid uneven gaps when some of the columns are hidden. column.Margin = new MarginPadding { Right = 10 }; diff --git a/osu.Game/Overlays/Mods/UserModSelectOverlay.cs b/osu.Game/Overlays/Mods/UserModSelectOverlay.cs index b8f4b8a196..a292a50b72 100644 --- a/osu.Game/Overlays/Mods/UserModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/UserModSelectOverlay.cs @@ -1,14 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Collections.Generic; using System.Linq; -using JetBrains.Annotations; using osu.Game.Rulesets.Mods; using osu.Game.Utils; -using osuTK.Input; namespace osu.Game.Overlays.Mods { @@ -19,7 +15,7 @@ namespace osu.Game.Overlays.Mods { } - protected override ModColumn CreateModColumn(ModType modType, Key[] toggleKeys = null) => new UserModColumn(modType, false, toggleKeys); + protected override ModColumn CreateModColumn(ModType modType) => new UserModColumn(modType, false); protected override IReadOnlyList ComputeNewModsFromSelection(IReadOnlyList oldSelection, IReadOnlyList newSelection) { @@ -44,8 +40,8 @@ namespace osu.Game.Overlays.Mods private class UserModColumn : ModColumn { - public UserModColumn(ModType modType, bool allowBulkSelection, [CanBeNull] Key[] toggleKeys = null) - : base(modType, allowBulkSelection, toggleKeys) + public UserModColumn(ModType modType, bool allowBulkSelection) + : base(modType, allowBulkSelection) { } diff --git a/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs b/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs index c27b78642a..0f02692eda 100644 --- a/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; -using osuTK.Input; namespace osu.Game.Screens.OnlinePlay { @@ -33,7 +32,7 @@ namespace osu.Game.Screens.OnlinePlay IsValidMod = _ => true; } - protected override ModColumn CreateModColumn(ModType modType, Key[] toggleKeys = null) => new ModColumn(modType, true, toggleKeys); + protected override ModColumn CreateModColumn(ModType modType) => new ModColumn(modType, true); protected override IEnumerable CreateFooterButtons() => base.CreateFooterButtons().Prepend( new SelectAllModsButton(this) From 816fd338cb8cd4143242053d415783ccee08e4fd Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 21 Jun 2022 19:57:27 +0900 Subject: [PATCH 106/211] Fix typo --- osu.Game/Database/RealmAccess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index d02f8fe6b2..cf9109eb8b 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -387,7 +387,7 @@ namespace osu.Game.Database /// The work to run. public Task WriteAsync(Action action) { - // Regardless of calling Realm.GetInstance of Realm.GetInstanceAsync, there is a blocking overhead on retrieval. + // Regardless of calling Realm.GetInstance or Realm.GetInstanceAsync, there is a blocking overhead on retrieval. // Adding a forced Task.Run resolves this. return Task.Run(async () => From 5abd8a07d2ba2dcea0ab6e0c80b8cca8cc714a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Jun 2022 13:03:46 +0200 Subject: [PATCH 107/211] Add setting for changing mod select hotkey style --- osu.Game/Configuration/OsuConfigManager.cs | 3 +++ osu.Game/Localisation/UserInterfaceStrings.cs | 5 ++++ .../Mods/Input/ModSelectHotkeyStyle.cs | 27 +++++++++++++++++++ .../UserInterface/SongSelectSettings.cs | 7 +++++ 4 files changed, 42 insertions(+) create mode 100644 osu.Game/Overlays/Mods/Input/ModSelectHotkeyStyle.cs diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index a0e1d9ddc4..713166a9a0 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -20,6 +20,7 @@ using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.Localisation; using osu.Game.Overlays; +using osu.Game.Overlays.Mods.Input; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Filter; @@ -47,6 +48,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.SongSelectSortingMode, SortMode.Title); SetDefault(OsuSetting.RandomSelectAlgorithm, RandomSelectAlgorithm.RandomPermutation); + SetDefault(OsuSetting.ModSelectHotkeyStyle, ModSelectHotkeyStyle.Sequential); SetDefault(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2f, 1f); @@ -324,6 +326,7 @@ namespace osu.Game.Configuration SongSelectGroupingMode, SongSelectSortingMode, RandomSelectAlgorithm, + ModSelectHotkeyStyle, ShowFpsDisplay, ChatDisplayHeight, BeatmapListingCardSize, diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index 4e7af99ce9..a007f760d8 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -106,6 +106,11 @@ namespace osu.Game.Localisation /// public static LocalisableString RandomSelectionAlgorithm => new TranslatableString(getKey(@"random_selection_algorithm"), @"Random selection algorithm"); + /// + /// "Mod select hotkey style" + /// + public static LocalisableString ModSelectHotkeyStyle => new TranslatableString(getKey(@"mod_select_hotkey_style"), @"Mod select hotkey style"); + /// /// "no limit" /// diff --git a/osu.Game/Overlays/Mods/Input/ModSelectHotkeyStyle.cs b/osu.Game/Overlays/Mods/Input/ModSelectHotkeyStyle.cs new file mode 100644 index 0000000000..6375b37f8b --- /dev/null +++ b/osu.Game/Overlays/Mods/Input/ModSelectHotkeyStyle.cs @@ -0,0 +1,27 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Overlays.Mods.Input +{ + /// + /// The style of hotkey handling to use on the mod select screen. + /// + public enum ModSelectHotkeyStyle + { + /// + /// Each letter row on the keyboard controls one of the three first s. + /// Individual letters in a row trigger the mods in a sequential fashion. + /// Uses . + /// + Sequential, + + /// + /// Matches keybindings from stable 1:1. + /// One keybinding can toggle between what used to be s on stable, + /// and some mods in a column may not have any hotkeys at all. + /// + Classic + } +} diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index 8cec7bbb30..507e116723 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -11,6 +11,7 @@ using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; +using osu.Game.Overlays.Mods.Input; namespace osu.Game.Overlays.Settings.Sections.UserInterface { @@ -61,6 +62,12 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface { LabelText = UserInterfaceStrings.RandomSelectionAlgorithm, Current = config.GetBindable(OsuSetting.RandomSelectAlgorithm), + }, + new SettingsEnumDropdown + { + LabelText = UserInterfaceStrings.ModSelectHotkeyStyle, + Current = config.GetBindable(OsuSetting.ModSelectHotkeyStyle), + ClassicDefault = ModSelectHotkeyStyle.Classic } }; } From 658f5341c7b6b8717ac82fb5dea1a17129b6ebad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Jun 2022 13:10:22 +0200 Subject: [PATCH 108/211] Set up flow for switching between hotkey styles --- .../Visual/UserInterface/TestSceneModColumn.cs | 9 ++++++++- .../Mods/Input/ClassicModHotkeyHandler.cs | 16 ++++++++++++++++ osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs | 6 ++++-- osu.Game/Overlays/Mods/ModColumn.cs | 10 +++++++--- 4 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs index f98f39d445..d992f1aa05 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs @@ -9,9 +9,11 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; +using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osu.Game.Overlays.Mods; +using osu.Game.Overlays.Mods.Input; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Utils; @@ -25,6 +27,9 @@ namespace osu.Game.Tests.Visual.UserInterface [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); + [Resolved] + private OsuConfigManager configManager { get; set; } = null!; + [TestCase(ModType.DifficultyReduction)] [TestCase(ModType.DifficultyIncrease)] [TestCase(ModType.Conversion)] @@ -132,8 +137,10 @@ namespace osu.Game.Tests.Visual.UserInterface } [Test] - public void TestKeyboardSelection() + public void TestSequentialKeyboardSelection() { + AddStep("set sequential hotkey mode", () => configManager.SetValue(OsuSetting.ModSelectHotkeyStyle, ModSelectHotkeyStyle.Sequential)); + ModColumn column = null!; AddStep("create content", () => Child = new Container { diff --git a/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs new file mode 100644 index 0000000000..1dd732b79c --- /dev/null +++ b/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osuTK.Input; + +namespace osu.Game.Overlays.Mods.Input +{ + /// + /// Uses bindings from stable 1:1. + /// + public class ClassicModHotkeyHandler : IModHotkeyHandler + { + public bool HandleHotkeyPressed(Key hotkey, IEnumerable availableMods) => false; // TODO + } +} diff --git a/osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs index 22de557979..5c46b2065f 100644 --- a/osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs @@ -13,14 +13,16 @@ namespace osu.Game.Overlays.Mods.Input /// /// Creates an appropriate for the given . /// - public static IModHotkeyHandler Create(ModType modType) + public static IModHotkeyHandler Create(ModType modType, ModSelectHotkeyStyle style) { switch (modType) { case ModType.DifficultyReduction: case ModType.DifficultyIncrease: case ModType.Automation: - return SequentialModHotkeyHandler.Create(modType); + return style == ModSelectHotkeyStyle.Sequential + ? (IModHotkeyHandler)SequentialModHotkeyHandler.Create(modType) + : new ClassicModHotkeyHandler(); default: return new NoopModHotkeyHandler(); diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index 998437a0a0..cf3d354d47 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -17,6 +17,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -70,7 +71,8 @@ namespace osu.Game.Overlays.Mods protected virtual ModPanel CreateModPanel(ModState mod) => new ModPanel(mod); - private readonly IModHotkeyHandler hotkeyHandler; + private Bindable hotkeyStyle = null!; + private IModHotkeyHandler hotkeyHandler = null!; private readonly TextFlowContainer headerText; private readonly Box headerBackground; @@ -89,7 +91,6 @@ namespace osu.Game.Overlays.Mods public ModColumn(ModType modType, bool allowBulkSelection) { ModType = modType; - hotkeyHandler = ModHotkeyHandler.Create(modType); Width = 320; RelativeSizeAxes = Axes.Y; @@ -231,7 +232,7 @@ namespace osu.Game.Overlays.Mods } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider, OsuColour colours) + private void load(OverlayColourProvider colourProvider, OsuColour colours, OsuConfigManager configManager) { headerBackground.Colour = accentColour = colours.ForModType(ModType); @@ -243,6 +244,8 @@ namespace osu.Game.Overlays.Mods contentContainer.BorderColour = ColourInfo.GradientVertical(colourProvider.Background4, colourProvider.Background3); contentBackground.Colour = colourProvider.Background4; + + hotkeyStyle = configManager.GetBindable(OsuSetting.ModSelectHotkeyStyle); } protected override void LoadComplete() @@ -250,6 +253,7 @@ namespace osu.Game.Overlays.Mods base.LoadComplete(); toggleAllCheckbox?.Current.BindValueChanged(_ => updateToggleAllText(), true); + hotkeyStyle.BindValueChanged(val => hotkeyHandler = ModHotkeyHandler.Create(ModType, val.NewValue), true); asyncLoadPanels(); } From 143c8e8da679b156868c40d7b72ffca2b011977b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Jun 2022 13:33:33 +0200 Subject: [PATCH 109/211] Add test scene for desired classic selection behaviour --- .../UserInterface/TestSceneModColumn.cs | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs index d992f1aa05..25e99ac24b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs @@ -178,6 +178,56 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("clear filter", () => setFilter(null)); } + [Test] + public void TestClassicKeyboardSelection() + { + AddStep("set classic hotkey mode", () => configManager.SetValue(OsuSetting.ModSelectHotkeyStyle, ModSelectHotkeyStyle.Classic)); + + ModColumn column = null!; + AddStep("create content", () => Child = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(30), + Child = column = new ModColumn(ModType.DifficultyIncrease, true) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AvailableMods = getExampleModsFor(ModType.DifficultyIncrease) + } + }); + + AddUntilStep("wait for panel load", () => column.IsLoaded && column.ItemsLoaded); + + AddStep("press A", () => InputManager.Key(Key.A)); + AddAssert("HR panel selected", () => this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "HR").Active.Value); + + AddStep("press A again", () => InputManager.Key(Key.A)); + AddAssert("HR panel deselected", () => !this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "HR").Active.Value); + + AddStep("press D", () => InputManager.Key(Key.D)); + AddAssert("DT panel selected", () => this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "DT").Active.Value); + + AddStep("press D again", () => InputManager.Key(Key.D)); + AddAssert("DT panel deselected", () => !this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "DT").Active.Value); + AddAssert("NC panel selected", () => this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "NC").Active.Value); + + AddStep("press D again", () => InputManager.Key(Key.D)); + AddAssert("DT panel deselected", () => !this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "DT").Active.Value); + AddAssert("NC panel deselected", () => !this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "NC").Active.Value); + + AddStep("press Shift-D", () => + { + InputManager.PressKey(Key.ShiftLeft); + InputManager.Key(Key.D); + InputManager.ReleaseKey(Key.ShiftLeft); + }); + AddAssert("DT panel deselected", () => !this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "DT").Active.Value); + AddAssert("NC panel selected", () => this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "NC").Active.Value); + + AddStep("press J", () => InputManager.Key(Key.J)); + AddAssert("no change", () => this.ChildrenOfType().Single(panel => panel.Active.Value).Mod.Acronym == "NC"); + } + private void setFilter(Func? filter) { foreach (var modState in this.ChildrenOfType().Single().AvailableMods) From 234120ff43ec16c09f394067b8e7c5d67330135b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Jun 2022 13:37:17 +0200 Subject: [PATCH 110/211] Forward entire event to `IModHotkeyHandler` Required for shift handling in the classic implementation. --- .../Overlays/Mods/Input/ClassicModHotkeyHandler.cs | 4 ++-- osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs | 10 +++++----- osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs | 4 ++-- .../Overlays/Mods/Input/SequentialModHotkeyHandler.cs | 5 +++-- osu.Game/Overlays/Mods/ModColumn.cs | 2 +- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs index 1dd732b79c..e22ad13451 100644 --- a/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using osuTK.Input; +using osu.Framework.Input.Events; namespace osu.Game.Overlays.Mods.Input { @@ -11,6 +11,6 @@ namespace osu.Game.Overlays.Mods.Input /// public class ClassicModHotkeyHandler : IModHotkeyHandler { - public bool HandleHotkeyPressed(Key hotkey, IEnumerable availableMods) => false; // TODO + public bool HandleHotkeyPressed(KeyDownEvent e, IEnumerable availableMods) => false; // TODO } } diff --git a/osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs index aec16ff764..d2cc0e84d2 100644 --- a/osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/IModHotkeyHandler.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using osuTK.Input; +using osu.Framework.Input.Events; namespace osu.Game.Overlays.Mods.Input { @@ -12,11 +12,11 @@ namespace osu.Game.Overlays.Mods.Input public interface IModHotkeyHandler { /// - /// Attempt to handle a press of the supplied as a selection of one of the mods in . + /// Attempt to handle the supplied as a selection of one of the mods in . /// - /// The key that was pressed by the user. + /// The event representing the user's keypress. /// The list of currently available mods. - /// Whether the was handled as a mod selection/deselection. - bool HandleHotkeyPressed(Key hotkey, IEnumerable availableMods); + /// Whether the supplied event was handled as a mod selection/deselection. + bool HandleHotkeyPressed(KeyDownEvent e, IEnumerable availableMods); } } diff --git a/osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs index 81152226da..3f7a6298a1 100644 --- a/osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/NoopModHotkeyHandler.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using osuTK.Input; +using osu.Framework.Input.Events; namespace osu.Game.Overlays.Mods.Input { @@ -12,6 +12,6 @@ namespace osu.Game.Overlays.Mods.Input /// public class NoopModHotkeyHandler : IModHotkeyHandler { - public bool HandleHotkeyPressed(Key hotkey, IEnumerable availableMods) => false; + public bool HandleHotkeyPressed(KeyDownEvent e, IEnumerable availableMods) => false; } } diff --git a/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs index 45cfa60fff..e6717053e1 100644 --- a/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using osu.Framework.Input.Events; using osu.Game.Rulesets.Mods; using osuTK.Input; @@ -41,9 +42,9 @@ namespace osu.Game.Overlays.Mods.Input toggleKeys = keys; } - public bool HandleHotkeyPressed(Key hotkey, IEnumerable availableMods) + public bool HandleHotkeyPressed(KeyDownEvent e, IEnumerable availableMods) { - int index = Array.IndexOf(toggleKeys, hotkey); + int index = Array.IndexOf(toggleKeys, e.Key); if (index < 0) return false; diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index cf3d354d47..1fef7257b5 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -432,7 +432,7 @@ namespace osu.Game.Overlays.Mods if (e.ControlPressed || e.AltPressed || e.SuperPressed || e.Repeat) return false; - return hotkeyHandler.HandleHotkeyPressed(e.Key, availableMods); + return hotkeyHandler.HandleHotkeyPressed(e, availableMods); } #endregion From 7b7b8c1892e36a9d2dda89c95e69d1f6d09ed4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Jun 2022 14:24:30 +0200 Subject: [PATCH 111/211] Implement behaviour for classic selection style --- .../Mods/Input/ClassicModHotkeyHandler.cs | 66 ++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs index e22ad13451..0faf509136 100644 --- a/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs @@ -1,8 +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 System; using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; using osu.Framework.Input.Events; +using osu.Game.Rulesets.Mods; +using osuTK.Input; namespace osu.Game.Overlays.Mods.Input { @@ -11,6 +16,65 @@ namespace osu.Game.Overlays.Mods.Input /// public class ClassicModHotkeyHandler : IModHotkeyHandler { - public bool HandleHotkeyPressed(KeyDownEvent e, IEnumerable availableMods) => false; // TODO + private static readonly Dictionary mod_type_lookup = new Dictionary + { + [Key.Q] = new[] { typeof(ModEasy) }, + [Key.W] = new[] { typeof(ModNoFail) }, + [Key.E] = new[] { typeof(ModHalfTime) }, + [Key.A] = new[] { typeof(ModHardRock) }, + [Key.S] = new[] { typeof(ModSuddenDeath), typeof(ModPerfect) }, + [Key.D] = new[] { typeof(ModDoubleTime), typeof(ModNightcore) }, + [Key.F] = new[] { typeof(ModHidden) }, + [Key.G] = new[] { typeof(ModFlashlight) }, + [Key.Z] = new[] { typeof(ModRelax) }, + [Key.V] = new[] { typeof(ModAutoplay), typeof(ModCinema) } + }; + + public bool HandleHotkeyPressed(KeyDownEvent e, IEnumerable availableMods) + { + if (!mod_type_lookup.TryGetValue(e.Key, out var typesToMatch)) + return false; + + var matchingMods = availableMods.Where(modState => matches(modState, typesToMatch)).ToArray(); + + if (matchingMods.Length == 0) + return false; + + if (matchingMods.Length == 1) + { + matchingMods.Single().Active.Toggle(); + return true; + } + + // we're assuming that only one mod from the group can be active at a time. + // this is mostly ensured by `IncompatibleMods` definitions, but let's make sure just in case. + Debug.Assert(matchingMods.Count(modState => modState.Active.Value) <= 1); + int currentSelectedIndex = Array.FindIndex(matchingMods, modState => modState.Active.Value); + + // `FindIndex` will return -1 if it doesn't find the item. + // this is convenient in the forward direction, since if we add 1 then we'll end up at the first item, + // but less so in the backwards direction. + // for convenience, detect this situation and set the index to one index past the last item. + // this makes it so that if we subtract 1 then we'll end up at the last item again. + if (currentSelectedIndex < 0 && e.ShiftPressed) + currentSelectedIndex = matchingMods.Length; + + int indexToSelect = e.ShiftPressed ? currentSelectedIndex - 1 : currentSelectedIndex + 1; + + // `currentSelectedIndex` and `indexToSelect` can both be equal to -1 or `matchingMods.Length`. + // if the former is beyond array range, it means nothing was previously selected and so there's nothing to deselect. + // if the latter is beyond array range, it means that either the previous selection was first and we're going backwards, + // or it was last and we're going forwards. + // in either case there is nothing to select. + if (currentSelectedIndex >= 0 && currentSelectedIndex <= matchingMods.Length - 1) + matchingMods[currentSelectedIndex].Active.Value = false; + if (indexToSelect >= 0 && indexToSelect <= matchingMods.Length - 1) + matchingMods[indexToSelect].Active.Value = true; + + return true; + } + + private static bool matches(ModState modState, Type[] typesToMatch) + => typesToMatch.Any(typeToMatch => typeToMatch.IsInstanceOfType(modState.Mod)); } } From da1814e7c3bcc8beff26ec0de471a0ca19106a71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Jun 2022 14:48:41 +0200 Subject: [PATCH 112/211] Restructure everything to fix free mod overlay issue --- .../UserInterface/TestSceneModColumn.cs | 55 +++++++++++++++++-- .../Mods/Input/ClassicModHotkeyHandler.cs | 22 +++++++- .../Overlays/Mods/Input/ModHotkeyHandler.cs | 32 ----------- osu.Game/Overlays/Mods/ModColumn.cs | 33 +++++++++-- .../Overlays/Mods/UserModSelectOverlay.cs | 4 +- 5 files changed, 101 insertions(+), 45 deletions(-) delete mode 100644 osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs index 25e99ac24b..ec3c5b6ac6 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs @@ -179,7 +179,7 @@ namespace osu.Game.Tests.Visual.UserInterface } [Test] - public void TestClassicKeyboardSelection() + public void TestClassicKeyboardExclusiveSelection() { AddStep("set classic hotkey mode", () => configManager.SetValue(OsuSetting.ModSelectHotkeyStyle, ModSelectHotkeyStyle.Classic)); @@ -188,7 +188,7 @@ namespace osu.Game.Tests.Visual.UserInterface { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(30), - Child = column = new ModColumn(ModType.DifficultyIncrease, true) + Child = column = new ModColumn(ModType.DifficultyIncrease, false) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -228,6 +228,53 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("no change", () => this.ChildrenOfType().Single(panel => panel.Active.Value).Mod.Acronym == "NC"); } + [Test] + public void TestClassicKeyboardIncompatibleSelection() + { + AddStep("set classic hotkey mode", () => configManager.SetValue(OsuSetting.ModSelectHotkeyStyle, ModSelectHotkeyStyle.Classic)); + + ModColumn column = null!; + AddStep("create content", () => Child = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(30), + Child = column = new ModColumn(ModType.DifficultyIncrease, true) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AvailableMods = getExampleModsFor(ModType.DifficultyIncrease) + } + }); + + AddUntilStep("wait for panel load", () => column.IsLoaded && column.ItemsLoaded); + + AddStep("press A", () => InputManager.Key(Key.A)); + AddAssert("HR panel selected", () => this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "HR").Active.Value); + + AddStep("press A again", () => InputManager.Key(Key.A)); + AddAssert("HR panel deselected", () => !this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "HR").Active.Value); + + AddStep("press D", () => InputManager.Key(Key.D)); + AddAssert("DT panel selected", () => this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "DT").Active.Value); + AddAssert("NC panel selected", () => this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "NC").Active.Value); + + AddStep("press D again", () => InputManager.Key(Key.D)); + AddAssert("DT panel deselected", () => !this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "DT").Active.Value); + AddAssert("NC panel deselected", () => !this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "NC").Active.Value); + + AddStep("press Shift-D", () => + { + InputManager.PressKey(Key.ShiftLeft); + InputManager.Key(Key.D); + InputManager.ReleaseKey(Key.ShiftLeft); + }); + AddAssert("DT panel selected", () => this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "DT").Active.Value); + AddAssert("NC panel selected", () => this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "NC").Active.Value); + + AddStep("press J", () => InputManager.Key(Key.J)); + AddAssert("no change", () => this.ChildrenOfType().Count(panel => panel.Active.Value) == 2); + } + private void setFilter(Func? filter) { foreach (var modState in this.ChildrenOfType().Single().AvailableMods) @@ -238,8 +285,8 @@ namespace osu.Game.Tests.Visual.UserInterface { public new bool SelectionAnimationRunning => base.SelectionAnimationRunning; - public TestModColumn(ModType modType, bool allowBulkSelection) - : base(modType, allowBulkSelection) + public TestModColumn(ModType modType, bool allowIncompatibleSelection) + : base(modType, allowIncompatibleSelection) { } } diff --git a/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs index 0faf509136..33d86cbdaa 100644 --- a/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs @@ -30,6 +30,13 @@ namespace osu.Game.Overlays.Mods.Input [Key.V] = new[] { typeof(ModAutoplay), typeof(ModCinema) } }; + private readonly bool allowIncompatibleSelection; + + public ClassicModHotkeyHandler(bool allowIncompatibleSelection) + { + this.allowIncompatibleSelection = allowIncompatibleSelection; + } + public bool HandleHotkeyPressed(KeyDownEvent e, IEnumerable availableMods) { if (!mod_type_lookup.TryGetValue(e.Key, out var typesToMatch)) @@ -46,8 +53,19 @@ namespace osu.Game.Overlays.Mods.Input return true; } - // we're assuming that only one mod from the group can be active at a time. - // this is mostly ensured by `IncompatibleMods` definitions, but let's make sure just in case. + if (allowIncompatibleSelection) + { + // easier path - multiple incompatible mods can be active at a time. + // this is used in the free mod select overlay. + // in this case, just toggle everything. + bool anyActive = matchingMods.Any(mod => mod.Active.Value); + foreach (var mod in matchingMods) + mod.Active.Value = !anyActive; + return true; + } + + // we now know there are multiple possible mods to handle, and only one of them can be active at a time. + // let's make sure of this just in case. Debug.Assert(matchingMods.Count(modState => modState.Active.Value) <= 1); int currentSelectedIndex = Array.FindIndex(matchingMods, modState => modState.Active.Value); diff --git a/osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs deleted file mode 100644 index 5c46b2065f..0000000000 --- a/osu.Game/Overlays/Mods/Input/ModHotkeyHandler.cs +++ /dev/null @@ -1,32 +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.Mods; - -namespace osu.Game.Overlays.Mods.Input -{ - /// - /// Static factory class for s. - /// - public static class ModHotkeyHandler - { - /// - /// Creates an appropriate for the given . - /// - public static IModHotkeyHandler Create(ModType modType, ModSelectHotkeyStyle style) - { - switch (modType) - { - case ModType.DifficultyReduction: - case ModType.DifficultyIncrease: - case ModType.Automation: - return style == ModSelectHotkeyStyle.Sequential - ? (IModHotkeyHandler)SequentialModHotkeyHandler.Create(modType) - : new ClassicModHotkeyHandler(); - - default: - return new NoopModHotkeyHandler(); - } - } - } -} diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index 1fef7257b5..f8f6b814ca 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -71,8 +71,7 @@ namespace osu.Game.Overlays.Mods protected virtual ModPanel CreateModPanel(ModState mod) => new ModPanel(mod); - private Bindable hotkeyStyle = null!; - private IModHotkeyHandler hotkeyHandler = null!; + private readonly bool allowIncompatibleSelection; private readonly TextFlowContainer headerText; private readonly Box headerBackground; @@ -83,14 +82,18 @@ namespace osu.Game.Overlays.Mods private Colour4 accentColour; + private Bindable hotkeyStyle = null!; + private IModHotkeyHandler hotkeyHandler = null!; + private Task? latestLoadTask; internal bool ItemsLoaded => latestLoadTask == null; private const float header_height = 42; - public ModColumn(ModType modType, bool allowBulkSelection) + public ModColumn(ModType modType, bool allowIncompatibleSelection) { ModType = modType; + this.allowIncompatibleSelection = allowIncompatibleSelection; Width = 320; RelativeSizeAxes = Axes.Y; @@ -198,7 +201,7 @@ namespace osu.Game.Overlays.Mods createHeaderText(); - if (allowBulkSelection) + if (allowIncompatibleSelection) { controlContainer.Height = 35; controlContainer.Add(toggleAllCheckbox = new ToggleAllCheckbox(this) @@ -253,7 +256,7 @@ namespace osu.Game.Overlays.Mods base.LoadComplete(); toggleAllCheckbox?.Current.BindValueChanged(_ => updateToggleAllText(), true); - hotkeyStyle.BindValueChanged(val => hotkeyHandler = ModHotkeyHandler.Create(ModType, val.NewValue), true); + hotkeyStyle.BindValueChanged(val => hotkeyHandler = CreateHotkeyHandler(val.NewValue), true); asyncLoadPanels(); } @@ -427,6 +430,26 @@ namespace osu.Game.Overlays.Mods #region Keyboard selection support + /// + /// Creates an appropriate for this column's and + /// the supplied . + /// + protected virtual IModHotkeyHandler CreateHotkeyHandler(ModSelectHotkeyStyle hotkeyStyle) + { + switch (ModType) + { + case ModType.DifficultyReduction: + case ModType.DifficultyIncrease: + case ModType.Automation: + return hotkeyStyle == ModSelectHotkeyStyle.Sequential + ? (IModHotkeyHandler)SequentialModHotkeyHandler.Create(ModType) + : new ClassicModHotkeyHandler(allowIncompatibleSelection); + + default: + return new NoopModHotkeyHandler(); + } + } + protected override bool OnKeyDown(KeyDownEvent e) { if (e.ControlPressed || e.AltPressed || e.SuperPressed || e.Repeat) diff --git a/osu.Game/Overlays/Mods/UserModSelectOverlay.cs b/osu.Game/Overlays/Mods/UserModSelectOverlay.cs index a292a50b72..1090306c5b 100644 --- a/osu.Game/Overlays/Mods/UserModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/UserModSelectOverlay.cs @@ -40,8 +40,8 @@ namespace osu.Game.Overlays.Mods private class UserModColumn : ModColumn { - public UserModColumn(ModType modType, bool allowBulkSelection) - : base(modType, allowBulkSelection) + public UserModColumn(ModType modType, bool allowIncompatibleSelection) + : base(modType, allowIncompatibleSelection) { } From a996325e19bf5496994802e0c8d88c081b164e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Jun 2022 15:00:39 +0200 Subject: [PATCH 113/211] Add test coverage for filter handling in classic style --- .../Visual/UserInterface/TestSceneModColumn.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs index ec3c5b6ac6..3765bc2ca0 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs @@ -226,6 +226,11 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("press J", () => InputManager.Key(Key.J)); AddAssert("no change", () => this.ChildrenOfType().Single(panel => panel.Active.Value).Mod.Acronym == "NC"); + + AddStep("filter everything but NC", () => setFilter(mod => mod.Acronym == "NC")); + + AddStep("press A", () => InputManager.Key(Key.A)); + AddAssert("no change", () => this.ChildrenOfType().Single(panel => panel.Active.Value).Mod.Acronym == "NC"); } [Test] @@ -273,6 +278,11 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("press J", () => InputManager.Key(Key.J)); AddAssert("no change", () => this.ChildrenOfType().Count(panel => panel.Active.Value) == 2); + + AddStep("filter everything but NC", () => setFilter(mod => mod.Acronym == "NC")); + + AddStep("press A", () => InputManager.Key(Key.A)); + AddAssert("no change", () => this.ChildrenOfType().Count(panel => panel.Active.Value) == 2); } private void setFilter(Func? filter) From 9e5cc89edbcef90f2804e6a0eb163445b08f07a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Jun 2022 15:01:33 +0200 Subject: [PATCH 114/211] Fix classic hotkeys toggling filtered mods --- osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs index 33d86cbdaa..4f3c18fc43 100644 --- a/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/ClassicModHotkeyHandler.cs @@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Mods.Input if (!mod_type_lookup.TryGetValue(e.Key, out var typesToMatch)) return false; - var matchingMods = availableMods.Where(modState => matches(modState, typesToMatch)).ToArray(); + var matchingMods = availableMods.Where(modState => matches(modState, typesToMatch) && !modState.Filtered.Value).ToArray(); if (matchingMods.Length == 0) return false; From a9f6eb0293fd8fcc018f4ff2d29dba10f24bc117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Jun 2022 15:18:37 +0200 Subject: [PATCH 115/211] Add test coverage for new intended behaviour of sequential hotkey style --- osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs index 3765bc2ca0..72cddc0ad2 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs @@ -165,9 +165,12 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("set filter to NF", () => setFilter(mod => mod.Acronym == "NF")); AddStep("press W", () => InputManager.Key(Key.W)); + AddAssert("NF panel not selected", () => !this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "NF").Active.Value); + + AddStep("press Q", () => InputManager.Key(Key.Q)); AddAssert("NF panel selected", () => this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "NF").Active.Value); - AddStep("press W again", () => InputManager.Key(Key.W)); + AddStep("press Q again", () => InputManager.Key(Key.Q)); AddAssert("NF panel deselected", () => !this.ChildrenOfType().Single(panel => panel.Mod.Acronym == "NF").Active.Value); AddStep("filter out everything", () => setFilter(_ => false)); From f564ed589fdac206748c43000d98b2c918f1ae78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Jun 2022 15:19:41 +0200 Subject: [PATCH 116/211] Alter sequential hotkey style to always use visible index Previous behaviour was once mentioned off-hand as unintuitive. --- osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs b/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs index e6717053e1..dedb556304 100644 --- a/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs +++ b/osu.Game/Overlays/Mods/Input/SequentialModHotkeyHandler.cs @@ -48,8 +48,8 @@ namespace osu.Game.Overlays.Mods.Input if (index < 0) return false; - var modState = availableMods.ElementAtOrDefault(index); - if (modState == null || modState.Filtered.Value) + var modState = availableMods.Where(modState => !modState.Filtered.Value).ElementAtOrDefault(index); + if (modState == null) return false; modState.Active.Toggle(); From 7013909322687424052ffe6562a0b26d4ca62a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 21 Jun 2022 16:43:04 +0200 Subject: [PATCH 117/211] Remove unnecessary `protected virtual` --- osu.Game/Overlays/Mods/ModColumn.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index f8f6b814ca..c51e6baa0d 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -256,7 +256,7 @@ namespace osu.Game.Overlays.Mods base.LoadComplete(); toggleAllCheckbox?.Current.BindValueChanged(_ => updateToggleAllText(), true); - hotkeyStyle.BindValueChanged(val => hotkeyHandler = CreateHotkeyHandler(val.NewValue), true); + hotkeyStyle.BindValueChanged(val => hotkeyHandler = createHotkeyHandler(val.NewValue), true); asyncLoadPanels(); } @@ -434,7 +434,7 @@ namespace osu.Game.Overlays.Mods /// Creates an appropriate for this column's and /// the supplied . /// - protected virtual IModHotkeyHandler CreateHotkeyHandler(ModSelectHotkeyStyle hotkeyStyle) + private IModHotkeyHandler createHotkeyHandler(ModSelectHotkeyStyle hotkeyStyle) { switch (ModType) { From e4931f977cadd7d90a4f965d4215013eaa207fe6 Mon Sep 17 00:00:00 2001 From: Supersonicboss1 Date: Tue, 21 Jun 2022 23:00:03 +0100 Subject: [PATCH 118/211] improved UI of maintenance section in settings --- ...{GeneralSettings.cs => BeatmapSettings.cs} | 88 +++---------------- .../Maintenance/CollectionsSettings.cs | 49 +++++++++++ .../Sections/Maintenance/ScoreSettings.cs | 52 +++++++++++ .../Sections/Maintenance/SkinSettings.cs | 52 +++++++++++ .../Settings/Sections/MaintenanceSection.cs | 5 +- 5 files changed, 170 insertions(+), 76 deletions(-) rename osu.Game/Overlays/Settings/Sections/Maintenance/{GeneralSettings.cs => BeatmapSettings.cs} (62%) create mode 100644 osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs create mode 100644 osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs create mode 100644 osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs similarity index 62% rename from osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs rename to osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs index 916c607c1c..474f23e4e7 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs @@ -9,31 +9,25 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Beatmaps; -using osu.Game.Collections; using osu.Game.Database; using osu.Game.Localisation; using osu.Game.Scoring; -using osu.Game.Skinning; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public class GeneralSettings : SettingsSubsection + public class BeatmapSettings : SettingsSubsection { - protected override LocalisableString Header => "General"; - + protected override LocalisableString Header => "Beatmaps"; private SettingsButton importBeatmapsButton; private SettingsButton importScoresButton; - private SettingsButton importSkinsButton; - private SettingsButton importCollectionsButton; private SettingsButton deleteBeatmapsButton; + private SettingsButton deleteBeatmapVideosButton; private SettingsButton deleteScoresButton; - private SettingsButton deleteSkinsButton; private SettingsButton restoreButton; private SettingsButton undeleteButton; - private SettingsButton deleteBeatmapVideosButton; [BackgroundDependencyLoader(permitNulls: true)] - private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, [CanBeNull] CollectionManager collectionManager, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay) + private void load(BeatmapManager beatmaps, ScoreManager scores, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay) { if (legacyImportManager?.SupportsImportFromStable == true) { @@ -46,6 +40,15 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance legacyImportManager.ImportFromStableAsync(StableContent.Beatmaps).ContinueWith(t => Schedule(() => importBeatmapsButton.Enabled.Value = true)); } }); + Add(importScoresButton = new SettingsButton + { + Text = MaintenanceSettingsStrings.ImportScoresFromStable, + Action = () => + { + importScoresButton.Enabled.Value = false; + legacyImportManager.ImportFromStableAsync(StableContent.Scores).ContinueWith(t => Schedule(() => importScoresButton.Enabled.Value = true)); + } + }); } Add(deleteBeatmapsButton = new DangerousSettingsButton @@ -74,19 +77,6 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance } }); - if (legacyImportManager?.SupportsImportFromStable == true) - { - Add(importScoresButton = new SettingsButton - { - Text = MaintenanceSettingsStrings.ImportScoresFromStable, - Action = () => - { - importScoresButton.Enabled.Value = false; - legacyImportManager.ImportFromStableAsync(StableContent.Scores).ContinueWith(t => Schedule(() => importScoresButton.Enabled.Value = true)); - } - }); - } - Add(deleteScoresButton = new DangerousSettingsButton { Text = MaintenanceSettingsStrings.DeleteAllScores, @@ -99,58 +89,6 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance })); } }); - - if (legacyImportManager?.SupportsImportFromStable == true) - { - Add(importSkinsButton = new SettingsButton - { - Text = MaintenanceSettingsStrings.ImportSkinsFromStable, - Action = () => - { - importSkinsButton.Enabled.Value = false; - legacyImportManager.ImportFromStableAsync(StableContent.Skins).ContinueWith(t => Schedule(() => importSkinsButton.Enabled.Value = true)); - } - }); - } - - Add(deleteSkinsButton = new DangerousSettingsButton - { - Text = MaintenanceSettingsStrings.DeleteAllSkins, - Action = () => - { - dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => - { - deleteSkinsButton.Enabled.Value = false; - Task.Run(() => skins.Delete()).ContinueWith(t => Schedule(() => deleteSkinsButton.Enabled.Value = true)); - })); - } - }); - - if (collectionManager != null) - { - if (legacyImportManager?.SupportsImportFromStable == true) - { - Add(importCollectionsButton = new SettingsButton - { - Text = MaintenanceSettingsStrings.ImportCollectionsFromStable, - Action = () => - { - importCollectionsButton.Enabled.Value = false; - legacyImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(t => Schedule(() => importCollectionsButton.Enabled.Value = true)); - } - }); - } - - Add(new DangerousSettingsButton - { - Text = MaintenanceSettingsStrings.DeleteAllCollections, - Action = () => - { - dialogOverlay?.Push(new MassDeleteConfirmationDialog(collectionManager.DeleteAll)); - } - }); - } - AddRange(new Drawable[] { restoreButton = new SettingsButton diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs new file mode 100644 index 0000000000..98a9a271ab --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs @@ -0,0 +1,49 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Localisation; +using osu.Game.Collections; +using osu.Game.Database; +using osu.Game.Localisation; + +namespace osu.Game.Overlays.Settings.Sections.Maintenance +{ + public class CollectionsSettings : SettingsSubsection + { + protected override LocalisableString Header => "Collections"; + private SettingsButton importCollectionsButton; + + [BackgroundDependencyLoader(permitNulls: true)] + private void load([CanBeNull] CollectionManager collectionManager, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay) + { + if (collectionManager != null) + { + if (legacyImportManager?.SupportsImportFromStable == true) + { + Add(importCollectionsButton = new SettingsButton + { + Text = MaintenanceSettingsStrings.ImportCollectionsFromStable, + Action = () => + { + importCollectionsButton.Enabled.Value = false; + legacyImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(t => Schedule(() => importCollectionsButton.Enabled.Value = true)); + } + }); + } + + Add(new DangerousSettingsButton + { + Text = MaintenanceSettingsStrings.DeleteAllCollections, + Action = () => + { + dialogOverlay?.Push(new MassDeleteConfirmationDialog(collectionManager.DeleteAll)); + } + }); + } + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs new file mode 100644 index 0000000000..ddeb48725c --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.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. + +#nullable disable + +using System.Threading.Tasks; +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Localisation; +using osu.Game.Database; +using osu.Game.Localisation; +using osu.Game.Scoring; + +namespace osu.Game.Overlays.Settings.Sections.Maintenance +{ + public class ScoreSettings : SettingsSubsection + { + protected override LocalisableString Header => "Scores"; + private SettingsButton importScoresButton; + private SettingsButton deleteScoresButton; + + [BackgroundDependencyLoader(permitNulls: true)] + private void load(ScoreManager scores, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay) + { + if (legacyImportManager?.SupportsImportFromStable == true) + { + Add(importScoresButton = new SettingsButton + { + Text = MaintenanceSettingsStrings.ImportScoresFromStable, + Action = () => + { + importScoresButton.Enabled.Value = false; + legacyImportManager.ImportFromStableAsync(StableContent.Scores).ContinueWith(t => Schedule(() => importScoresButton.Enabled.Value = true)); + } + }); + } + + Add(deleteScoresButton = new DangerousSettingsButton + { + Text = MaintenanceSettingsStrings.DeleteAllScores, + Action = () => + { + dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => + { + deleteScoresButton.Enabled.Value = false; + Task.Run(() => scores.Delete()).ContinueWith(t => Schedule(() => deleteScoresButton.Enabled.Value = true)); + })); + } + }); + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs new file mode 100644 index 0000000000..6019023c50 --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.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. + +#nullable disable + +using System.Threading.Tasks; +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Localisation; +using osu.Game.Database; +using osu.Game.Localisation; +using osu.Game.Skinning; + +namespace osu.Game.Overlays.Settings.Sections.Maintenance +{ + public class SkinSettings : SettingsSubsection + { + protected override LocalisableString Header => "Skins"; + private SettingsButton importSkinsButton; + private SettingsButton deleteSkinsButton; + + [BackgroundDependencyLoader(permitNulls: true)] + private void load(SkinManager skins, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay) + { + if (legacyImportManager?.SupportsImportFromStable == true) + { + Add(importSkinsButton = new SettingsButton + { + Text = MaintenanceSettingsStrings.ImportSkinsFromStable, + Action = () => + { + importSkinsButton.Enabled.Value = false; + legacyImportManager.ImportFromStableAsync(StableContent.Skins).ContinueWith(t => Schedule(() => importSkinsButton.Enabled.Value = true)); + } + }); + } + + Add(deleteSkinsButton = new DangerousSettingsButton + { + Text = MaintenanceSettingsStrings.DeleteAllSkins, + Action = () => + { + dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => + { + deleteSkinsButton.Enabled.Value = false; + Task.Run(() => skins.Delete()).ContinueWith(t => Schedule(() => deleteSkinsButton.Enabled.Value = true)); + })); + } + }); + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs b/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs index cfe1961bc1..19d02baa4a 100644 --- a/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs +++ b/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs @@ -24,7 +24,10 @@ namespace osu.Game.Overlays.Settings.Sections { Children = new Drawable[] { - new GeneralSettings() + new BeatmapSettings(), + new SkinSettings(), + new CollectionsSettings(), + new ScoreSettings() }; } } From 4aa86b0a8001fa1e0f2f6895f7160d226b80cb6d Mon Sep 17 00:00:00 2001 From: Supersonicboss1 Date: Tue, 21 Jun 2022 23:41:25 +0100 Subject: [PATCH 119/211] fixed duplicates and cleaned up code --- .../Sections/Maintenance/BeatmapSettings.cs | 113 +++++++----------- .../Maintenance/CollectionsSettings.cs | 36 +++--- .../Sections/Maintenance/ScoreSettings.cs | 2 +- .../Sections/Maintenance/SkinSettings.cs | 2 +- 4 files changed, 64 insertions(+), 89 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs index 474f23e4e7..57de259670 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd .Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable disable @@ -11,7 +11,6 @@ using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Localisation; -using osu.Game.Scoring; namespace osu.Game.Overlays.Settings.Sections.Maintenance { @@ -19,15 +18,13 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { protected override LocalisableString Header => "Beatmaps"; private SettingsButton importBeatmapsButton; - private SettingsButton importScoresButton; private SettingsButton deleteBeatmapsButton; private SettingsButton deleteBeatmapVideosButton; - private SettingsButton deleteScoresButton; private SettingsButton restoreButton; private SettingsButton undeleteButton; [BackgroundDependencyLoader(permitNulls: true)] - private void load(BeatmapManager beatmaps, ScoreManager scores, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay) + private void load(BeatmapManager beatmaps, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay) { if (legacyImportManager?.SupportsImportFromStable == true) { @@ -40,76 +37,54 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance legacyImportManager.ImportFromStableAsync(StableContent.Beatmaps).ContinueWith(t => Schedule(() => importBeatmapsButton.Enabled.Value = true)); } }); - Add(importScoresButton = new SettingsButton + + Add(deleteBeatmapsButton = new DangerousSettingsButton { - Text = MaintenanceSettingsStrings.ImportScoresFromStable, + Text = MaintenanceSettingsStrings.DeleteAllBeatmaps, Action = () => { - importScoresButton.Enabled.Value = false; - legacyImportManager.ImportFromStableAsync(StableContent.Scores).ContinueWith(t => Schedule(() => importScoresButton.Enabled.Value = true)); + dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => + { + deleteBeatmapsButton.Enabled.Value = false; + Task.Run(() => beatmaps.Delete()).ContinueWith(t => Schedule(() => deleteBeatmapsButton.Enabled.Value = true)); + })); + } + }); + + Add(deleteBeatmapVideosButton = new DangerousSettingsButton + { + Text = MaintenanceSettingsStrings.DeleteAllBeatmapVideos, + Action = () => + { + dialogOverlay?.Push(new MassVideoDeleteConfirmationDialog(() => + { + deleteBeatmapVideosButton.Enabled.Value = false; + Task.Run(beatmaps.DeleteAllVideos).ContinueWith(t => Schedule(() => deleteBeatmapVideosButton.Enabled.Value = true)); + })); + } + }); + AddRange(new Drawable[] + { + restoreButton = new SettingsButton + { + Text = MaintenanceSettingsStrings.RestoreAllHiddenDifficulties, + Action = () => + { + restoreButton.Enabled.Value = false; + Task.Run(beatmaps.RestoreAll).ContinueWith(t => Schedule(() => restoreButton.Enabled.Value = true)); + } + }, + undeleteButton = new SettingsButton + { + Text = MaintenanceSettingsStrings.RestoreAllRecentlyDeletedBeatmaps, + Action = () => + { + undeleteButton.Enabled.Value = false; + Task.Run(beatmaps.UndeleteAll).ContinueWith(t => Schedule(() => undeleteButton.Enabled.Value = true)); + } } }); } - - Add(deleteBeatmapsButton = new DangerousSettingsButton - { - Text = MaintenanceSettingsStrings.DeleteAllBeatmaps, - Action = () => - { - dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => - { - deleteBeatmapsButton.Enabled.Value = false; - Task.Run(() => beatmaps.Delete()).ContinueWith(t => Schedule(() => deleteBeatmapsButton.Enabled.Value = true)); - })); - } - }); - - Add(deleteBeatmapVideosButton = new DangerousSettingsButton - { - Text = MaintenanceSettingsStrings.DeleteAllBeatmapVideos, - Action = () => - { - dialogOverlay?.Push(new MassVideoDeleteConfirmationDialog(() => - { - deleteBeatmapVideosButton.Enabled.Value = false; - Task.Run(beatmaps.DeleteAllVideos).ContinueWith(t => Schedule(() => deleteBeatmapVideosButton.Enabled.Value = true)); - })); - } - }); - - Add(deleteScoresButton = new DangerousSettingsButton - { - Text = MaintenanceSettingsStrings.DeleteAllScores, - Action = () => - { - dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => - { - deleteScoresButton.Enabled.Value = false; - Task.Run(() => scores.Delete()).ContinueWith(t => Schedule(() => deleteScoresButton.Enabled.Value = true)); - })); - } - }); - AddRange(new Drawable[] - { - restoreButton = new SettingsButton - { - Text = MaintenanceSettingsStrings.RestoreAllHiddenDifficulties, - Action = () => - { - restoreButton.Enabled.Value = false; - Task.Run(beatmaps.RestoreAll).ContinueWith(t => Schedule(() => restoreButton.Enabled.Value = true)); - } - }, - undeleteButton = new SettingsButton - { - Text = MaintenanceSettingsStrings.RestoreAllRecentlyDeletedBeatmaps, - Action = () => - { - undeleteButton.Enabled.Value = false; - Task.Run(beatmaps.UndeleteAll).ContinueWith(t => Schedule(() => undeleteButton.Enabled.Value = true)); - } - }, - }); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs index 98a9a271ab..31b889ce0e 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd .Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable disable @@ -20,30 +20,30 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance [BackgroundDependencyLoader(permitNulls: true)] private void load([CanBeNull] CollectionManager collectionManager, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay) { - if (collectionManager != null) - { - if (legacyImportManager?.SupportsImportFromStable == true) - { - Add(importCollectionsButton = new SettingsButton - { - Text = MaintenanceSettingsStrings.ImportCollectionsFromStable, - Action = () => - { - importCollectionsButton.Enabled.Value = false; - legacyImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(t => Schedule(() => importCollectionsButton.Enabled.Value = true)); - } - }); - } + if (collectionManager == null) return; - Add(new DangerousSettingsButton + if (legacyImportManager?.SupportsImportFromStable == true) + + { + Add(importCollectionsButton = new SettingsButton { - Text = MaintenanceSettingsStrings.DeleteAllCollections, + Text = MaintenanceSettingsStrings.ImportCollectionsFromStable, Action = () => { - dialogOverlay?.Push(new MassDeleteConfirmationDialog(collectionManager.DeleteAll)); + importCollectionsButton.Enabled.Value = false; + legacyImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(t => Schedule(() => importCollectionsButton.Enabled.Value = true)); } }); } + + Add(new DangerousSettingsButton + { + Text = MaintenanceSettingsStrings.DeleteAllCollections, + Action = () => + { + dialogOverlay?.Push(new MassDeleteConfirmationDialog(collectionManager.DeleteAll)); + } + }); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs index ddeb48725c..26d9d2aa51 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd .Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable disable diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs index 6019023c50..ad680b363e 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd .Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable disable From 07e0cd53a4c81d1256c21864ec71bc849ebf37d9 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 21 Jun 2022 19:06:08 -0700 Subject: [PATCH 120/211] Add back online view container to chat overlay --- osu.Game/Overlays/ChatOverlay.cs | 74 +++++++++++++++++++------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 81a408598b..c491c0c695 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -18,6 +18,7 @@ using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; +using osu.Game.Online; using osu.Game.Online.Chat; using osu.Game.Overlays.Chat; using osu.Game.Overlays.Chat.ChannelList; @@ -100,23 +101,10 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.X, Height = top_bar_height, }, - channelList = new ChannelList - { - RelativeSizeAxes = Axes.Y, - Width = side_bar_width, - Padding = new MarginPadding { Top = top_bar_height }, - }, new Container { RelativeSizeAxes = Axes.Both, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Padding = new MarginPadding - { - Top = top_bar_height, - Left = side_bar_width, - Bottom = chat_bar_height, - }, + Padding = new MarginPadding { Top = top_bar_height }, Children = new Drawable[] { new Box @@ -124,24 +112,50 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background4, }, - currentChannelContainer = new Container + new OnlineViewContainer("Sign in to chat") { RelativeSizeAxes = Axes.Both, - }, - loading = new LoadingLayer(true), - channelListing = new ChannelListing - { - RelativeSizeAxes = Axes.Both, - }, - }, - }, - textBar = new ChatTextBar - { - RelativeSizeAxes = Axes.X, - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - Padding = new MarginPadding { Left = side_bar_width }, - }, + Children = new Drawable[] + { + channelList = new ChannelList + { + RelativeSizeAxes = Axes.Y, + Width = side_bar_width, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Padding = new MarginPadding + { + Left = side_bar_width, + Bottom = chat_bar_height, + }, + Children = new Drawable[] + { + currentChannelContainer = new Container + { + RelativeSizeAxes = Axes.Both, + }, + loading = new LoadingLayer(true), + channelListing = new ChannelListing + { + RelativeSizeAxes = Axes.Both, + }, + }, + }, + textBar = new ChatTextBar + { + RelativeSizeAxes = Axes.X, + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Padding = new MarginPadding { Left = side_bar_width }, + }, + } + } + } + } }; } From 23254d2ff206146b29fcf36c6643a404b1b33bbd Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 22 Jun 2022 13:02:33 +0900 Subject: [PATCH 121/211] Fix broken files --- .../Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs | 2 +- .../Settings/Sections/Maintenance/CollectionsSettings.cs | 2 +- .../Overlays/Settings/Sections/Maintenance/ScoreSettings.cs | 2 +- osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs index 57de259670..7d5c8a9958 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd .Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable disable diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs index 31b889ce0e..96583a1e4b 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd .Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable disable diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs index 26d9d2aa51..ddeb48725c 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd .Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable disable diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs index ad680b363e..6019023c50 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd .Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable disable From 1018c9852d0ce5e7b6bf3b0f4e056ea92e5d8664 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 22 Jun 2022 13:07:44 +0900 Subject: [PATCH 122/211] Cleanup nullability --- .../Sections/Maintenance/BeatmapSettings.cs | 18 ++++++++---------- .../Maintenance/CollectionsSettings.cs | 10 ++++------ .../Sections/Maintenance/ScoreSettings.cs | 12 +++++------- .../Sections/Maintenance/SkinSettings.cs | 12 +++++------- 4 files changed, 22 insertions(+), 30 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs index 7d5c8a9958..8039ee7cd9 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs @@ -1,10 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Threading.Tasks; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; @@ -17,14 +14,15 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance public class BeatmapSettings : SettingsSubsection { protected override LocalisableString Header => "Beatmaps"; - private SettingsButton importBeatmapsButton; - private SettingsButton deleteBeatmapsButton; - private SettingsButton deleteBeatmapVideosButton; - private SettingsButton restoreButton; - private SettingsButton undeleteButton; - [BackgroundDependencyLoader(permitNulls: true)] - private void load(BeatmapManager beatmaps, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay) + private SettingsButton importBeatmapsButton = null!; + private SettingsButton deleteBeatmapsButton = null!; + private SettingsButton deleteBeatmapVideosButton = null!; + private SettingsButton restoreButton = null!; + private SettingsButton undeleteButton = null!; + + [BackgroundDependencyLoader] + private void load(BeatmapManager beatmaps, LegacyImportManager? legacyImportManager, IDialogOverlay? dialogOverlay) { if (legacyImportManager?.SupportsImportFromStable == true) { diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs index 96583a1e4b..8387582fcb 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Localisation; using osu.Game.Collections; @@ -15,10 +12,11 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance public class CollectionsSettings : SettingsSubsection { protected override LocalisableString Header => "Collections"; - private SettingsButton importCollectionsButton; - [BackgroundDependencyLoader(permitNulls: true)] - private void load([CanBeNull] CollectionManager collectionManager, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay) + private SettingsButton importCollectionsButton = null!; + + [BackgroundDependencyLoader] + private void load(CollectionManager? collectionManager, LegacyImportManager? legacyImportManager, IDialogOverlay? dialogOverlay) { if (collectionManager == null) return; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs index ddeb48725c..9c1281f371 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs @@ -1,10 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Threading.Tasks; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Localisation; using osu.Game.Database; @@ -16,11 +13,12 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance public class ScoreSettings : SettingsSubsection { protected override LocalisableString Header => "Scores"; - private SettingsButton importScoresButton; - private SettingsButton deleteScoresButton; - [BackgroundDependencyLoader(permitNulls: true)] - private void load(ScoreManager scores, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay) + private SettingsButton importScoresButton = null!; + private SettingsButton deleteScoresButton = null!; + + [BackgroundDependencyLoader] + private void load(ScoreManager scores, LegacyImportManager? legacyImportManager, IDialogOverlay? dialogOverlay) { if (legacyImportManager?.SupportsImportFromStable == true) { diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs index 6019023c50..0fff9fef26 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs @@ -1,10 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Threading.Tasks; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Localisation; using osu.Game.Database; @@ -16,11 +13,12 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance public class SkinSettings : SettingsSubsection { protected override LocalisableString Header => "Skins"; - private SettingsButton importSkinsButton; - private SettingsButton deleteSkinsButton; - [BackgroundDependencyLoader(permitNulls: true)] - private void load(SkinManager skins, [CanBeNull] LegacyImportManager legacyImportManager, IDialogOverlay dialogOverlay) + private SettingsButton importSkinsButton = null!; + private SettingsButton deleteSkinsButton = null!; + + [BackgroundDependencyLoader] + private void load(SkinManager skins, LegacyImportManager? legacyImportManager, IDialogOverlay? dialogOverlay) { if (legacyImportManager?.SupportsImportFromStable == true) { From 321920bc857b07f1359ac0407a080c56f2815a6c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 22 Jun 2022 13:08:14 +0900 Subject: [PATCH 123/211] Remove one more nullable disable --- osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs b/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs index 19d02baa4a..841a7d0abe 100644 --- a/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs +++ b/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; From ff440fc1a4517d1da519f2ace93aa75a0698c366 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 22 Jun 2022 13:13:04 +0900 Subject: [PATCH 124/211] Fix too many buttons inside condition --- .../Sections/Maintenance/BeatmapSettings.cs | 94 +++++++++---------- .../Maintenance/CollectionsSettings.cs | 1 - 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs index 8039ee7cd9..8c8c2c96ff 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs @@ -35,54 +35,54 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance legacyImportManager.ImportFromStableAsync(StableContent.Beatmaps).ContinueWith(t => Schedule(() => importBeatmapsButton.Enabled.Value = true)); } }); - - Add(deleteBeatmapsButton = new DangerousSettingsButton - { - Text = MaintenanceSettingsStrings.DeleteAllBeatmaps, - Action = () => - { - dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => - { - deleteBeatmapsButton.Enabled.Value = false; - Task.Run(() => beatmaps.Delete()).ContinueWith(t => Schedule(() => deleteBeatmapsButton.Enabled.Value = true)); - })); - } - }); - - Add(deleteBeatmapVideosButton = new DangerousSettingsButton - { - Text = MaintenanceSettingsStrings.DeleteAllBeatmapVideos, - Action = () => - { - dialogOverlay?.Push(new MassVideoDeleteConfirmationDialog(() => - { - deleteBeatmapVideosButton.Enabled.Value = false; - Task.Run(beatmaps.DeleteAllVideos).ContinueWith(t => Schedule(() => deleteBeatmapVideosButton.Enabled.Value = true)); - })); - } - }); - AddRange(new Drawable[] - { - restoreButton = new SettingsButton - { - Text = MaintenanceSettingsStrings.RestoreAllHiddenDifficulties, - Action = () => - { - restoreButton.Enabled.Value = false; - Task.Run(beatmaps.RestoreAll).ContinueWith(t => Schedule(() => restoreButton.Enabled.Value = true)); - } - }, - undeleteButton = new SettingsButton - { - Text = MaintenanceSettingsStrings.RestoreAllRecentlyDeletedBeatmaps, - Action = () => - { - undeleteButton.Enabled.Value = false; - Task.Run(beatmaps.UndeleteAll).ContinueWith(t => Schedule(() => undeleteButton.Enabled.Value = true)); - } - } - }); } + + Add(deleteBeatmapsButton = new DangerousSettingsButton + { + Text = MaintenanceSettingsStrings.DeleteAllBeatmaps, + Action = () => + { + dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => + { + deleteBeatmapsButton.Enabled.Value = false; + Task.Run(() => beatmaps.Delete()).ContinueWith(t => Schedule(() => deleteBeatmapsButton.Enabled.Value = true)); + })); + } + }); + + Add(deleteBeatmapVideosButton = new DangerousSettingsButton + { + Text = MaintenanceSettingsStrings.DeleteAllBeatmapVideos, + Action = () => + { + dialogOverlay?.Push(new MassVideoDeleteConfirmationDialog(() => + { + deleteBeatmapVideosButton.Enabled.Value = false; + Task.Run(beatmaps.DeleteAllVideos).ContinueWith(t => Schedule(() => deleteBeatmapVideosButton.Enabled.Value = true)); + })); + } + }); + AddRange(new Drawable[] + { + restoreButton = new SettingsButton + { + Text = MaintenanceSettingsStrings.RestoreAllHiddenDifficulties, + Action = () => + { + restoreButton.Enabled.Value = false; + Task.Run(beatmaps.RestoreAll).ContinueWith(t => Schedule(() => restoreButton.Enabled.Value = true)); + } + }, + undeleteButton = new SettingsButton + { + Text = MaintenanceSettingsStrings.RestoreAllRecentlyDeletedBeatmaps, + Action = () => + { + undeleteButton.Enabled.Value = false; + Task.Run(beatmaps.UndeleteAll).ContinueWith(t => Schedule(() => undeleteButton.Enabled.Value = true)); + } + } + }); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs index 8387582fcb..74e9ebc084 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs @@ -21,7 +21,6 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance if (collectionManager == null) return; if (legacyImportManager?.SupportsImportFromStable == true) - { Add(importCollectionsButton = new SettingsButton { From f561d5b4ad5a96d88690c14126efe41ee3e946eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Jun 2022 14:32:42 +0900 Subject: [PATCH 125/211] Change always-discarded-parameter inspection to hint See https://github.com/ppy/osu/blob/f8830c6850128456266c82de83273204f8b74ac0/osu.Game/Rulesets/Scoring/ScoreProcessor.cs#L518 Coming up as a suggestion (the only one in the solution). --- osu.sln.DotSettings | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 286a1eb29f..e732b25951 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -126,6 +126,8 @@ HINT HINT WARNING + HINT + HINT HINT HINT HINT From 950551f4fda91db3ab8a078b29d2f4977fd3d370 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Wed, 22 Jun 2022 15:33:42 +0900 Subject: [PATCH 126/211] Fix metronome arm being stuck white when paused 'close enough' to center --- osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index 37fc38404f..3895959982 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -276,6 +276,7 @@ namespace osu.Game.Screens.Edit.Timing if (Precision.AlmostEquals(swing.Rotation, 0, 1)) { swing.RotateTo(0, 60, Easing.OutQuint); + stick.FadeColour(overlayColourProvider.Colour2, 1000, Easing.OutQuint); sampleLatch?.Play(); return; } From 948c28f41532bd3b8406ce371cb453bdf1dbaca1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 22 Jun 2022 20:34:05 +0900 Subject: [PATCH 127/211] Fix collection modified during `BlockAllOperations` if any subscriptions have been established --- osu.Game/Database/RealmAccess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index cf9109eb8b..68f9dcb541 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -822,7 +822,7 @@ namespace osu.Game.Database // Before disposing the update context, clean up all subscriptions. // Note that in the case of realm notification subscriptions, this is not really required (they will be cleaned up by disposal). // In the case of custom subscriptions, we want them to fire before the update realm is disposed in case they do any follow-up work. - foreach (var action in customSubscriptionsResetMap) + foreach (var action in customSubscriptionsResetMap.ToArray()) { action.Value?.Dispose(); customSubscriptionsResetMap[action.Key] = null; From bc557bacf05199aecd51adec69536eb1cdb10a9a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Jun 2022 14:10:17 +0900 Subject: [PATCH 128/211] Remove room null assertion in `TestMultiplayerClient.ChangeState` to avoid assert This method is run from async contexts, but `get_Room` asserts update thread which is not the case. Was causing silent test failures (showing as pass but failing `dotnet-test` via return code): TestSceneMultiplayer.TestGameplayFlow ``` [13:13:17] : [dotnet test] [runtime] 2022-06-22 13:13:16 [error]: Score preparation failed! [13:13:17] : [dotnet test] [runtime] 2022-06-22 13:13:16 [error]: NUnit.Framework.AssertionException: : [13:13:17] : [dotnet test] [runtime] 2022-06-22 13:13:16 [error]: at osu.Framework.Logging.ThrowingTraceListener.Fail(String message1, String message2) [13:13:17] : [dotnet test] [runtime] 2022-06-22 13:13:16 [error]: at System.Diagnostics.TraceInternal.Fail(String message, String detailMessage) [13:13:17] : [dotnet test] [runtime] 2022-06-22 13:13:16 [error]: at System.Diagnostics.TraceInternal.TraceProvider.Fail(String message, String detailMessage) [13:13:17] : [dotnet test] [runtime] 2022-06-22 13:13:16 [error]: at System.Diagnostics.Debug.Fail(String message, String detailMessage) [13:13:17] : [dotnet test] [runtime] 2022-06-22 13:13:16 [error]: at osu.Game.Online.Multiplayer.MultiplayerClient.get_Room() in /opt/buildagent/work/ecd860037212ac52/osu.Game/Online/Multiplayer/MultiplayerClient.cs:line 98 [13:13:17] : [dotnet test] [runtime] 2022-06-22 13:13:16 [error]: at osu.Game.Tests.Visual.Multiplayer.TestMultiplayerClient.ChangeState(MultiplayerUserState newState) in /opt/buildagent/work/ecd860037212ac52/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs:line 275 [13:13:17] : [dotnet test] [runtime] 2022-06-22 13:13:16 [error]: at osu.Game.Screens.OnlinePlay.Multiplayer.MultiplayerPlayer.PrepareScoreForResultsAsync(Score score) in /opt/buildagent/work/ecd860037212ac52/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs:line 223 [13:13:17] : [dotnet test] [runtime] 2022-06-22 13:13:16 [error]: at osu.Game.Screens.Play.Player.prepareScoreForResults() in /opt/buildagent/work/ecd860037212ac52/osu.Game/Screens/Play/Player.cs:line 747 ``` --- osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index e5a1236abf..f2024a3107 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -272,8 +272,6 @@ namespace osu.Game.Tests.Visual.Multiplayer public override Task ChangeState(MultiplayerUserState newState) { - Debug.Assert(Room != null); - if (newState == MultiplayerUserState.Idle && LocalUser?.State == MultiplayerUserState.WaitingForLoad) return Task.CompletedTask; From ed9c55a7765d8e9771d6dd3b6ceca350c5781a3f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Jun 2022 14:33:07 +0900 Subject: [PATCH 129/211] Ban usage of `ManualResetEventSlim.Wait()` without a timeout value --- CodeAnalysis/BannedSymbols.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CodeAnalysis/BannedSymbols.txt b/CodeAnalysis/BannedSymbols.txt index b72df0a306..77197c4c51 100644 --- a/CodeAnalysis/BannedSymbols.txt +++ b/CodeAnalysis/BannedSymbols.txt @@ -16,3 +16,4 @@ M:Realms.CollectionExtensions.SubscribeForNotifications`1(System.Linq.IQueryable M:Realms.CollectionExtensions.SubscribeForNotifications`1(System.Collections.Generic.IList{``0},Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IList,NotificationCallbackDelegate) instead. M:System.Threading.Tasks.Task.Wait();Don't use Task.Wait. Use Task.WaitSafely() to ensure we avoid deadlocks. P:System.Threading.Tasks.Task`1.Result;Don't use Task.Result. Use Task.GetResultSafely() to ensure we avoid deadlocks. +M:System.Threading.ManualResetEventSlim.Wait();Specify a timeout to avoid waiting forever. From 7ef8b7df5f788427d2d0c0309923babb073b23bc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Jun 2022 14:33:20 +0900 Subject: [PATCH 130/211] Add timeout for all `ManualResetEventSlim.Wait` invocations Timeout values were taken as best-guesses of upper values we'd expect from sane execution. --- osu.Game.Benchmarks/BenchmarkRealmReads.cs | 4 ++-- osu.Game.Tests/Database/GeneralUsageTests.cs | 4 ++-- .../Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs | 2 +- osu.Game/Database/DatabaseContextFactory.cs | 2 +- osu.Game/Graphics/ScreenshotManager.cs | 2 +- osu.Game/OsuGameBase.cs | 3 ++- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/osu.Game.Benchmarks/BenchmarkRealmReads.cs b/osu.Game.Benchmarks/BenchmarkRealmReads.cs index bdc24315bf..b26fc3fd59 100644 --- a/osu.Game.Benchmarks/BenchmarkRealmReads.cs +++ b/osu.Game.Benchmarks/BenchmarkRealmReads.cs @@ -76,7 +76,7 @@ namespace osu.Game.Benchmarks } }); - done.Wait(); + done.Wait(60000); } [Benchmark] @@ -115,7 +115,7 @@ namespace osu.Game.Benchmarks } }); - done.Wait(); + done.Wait(60000); } [Benchmark] diff --git a/osu.Game.Tests/Database/GeneralUsageTests.cs b/osu.Game.Tests/Database/GeneralUsageTests.cs index d10ab2ad2b..c28a0c63af 100644 --- a/osu.Game.Tests/Database/GeneralUsageTests.cs +++ b/osu.Game.Tests/Database/GeneralUsageTests.cs @@ -79,11 +79,11 @@ namespace osu.Game.Tests.Database { hasThreadedUsage.Set(); - stopThreadedUsage.Wait(); + stopThreadedUsage.Wait(60000); }); }, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler); - hasThreadedUsage.Wait(); + hasThreadedUsage.Wait(60000); Assert.Throws(() => { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs index fc3079cba0..5b4e0a88aa 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs @@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { Task.Run(() => { - allowResponseCallback.Wait(); + allowResponseCallback.Wait(10000); allowResponseCallback.Reset(); Schedule(() => d?.Invoke("Incorrect password")); }); diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs index 8af649fbfa..075383c6e1 100644 --- a/osu.Game/Database/DatabaseContextFactory.cs +++ b/osu.Game/Database/DatabaseContextFactory.cs @@ -209,6 +209,6 @@ namespace osu.Game.Database public void SetMigrationCompletion() => migrationComplete.Set(); - public void WaitForMigrationCompletion() => migrationComplete.Wait(); + public void WaitForMigrationCompletion() => migrationComplete.Wait(300000); } } diff --git a/osu.Game/Graphics/ScreenshotManager.cs b/osu.Game/Graphics/ScreenshotManager.cs index 7147f89dd0..fe9865dad6 100644 --- a/osu.Game/Graphics/ScreenshotManager.cs +++ b/osu.Game/Graphics/ScreenshotManager.cs @@ -103,7 +103,7 @@ namespace osu.Game.Graphics framesWaitedEvent.Set(); }, 10, true); - framesWaitedEvent.Wait(); + framesWaitedEvent.Wait(1000); waitDelegate.Cancel(); } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 58929ce4a4..7bbad3bb72 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -451,7 +451,8 @@ namespace osu.Game readyToRun.Set(); }, false); - readyToRun.Wait(); + if (!readyToRun.Wait(30000)) + throw new TimeoutException("Attempting to block for migration took too long."); bool? cleanupSucceded = (Storage as OsuStorage)?.Migrate(Host.GetStorage(path)); From 51268d0cc8333bb7f74e74e6fc776b698ea47d63 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Jun 2022 15:28:20 +0900 Subject: [PATCH 131/211] Throw on `Wait` failure in a few remaining cases --- osu.Game/Database/DatabaseContextFactory.cs | 6 +++++- osu.Game/Graphics/ScreenshotManager.cs | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs index 075383c6e1..af91fb4971 100644 --- a/osu.Game/Database/DatabaseContextFactory.cs +++ b/osu.Game/Database/DatabaseContextFactory.cs @@ -209,6 +209,10 @@ namespace osu.Game.Database public void SetMigrationCompletion() => migrationComplete.Set(); - public void WaitForMigrationCompletion() => migrationComplete.Wait(300000); + public void WaitForMigrationCompletion() + { + if (!migrationComplete.Wait(300000)) + throw new TimeoutException("Migration took too long (likely stuck)."); + } } } diff --git a/osu.Game/Graphics/ScreenshotManager.cs b/osu.Game/Graphics/ScreenshotManager.cs index fe9865dad6..2cc9e63c87 100644 --- a/osu.Game/Graphics/ScreenshotManager.cs +++ b/osu.Game/Graphics/ScreenshotManager.cs @@ -103,7 +103,9 @@ namespace osu.Game.Graphics framesWaitedEvent.Set(); }, 10, true); - framesWaitedEvent.Wait(1000); + if (!framesWaitedEvent.Wait(1000)) + throw new TimeoutException("Screenshot data did not arrive in a timely fashion"); + waitDelegate.Cancel(); } } From 158f0a1f233d14234ddc999dfe6b5d763f41e733 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Jun 2022 17:38:34 +0900 Subject: [PATCH 132/211] Remove remaining `Room!=null` checks in `TestMultiplayerClient` where possible --- .../Visual/Multiplayer/TestMultiplayerClient.cs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index f2024a3107..6b7495762a 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -87,8 +87,6 @@ namespace osu.Game.Tests.Visual.Multiplayer switch (Room?.MatchState) { case TeamVersusRoomState teamVersus: - Debug.Assert(Room != null); - // simulate the server's automatic assignment of users to teams on join. // the "best" team is the one with the least users on it. int bestTeam = teamVersus.Teams @@ -103,6 +101,7 @@ namespace osu.Game.Tests.Visual.Multiplayer public void RemoveUser(APIUser user) { Debug.Assert(Room != null); + ((IMultiplayerClient)this).UserLeft(new MultiplayerRoomUser(user.Id)); Schedule(() => @@ -114,25 +113,23 @@ namespace osu.Game.Tests.Visual.Multiplayer public void ChangeRoomState(MultiplayerRoomState newState) { - Debug.Assert(Room != null); ((IMultiplayerClient)this).RoomStateChanged(newState); } public void ChangeUserState(int userId, MultiplayerUserState newState) { - Debug.Assert(Room != null); - ((IMultiplayerClient)this).UserStateChanged(userId, newState); updateRoomStateIfRequired(); } private void updateRoomStateIfRequired() { - Debug.Assert(Room != null); Debug.Assert(APIRoom != null); Schedule(() => { + Debug.Assert(Room != null); + switch (Room.State) { case MultiplayerRoomState.Open: @@ -179,8 +176,6 @@ namespace osu.Game.Tests.Visual.Multiplayer public void ChangeUserBeatmapAvailability(int userId, BeatmapAvailability newBeatmapAvailability) { - Debug.Assert(Room != null); - ((IMultiplayerClient)this).UserBeatmapAvailabilityChanged(userId, newBeatmapAvailability); } @@ -290,7 +285,6 @@ namespace osu.Game.Tests.Visual.Multiplayer public void ChangeUserMods(int userId, IEnumerable newMods) { - Debug.Assert(Room != null); ((IMultiplayerClient)this).UserModsChanged(userId, newMods.ToList()); } @@ -338,7 +332,6 @@ namespace osu.Game.Tests.Visual.Multiplayer public override Task AbortGameplay() { - Debug.Assert(Room != null); Debug.Assert(LocalUser != null); ChangeUserState(LocalUser.UserID, MultiplayerUserState.Idle); From 4a316fad2fedf334db9761764a46d59fb9e18e3a Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 23 Jun 2022 17:18:37 +0900 Subject: [PATCH 133/211] Add audio feedback for rearranging list items --- .../OsuRearrangeableListContainer.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs b/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs index 84d0d1eb32..a314992287 100644 --- a/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs +++ b/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs @@ -3,9 +3,14 @@ #nullable disable +using System.Collections.Specialized; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Utils; namespace osu.Game.Graphics.Containers { @@ -18,11 +23,44 @@ namespace osu.Game.Graphics.Containers protected override ScrollContainer CreateScrollContainer() => new OsuScrollContainer(); + private Sample sampleSwap; + private double sampleLastPlaybackTime; + protected sealed override RearrangeableListItem CreateDrawable(TModel item) => CreateOsuDrawable(item).With(d => { d.DragActive.BindTo(DragActive); }); protected abstract OsuRearrangeableListItem CreateOsuDrawable(TModel item); + + protected OsuRearrangeableListContainer() + { + Items.CollectionChanged += (_, args) => + { + if (args.Action == NotifyCollectionChangedAction.Move) + playSwapSample(); + }; + } + + private void playSwapSample() + { + if (Time.Current - sampleLastPlaybackTime <= 35) + return; + + var channel = sampleSwap?.GetChannel(); + if (channel == null) + return; + + channel.Frequency.Value = 0.96 + RNG.NextDouble(0.08); + channel.Play(); + sampleLastPlaybackTime = Time.Current; + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sampleSwap = audio.Samples.Get(@"UI/item-swap"); + sampleLastPlaybackTime = Time.Current; + } } } From d6b073ebad526db327ad0fcb43d4c9f9dbaf2fbb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Jun 2022 16:39:33 +0900 Subject: [PATCH 134/211] Move `DifficultyRetrieve` to own class and split both pathways into separate constructors --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 63 ++++---------- .../Beatmaps/Drawables/DifficultyRetriever.cs | 85 +++++++++++++++++++ 2 files changed, 100 insertions(+), 48 deletions(-) create mode 100644 osu.Game/Beatmaps/Drawables/DifficultyRetriever.cs diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index a1b0f04aae..a5b13d10e6 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; -using System.Threading; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -63,7 +62,8 @@ namespace osu.Game.Beatmaps.Drawables /// The mods to show the difficulty with. /// Whether to display a tooltip when hovered. /// Whether to perform difficulty lookup (including calculation if necessary). - public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList mods, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true) + public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList mods, bool shouldShowTooltip = true, + bool performBackgroundDifficultyLookup = true) : this(beatmapInfo, shouldShowTooltip, performBackgroundDifficultyLookup) { this.ruleset = ruleset ?? beatmapInfo.Ruleset; @@ -125,13 +125,21 @@ namespace osu.Game.Beatmaps.Drawables }; if (performBackgroundDifficultyLookup) - iconContainer.Add(new DelayedLoadUnloadWrapper(() => new DifficultyRetriever(beatmapInfo, ruleset, mods) { StarDifficulty = { BindTarget = difficultyBindable } }, 0)); + iconContainer.Add(new DelayedLoadUnloadWrapper(createDifficultyRetriever, 0)); else difficultyBindable.Value = new StarDifficulty(beatmapInfo.StarRating, 0); difficultyBindable.BindValueChanged(difficulty => background.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars)); } + private Drawable createDifficultyRetriever() + { + if (ruleset != null && mods != null) + return new DifficultyRetriever(beatmapInfo, ruleset, mods) { StarDifficulty = { BindTarget = difficultyBindable } }; + + return new DifficultyRetriever(beatmapInfo) { StarDifficulty = { BindTarget = difficultyBindable } }; + } + private Drawable getRulesetIcon() { int? onlineID = (ruleset ?? beatmapInfo.Ruleset).OnlineID; @@ -142,51 +150,10 @@ namespace osu.Game.Beatmaps.Drawables return new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle }; } - ITooltip IHasCustomTooltip.GetCustomTooltip() => new DifficultyIconTooltip(); + ITooltip IHasCustomTooltip. + GetCustomTooltip() => new DifficultyIconTooltip(); - DifficultyIconTooltipContent IHasCustomTooltip.TooltipContent => shouldShowTooltip ? new DifficultyIconTooltipContent(beatmapInfo, difficultyBindable) : null; - - private class DifficultyRetriever : Component - { - public readonly Bindable StarDifficulty = new Bindable(); - - private readonly IBeatmapInfo beatmapInfo; - private readonly IRulesetInfo ruleset; - private readonly IReadOnlyList mods; - - private CancellationTokenSource difficultyCancellation; - - [Resolved] - private BeatmapDifficultyCache difficultyCache { get; set; } - - public DifficultyRetriever(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, IReadOnlyList mods) - { - this.beatmapInfo = beatmapInfo; - this.ruleset = ruleset; - this.mods = mods; - } - - private IBindable localStarDifficulty; - - [BackgroundDependencyLoader] - private void load() - { - difficultyCancellation = new CancellationTokenSource(); - localStarDifficulty = ruleset != null - ? difficultyCache.GetBindableDifficulty(beatmapInfo, ruleset, mods, difficultyCancellation.Token) - : difficultyCache.GetBindableDifficulty(beatmapInfo, difficultyCancellation.Token); - localStarDifficulty.BindValueChanged(d => - { - if (d.NewValue is StarDifficulty diff) - StarDifficulty.Value = diff; - }); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - difficultyCancellation?.Cancel(); - } - } + DifficultyIconTooltipContent IHasCustomTooltip. + TooltipContent => shouldShowTooltip ? new DifficultyIconTooltipContent(beatmapInfo, difficultyBindable) : null; } } diff --git a/osu.Game/Beatmaps/Drawables/DifficultyRetriever.cs b/osu.Game/Beatmaps/Drawables/DifficultyRetriever.cs new file mode 100644 index 0000000000..a993f0657b --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/DifficultyRetriever.cs @@ -0,0 +1,85 @@ +// 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.Collections.Generic; +using System.Threading; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Beatmaps.Drawables +{ + /// + /// A component solely responsible for calculating difficulty in the background. + /// Intended for use with to only run processing when usage is on-screen. + /// + public class DifficultyRetriever : Component + { + /// + /// The bindable star difficulty. + /// + public IBindable StarDifficulty => starDifficulty; + + private readonly Bindable starDifficulty = new Bindable(); + + private readonly IBeatmapInfo beatmapInfo; + + private readonly IRulesetInfo? ruleset; + private readonly IReadOnlyList? mods; + + private readonly CancellationTokenSource difficultyCancellation = new CancellationTokenSource(); + + [Resolved] + private BeatmapDifficultyCache difficultyCache { get; set; } = null!; + + /// + /// Construct a difficulty retriever that tracks the current ruleset / mod selection. + /// + /// The beatmap to use for calculation. + public DifficultyRetriever(IBeatmapInfo beatmapInfo) + { + this.beatmapInfo = beatmapInfo; + } + + /// + /// Construct a difficulty retriever that is calculated only once for the specified ruleset / mod combination. + /// This will not track global ruleset and mod changes. + /// + /// The beatmap to use for calculation. + /// The ruleset to use for calculation. + /// The mods to use for calculation. + public DifficultyRetriever(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, IReadOnlyList mods) + { + this.beatmapInfo = beatmapInfo; + this.ruleset = ruleset; + this.mods = mods; + } + + private IBindable localStarDifficulty = null!; + + [BackgroundDependencyLoader] + private void load() + { + localStarDifficulty = ruleset != null + ? difficultyCache.GetBindableDifficulty(beatmapInfo, ruleset, mods, difficultyCancellation.Token) + : difficultyCache.GetBindableDifficulty(beatmapInfo, difficultyCancellation.Token); + + localStarDifficulty.BindValueChanged(d => + { + if (d.NewValue is StarDifficulty diff) + starDifficulty.Value = diff; + }); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + difficultyCancellation.Cancel(); + } + } +} From 3a83e5684c64226005ddddc349af36f1defba66a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Jun 2022 16:55:22 +0900 Subject: [PATCH 135/211] Tidy up `DifficultyIcon` --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index a5b13d10e6..48ee1e1fc8 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -26,8 +26,6 @@ namespace osu.Game.Beatmaps.Drawables { public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip { - private readonly Container iconContainer; - /// /// Size of this difficulty icon. /// @@ -46,14 +44,19 @@ namespace osu.Game.Beatmaps.Drawables [CanBeNull] private readonly IReadOnlyList mods; + [Resolved] + private IRulesetStore rulesets { get; set; } + private readonly bool shouldShowTooltip; private readonly bool performBackgroundDifficultyLookup; - private readonly Bindable difficultyBindable = new Bindable(); - private Drawable background; + private readonly Container iconContainer; + + private readonly Bindable difficultyBindable = new Bindable(); + /// /// Creates a new with a given and combination. /// @@ -87,9 +90,6 @@ namespace osu.Game.Beatmaps.Drawables InternalChild = iconContainer = new Container { Size = new Vector2(20f) }; } - [Resolved] - private IRulesetStore rulesets { get; set; } - [BackgroundDependencyLoader] private void load(OsuColour colours) { From 4a2ca4394b7ccd79fe32232ce3a84fa93a3f5234 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Jun 2022 18:37:36 +0900 Subject: [PATCH 136/211] Remove unused `ModeTypeInfo` class --- .../OnlinePlay/Components/ModeTypeInfo.cs | 78 ------------------- 1 file changed, 78 deletions(-) delete mode 100644 osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs diff --git a/osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs b/osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs deleted file mode 100644 index 641776a9e8..0000000000 --- a/osu.Game/Screens/OnlinePlay/Components/ModeTypeInfo.cs +++ /dev/null @@ -1,78 +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 disable - -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps.Drawables; -using osu.Game.Rulesets; -using osuTK; - -namespace osu.Game.Screens.OnlinePlay.Components -{ - public class ModeTypeInfo : OnlinePlayComposite - { - private const float height = 28; - private const float transition_duration = 100; - - [Resolved] - private RulesetStore rulesets { get; set; } - - private Container drawableRuleset; - - public ModeTypeInfo() - { - AutoSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader] - private void load() - { - Container gameTypeContainer; - - InternalChild = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5f, 0f), - LayoutDuration = 100, - Children = new[] - { - drawableRuleset = new Container - { - AutoSizeAxes = Axes.Both, - }, - gameTypeContainer = new Container - { - AutoSizeAxes = Axes.Both, - }, - }, - }; - - Type.BindValueChanged(type => gameTypeContainer.Child = new DrawableGameType(type.NewValue) { Size = new Vector2(height) }, true); - - Playlist.CollectionChanged += (_, __) => updateBeatmap(); - - updateBeatmap(); - } - - private void updateBeatmap() - { - var item = Playlist.FirstOrDefault(); - var ruleset = item == null ? null : rulesets.GetRuleset(item.RulesetID)?.CreateInstance(); - - if (item?.Beatmap != null && ruleset != null) - { - var mods = item.RequiredMods.Select(m => m.ToMod(ruleset)).ToArray(); - - drawableRuleset.FadeIn(transition_duration); - drawableRuleset.Child = new DifficultyIcon(item.Beatmap, ruleset.RulesetInfo, mods) { Size = new Vector2(height) }; - } - else - drawableRuleset.FadeOut(transition_duration); - } - } -} From 7dec530ca5b1a3cdf18c56f76863d9eaf3a2c633 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Jun 2022 18:37:53 +0900 Subject: [PATCH 137/211] Split out simple `DifficultyIcon` with no calculation overhead and update usages --- .../Drawables/CalculatingDifficultyIcon.cs | 80 +++++++++++++++++ osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 89 ++++++------------- .../Drawables/GroupedDifficultyIcon.cs | 2 +- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 3 +- .../OnlinePlay/DrawableRoomPlaylistItem.cs | 2 +- .../Carousel/DrawableCarouselBeatmap.cs | 2 +- .../Carousel/FilterableDifficultyIcon.cs | 4 +- .../Select/Carousel/SetPanelContent.cs | 8 +- 8 files changed, 120 insertions(+), 70 deletions(-) create mode 100644 osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs diff --git a/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs new file mode 100644 index 0000000000..5f914f446c --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs @@ -0,0 +1,80 @@ +#nullable enable +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; +using osuTK; + +namespace osu.Game.Beatmaps.Drawables +{ + /// + /// A difficulty icon which automatically calculates difficulty in the background. + /// + public class CalculatingDifficultyIcon : CompositeDrawable + { + /// + /// Size of this difficulty icon. + /// + public new Vector2 Size + { + get => difficultyIcon.Size; + set => difficultyIcon.Size = value; + } + + private readonly IRulesetInfo? ruleset; + + private readonly IReadOnlyList? mods; + + private readonly IBeatmapInfo beatmapInfo; + + private readonly DifficultyIcon difficultyIcon; + + /// + /// Creates a new with a given and combination. + /// + /// The beatmap to show the difficulty of. + /// The ruleset to show the difficulty with. + /// The mods to show the difficulty with. + /// Whether to display a tooltip when hovered. + /// Whether to perform difficulty lookup (including calculation if necessary). + public CalculatingDifficultyIcon(IBeatmapInfo beatmapInfo, IRulesetInfo? ruleset, IReadOnlyList? mods, bool shouldShowTooltip = true, + bool performBackgroundDifficultyLookup = true) + : this(beatmapInfo, shouldShowTooltip, performBackgroundDifficultyLookup) + { + this.ruleset = ruleset ?? beatmapInfo.Ruleset; + this.mods = mods ?? Array.Empty(); + } + + /// + /// Creates a new that follows the currently-selected ruleset and mods. + /// + /// The beatmap to show the difficulty of. + /// Whether to display a tooltip when hovered. + /// Whether to perform difficulty lookup (including calculation if necessary). + public CalculatingDifficultyIcon(IBeatmapInfo beatmapInfo, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true) + { + this.beatmapInfo = beatmapInfo ?? throw new ArgumentNullException(nameof(beatmapInfo)); + + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + difficultyIcon = new DifficultyIcon(beatmapInfo, beatmapInfo.Ruleset), + new DelayedLoadUnloadWrapper(createDifficultyRetriever, 0) + }; + } + + private Drawable createDifficultyRetriever() + { + if (ruleset != null && mods != null) + return new DifficultyRetriever(beatmapInfo, ruleset, mods) { StarDifficulty = { BindTarget = difficultyIcon.Current } }; + + return new DifficultyRetriever(beatmapInfo) { StarDifficulty = { BindTarget = difficultyIcon.Current } }; + } + } +} diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 48ee1e1fc8..d1b15cba76 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -1,11 +1,6 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using System; -using System.Collections.Generic; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -15,16 +10,16 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; using osuTK; using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables { - public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip + public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip, IHasCurrentValue { /// /// Size of this difficulty icon. @@ -35,58 +30,46 @@ namespace osu.Game.Beatmaps.Drawables set => iconContainer.Size = value; } - [NotNull] - private readonly IBeatmapInfo beatmapInfo; + private readonly IBeatmapInfo? beatmap; - [CanBeNull] private readonly IRulesetInfo ruleset; - [CanBeNull] - private readonly IReadOnlyList mods; - - [Resolved] - private IRulesetStore rulesets { get; set; } - - private readonly bool shouldShowTooltip; - - private readonly bool performBackgroundDifficultyLookup; - - private Drawable background; + private Drawable background = null!; private readonly Container iconContainer; - private readonly Bindable difficultyBindable = new Bindable(); + private readonly BindableWithCurrent difficulty = new BindableWithCurrent(); + + public virtual Bindable Current + { + get => difficulty.Current; + set => difficulty.Current = value; + } + + [Resolved] + private IRulesetStore rulesets { get; set; } = null!; /// - /// Creates a new with a given and combination. + /// Creates a new with a tooltip. Will use provided beatmap's for initial value. /// - /// The beatmap to show the difficulty of. - /// The ruleset to show the difficulty with. - /// The mods to show the difficulty with. - /// Whether to display a tooltip when hovered. - /// Whether to perform difficulty lookup (including calculation if necessary). - public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList mods, bool shouldShowTooltip = true, - bool performBackgroundDifficultyLookup = true) - : this(beatmapInfo, shouldShowTooltip, performBackgroundDifficultyLookup) + /// The beatmap to be displayed in the tooltip, and to be used for the initial star rating value. + /// An optional ruleset to be used for the icon display, in place of the beatmap's ruleset. + public DifficultyIcon(IBeatmapInfo beatmap, IRulesetInfo? ruleset) + : this(ruleset ?? beatmap.Ruleset) { - this.ruleset = ruleset ?? beatmapInfo.Ruleset; - this.mods = mods ?? Array.Empty(); + this.beatmap = beatmap; + Current.Value = new StarDifficulty(beatmap.StarRating, 0); } /// - /// Creates a new that follows the currently-selected ruleset and mods. + /// Creates a new with no tooltip. /// - /// The beatmap to show the difficulty of. - /// Whether to display a tooltip when hovered. - /// Whether to perform difficulty lookup (including calculation if necessary). - public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true) + /// The ruleset to be used for the icon display. + public DifficultyIcon(IRulesetInfo ruleset) { - this.beatmapInfo = beatmapInfo ?? throw new ArgumentNullException(nameof(beatmapInfo)); - this.shouldShowTooltip = shouldShowTooltip; - this.performBackgroundDifficultyLookup = performBackgroundDifficultyLookup; + this.ruleset = ruleset; AutoSizeAxes = Axes.Both; - InternalChild = iconContainer = new Container { Size = new Vector2(20f) }; } @@ -111,7 +94,6 @@ namespace osu.Game.Beatmaps.Drawables Child = background = new Box { RelativeSizeAxes = Axes.Both, - Colour = colours.ForStarDifficulty(beatmapInfo.StarRating) // Default value that will be re-populated once difficulty calculation completes }, }, new ConstrainedIconContainer @@ -124,25 +106,12 @@ namespace osu.Game.Beatmaps.Drawables }, }; - if (performBackgroundDifficultyLookup) - iconContainer.Add(new DelayedLoadUnloadWrapper(createDifficultyRetriever, 0)); - else - difficultyBindable.Value = new StarDifficulty(beatmapInfo.StarRating, 0); - - difficultyBindable.BindValueChanged(difficulty => background.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars)); - } - - private Drawable createDifficultyRetriever() - { - if (ruleset != null && mods != null) - return new DifficultyRetriever(beatmapInfo, ruleset, mods) { StarDifficulty = { BindTarget = difficultyBindable } }; - - return new DifficultyRetriever(beatmapInfo) { StarDifficulty = { BindTarget = difficultyBindable } }; + Current.BindValueChanged(difficulty => background.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars), true); } private Drawable getRulesetIcon() { - int? onlineID = (ruleset ?? beatmapInfo.Ruleset).OnlineID; + int? onlineID = ruleset.OnlineID; if (onlineID >= 0 && rulesets.GetRuleset(onlineID.Value)?.CreateInstance() is Ruleset rulesetInstance) return rulesetInstance.CreateIcon(); @@ -154,6 +123,6 @@ namespace osu.Game.Beatmaps.Drawables GetCustomTooltip() => new DifficultyIconTooltip(); DifficultyIconTooltipContent IHasCustomTooltip. - TooltipContent => shouldShowTooltip ? new DifficultyIconTooltipContent(beatmapInfo, difficultyBindable) : null; + TooltipContent => (beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current) : null)!; } } diff --git a/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs index 15ca4c60d4..a713592246 100644 --- a/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs @@ -19,7 +19,7 @@ namespace osu.Game.Beatmaps.Drawables /// /// Used in cases when there are too many difficulty icons to show. /// - public class GroupedDifficultyIcon : DifficultyIcon + public class GroupedDifficultyIcon : CalculatingDifficultyIcon { public GroupedDifficultyIcon(IEnumerable beatmaps, IRulesetInfo ruleset, Color4 counterColour) : base(beatmaps.OrderBy(b => b.StarRating).Last(), ruleset, null, false) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 8d89bb3cc7..2efdb71204 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -274,8 +274,9 @@ namespace osu.Game.Overlays.BeatmapSet Alpha = 0.5f } }, - icon = new DifficultyIcon(beatmapInfo, shouldShowTooltip: false) + icon = new DifficultyIcon(beatmapInfo.Ruleset) { + Current = { Value = new StarDifficulty(beatmapInfo.StarRating, 0) }, Anchor = Anchor.Centre, Origin = Anchor.Centre, Size = new Vector2(size - tile_icon_padding * 2), diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 53519b8b00..a3a176477e 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -266,7 +266,7 @@ namespace osu.Game.Screens.OnlinePlay } if (beatmap != null) - difficultyIconContainer.Child = new DifficultyIcon(beatmap, ruleset, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(icon_height) }; + difficultyIconContainer.Child = new DifficultyIcon(beatmap, ruleset) { Size = new Vector2(icon_height) }; else difficultyIconContainer.Clear(); diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index 1bea689e7c..79eee63172 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -113,7 +113,7 @@ namespace osu.Game.Screens.Select.Carousel Origin = Anchor.CentreLeft, Children = new Drawable[] { - new DifficultyIcon(beatmapInfo, shouldShowTooltip: false) + new CalculatingDifficultyIcon(beatmapInfo, shouldShowTooltip: false) { Scale = new Vector2(1.8f), }, diff --git a/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs b/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs index b0841caa47..3f7d5c13ad 100644 --- a/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs +++ b/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs @@ -10,7 +10,7 @@ using osu.Game.Beatmaps.Drawables; namespace osu.Game.Screens.Select.Carousel { - public class FilterableDifficultyIcon : DifficultyIcon + public class FilterableDifficultyIcon : CalculatingDifficultyIcon { private readonly BindableBool filtered = new BindableBool(); @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Select.Carousel public readonly CarouselBeatmap Item; public FilterableDifficultyIcon(CarouselBeatmap item) - : base(item.BeatmapInfo, performBackgroundDifficultyLookup: false) + : base(item.BeatmapInfo) { filtered.BindTo(item.Filtered); filtered.ValueChanged += isFiltered => Schedule(() => this.FadeTo(isFiltered.NewValue ? 0.1f : 1, 100)); diff --git a/osu.Game/Screens/Select/Carousel/SetPanelContent.cs b/osu.Game/Screens/Select/Carousel/SetPanelContent.cs index 73a835d67f..c5e5a70d59 100644 --- a/osu.Game/Screens/Select/Carousel/SetPanelContent.cs +++ b/osu.Game/Screens/Select/Carousel/SetPanelContent.cs @@ -73,7 +73,7 @@ namespace osu.Game.Screens.Select.Carousel TextPadding = new MarginPadding { Horizontal = 8, Vertical = 2 }, Status = beatmapSet.Status }, - new FillFlowContainer + new FillFlowContainer { AutoSizeAxes = Axes.Both, Spacing = new Vector2(3), @@ -87,13 +87,13 @@ namespace osu.Game.Screens.Select.Carousel private const int maximum_difficulty_icons = 18; - private IEnumerable getDifficultyIcons() + private IEnumerable getDifficultyIcons() { var beatmaps = carouselSet.Beatmaps.ToList(); return beatmaps.Count > maximum_difficulty_icons - ? (IEnumerable)beatmaps.GroupBy(b => b.BeatmapInfo.Ruleset) - .Select(group => new FilterableGroupedDifficultyIcon(group.ToList(), group.Last().BeatmapInfo.Ruleset)) + ? (IEnumerable)beatmaps.GroupBy(b => b.BeatmapInfo.Ruleset) + .Select(group => new FilterableGroupedDifficultyIcon(group.ToList(), group.Last().BeatmapInfo.Ruleset)) : beatmaps.Select(b => new FilterableDifficultyIcon(b)); } } From 01da6f20b380923a196885e4a789fd29d21e668e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Jun 2022 18:53:21 +0900 Subject: [PATCH 138/211] Tidy up all remaining usages --- .../SongSelect/TestScenePlaySongSelect.cs | 4 +- .../Drawables/CalculatingDifficultyIcon.cs | 40 ++++--------------- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 9 ++++- .../Beatmaps/Drawables/DifficultyRetriever.cs | 2 - .../Drawables/GroupedDifficultyIcon.cs | 39 ------------------ .../Carousel/DrawableCarouselBeatmap.cs | 3 +- .../Carousel/FilterableDifficultyIcon.cs | 2 +- ...icultyIcon.cs => GroupedDifficultyIcon.cs} | 25 ++++++++++-- .../Select/Carousel/SetPanelContent.cs | 8 ++-- 9 files changed, 46 insertions(+), 86 deletions(-) delete mode 100644 osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs rename osu.Game/Screens/Select/Carousel/{FilterableGroupedDifficultyIcon.cs => GroupedDifficultyIcon.cs} (53%) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 9fcd470d17..6d881555da 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -872,10 +872,10 @@ namespace osu.Game.Tests.Visual.SongSelect return set != null; }); - FilterableGroupedDifficultyIcon groupIcon = null; + GroupedDifficultyIcon groupIcon = null; AddUntilStep("Find group icon for different ruleset", () => { - return (groupIcon = set.ChildrenOfType() + return (groupIcon = set.ChildrenOfType() .FirstOrDefault(icon => icon.Items.First().BeatmapInfo.Ruleset.OnlineID == 3)) != null; }); diff --git a/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs index 5f914f446c..f8304226e5 100644 --- a/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs @@ -1,13 +1,9 @@ -#nullable enable -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; using osuTK; namespace osu.Game.Beatmaps.Drawables @@ -26,30 +22,16 @@ namespace osu.Game.Beatmaps.Drawables set => difficultyIcon.Size = value; } - private readonly IRulesetInfo? ruleset; - - private readonly IReadOnlyList? mods; + public bool ShowTooltip + { + get => difficultyIcon.ShowTooltip; + set => difficultyIcon.ShowTooltip = value; + } private readonly IBeatmapInfo beatmapInfo; private readonly DifficultyIcon difficultyIcon; - /// - /// Creates a new with a given and combination. - /// - /// The beatmap to show the difficulty of. - /// The ruleset to show the difficulty with. - /// The mods to show the difficulty with. - /// Whether to display a tooltip when hovered. - /// Whether to perform difficulty lookup (including calculation if necessary). - public CalculatingDifficultyIcon(IBeatmapInfo beatmapInfo, IRulesetInfo? ruleset, IReadOnlyList? mods, bool shouldShowTooltip = true, - bool performBackgroundDifficultyLookup = true) - : this(beatmapInfo, shouldShowTooltip, performBackgroundDifficultyLookup) - { - this.ruleset = ruleset ?? beatmapInfo.Ruleset; - this.mods = mods ?? Array.Empty(); - } - /// /// Creates a new that follows the currently-selected ruleset and mods. /// @@ -64,17 +46,11 @@ namespace osu.Game.Beatmaps.Drawables InternalChildren = new Drawable[] { - difficultyIcon = new DifficultyIcon(beatmapInfo, beatmapInfo.Ruleset), + difficultyIcon = new DifficultyIcon(beatmapInfo), new DelayedLoadUnloadWrapper(createDifficultyRetriever, 0) }; } - private Drawable createDifficultyRetriever() - { - if (ruleset != null && mods != null) - return new DifficultyRetriever(beatmapInfo, ruleset, mods) { StarDifficulty = { BindTarget = difficultyIcon.Current } }; - - return new DifficultyRetriever(beatmapInfo) { StarDifficulty = { BindTarget = difficultyIcon.Current } }; - } + private Drawable createDifficultyRetriever() => new DifficultyRetriever(beatmapInfo) { StarDifficulty = { BindTarget = difficultyIcon.Current } }; } } diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index d1b15cba76..03ff0b29b0 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -30,6 +30,11 @@ namespace osu.Game.Beatmaps.Drawables set => iconContainer.Size = value; } + /// + /// Whether to display a tooltip on hover. Only works if a beatmap was provided at construction time. + /// + public bool ShowTooltip { get; set; } = true; + private readonly IBeatmapInfo? beatmap; private readonly IRulesetInfo ruleset; @@ -54,7 +59,7 @@ namespace osu.Game.Beatmaps.Drawables /// /// The beatmap to be displayed in the tooltip, and to be used for the initial star rating value. /// An optional ruleset to be used for the icon display, in place of the beatmap's ruleset. - public DifficultyIcon(IBeatmapInfo beatmap, IRulesetInfo? ruleset) + public DifficultyIcon(IBeatmapInfo beatmap, IRulesetInfo? ruleset = null) : this(ruleset ?? beatmap.Ruleset) { this.beatmap = beatmap; @@ -123,6 +128,6 @@ namespace osu.Game.Beatmaps.Drawables GetCustomTooltip() => new DifficultyIconTooltip(); DifficultyIconTooltipContent IHasCustomTooltip. - TooltipContent => (beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current) : null)!; + TooltipContent => (ShowTooltip && beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current) : null)!; } } diff --git a/osu.Game/Beatmaps/Drawables/DifficultyRetriever.cs b/osu.Game/Beatmaps/Drawables/DifficultyRetriever.cs index a993f0657b..90ef89ee36 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyRetriever.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyRetriever.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable enable - using System.Collections.Generic; using System.Threading; using osu.Framework.Allocation; diff --git a/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs deleted file mode 100644 index a713592246..0000000000 --- a/osu.Game/Beatmaps/Drawables/GroupedDifficultyIcon.cs +++ /dev/null @@ -1,39 +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 disable - -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Graphics; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Rulesets; -using osuTK.Graphics; - -namespace osu.Game.Beatmaps.Drawables -{ - /// - /// A difficulty icon that contains a counter on the right-side of it. - /// - /// - /// Used in cases when there are too many difficulty icons to show. - /// - public class GroupedDifficultyIcon : CalculatingDifficultyIcon - { - public GroupedDifficultyIcon(IEnumerable beatmaps, IRulesetInfo ruleset, Color4 counterColour) - : base(beatmaps.OrderBy(b => b.StarRating).Last(), ruleset, null, false) - { - AddInternal(new OsuSpriteText - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Padding = new MarginPadding { Left = Size.X }, - Margin = new MarginPadding { Left = 2, Right = 5 }, - Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold), - Text = beatmaps.Count().ToString(), - Colour = counterColour, - }); - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index 79eee63172..e5fe03f929 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -113,8 +113,9 @@ namespace osu.Game.Screens.Select.Carousel Origin = Anchor.CentreLeft, Children = new Drawable[] { - new CalculatingDifficultyIcon(beatmapInfo, shouldShowTooltip: false) + new CalculatingDifficultyIcon(beatmapInfo) { + ShowTooltip = false, Scale = new Vector2(1.8f), }, new FillFlowContainer diff --git a/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs b/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs index 3f7d5c13ad..cc904fc1da 100644 --- a/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs +++ b/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs @@ -10,7 +10,7 @@ using osu.Game.Beatmaps.Drawables; namespace osu.Game.Screens.Select.Carousel { - public class FilterableDifficultyIcon : CalculatingDifficultyIcon + public class FilterableDifficultyIcon : DifficultyIcon { private readonly BindableBool filtered = new BindableBool(); diff --git a/osu.Game/Screens/Select/Carousel/FilterableGroupedDifficultyIcon.cs b/osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs similarity index 53% rename from osu.Game/Screens/Select/Carousel/FilterableGroupedDifficultyIcon.cs rename to osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs index f883740fd7..8b4140df56 100644 --- a/osu.Game/Screens/Select/Carousel/FilterableGroupedDifficultyIcon.cs +++ b/osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs @@ -8,23 +8,42 @@ using System.Linq; using osu.Framework.Graphics; using osu.Framework.Input.Events; using osu.Game.Beatmaps.Drawables; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; using osu.Game.Rulesets; using osuTK.Graphics; namespace osu.Game.Screens.Select.Carousel { - public class FilterableGroupedDifficultyIcon : GroupedDifficultyIcon + /// + /// A difficulty icon that contains a counter on the right-side of it. + /// + /// + /// Used in cases when there are too many difficulty icons to show. + /// + public class GroupedDifficultyIcon : DifficultyIcon { public readonly List Items; - public FilterableGroupedDifficultyIcon(List items, RulesetInfo ruleset) - : base(items.Select(i => i.BeatmapInfo).ToList(), ruleset, Color4.White) + public GroupedDifficultyIcon(List items, RulesetInfo ruleset) + : base(items.OrderBy(b => b.BeatmapInfo.StarRating).Last().BeatmapInfo, ruleset) { Items = items; foreach (var item in items) item.Filtered.BindValueChanged(_ => Scheduler.AddOnce(updateFilteredDisplay)); + AddInternal(new OsuSpriteText + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Padding = new MarginPadding { Left = Size.X }, + Margin = new MarginPadding { Left = 2, Right = 5 }, + Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold), + Text = items.Count.ToString(), + Colour = Color4.White, + }); + updateFilteredDisplay(); } diff --git a/osu.Game/Screens/Select/Carousel/SetPanelContent.cs b/osu.Game/Screens/Select/Carousel/SetPanelContent.cs index c5e5a70d59..cc3d722852 100644 --- a/osu.Game/Screens/Select/Carousel/SetPanelContent.cs +++ b/osu.Game/Screens/Select/Carousel/SetPanelContent.cs @@ -73,7 +73,7 @@ namespace osu.Game.Screens.Select.Carousel TextPadding = new MarginPadding { Horizontal = 8, Vertical = 2 }, Status = beatmapSet.Status }, - new FillFlowContainer + new FillFlowContainer { AutoSizeAxes = Axes.Both, Spacing = new Vector2(3), @@ -87,13 +87,13 @@ namespace osu.Game.Screens.Select.Carousel private const int maximum_difficulty_icons = 18; - private IEnumerable getDifficultyIcons() + private IEnumerable getDifficultyIcons() { var beatmaps = carouselSet.Beatmaps.ToList(); return beatmaps.Count > maximum_difficulty_icons - ? (IEnumerable)beatmaps.GroupBy(b => b.BeatmapInfo.Ruleset) - .Select(group => new FilterableGroupedDifficultyIcon(group.ToList(), group.Last().BeatmapInfo.Ruleset)) + ? (IEnumerable)beatmaps.GroupBy(b => b.BeatmapInfo.Ruleset) + .Select(group => new GroupedDifficultyIcon(group.ToList(), group.Last().BeatmapInfo.Ruleset)) : beatmaps.Select(b => new FilterableDifficultyIcon(b)); } } From 32652ace75b2a3954e359f4af915385b77262b8e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Jun 2022 19:51:44 +0900 Subject: [PATCH 139/211] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index caea787e22..f2790d2520 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 652dc2740f..0802a98858 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 0c3c38f9f0..a272df20d4 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + From b068df21497cba26067b98ed8d7356634421fb5e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Jun 2022 19:44:38 +0900 Subject: [PATCH 140/211] Enable NRT on `BeatmapDiffiultyCache` --- osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 45 +++++++++------------ 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index 69488277f1..b6314f5841 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -1,15 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; @@ -50,19 +47,19 @@ namespace osu.Game.Beatmaps /// private readonly object bindableUpdateLock = new object(); - private CancellationTokenSource trackedUpdateCancellationSource; + private CancellationTokenSource trackedUpdateCancellationSource = new CancellationTokenSource(); [Resolved] - private BeatmapManager beatmapManager { get; set; } + private BeatmapManager beatmapManager { get; set; } = null!; [Resolved] - private Bindable currentRuleset { get; set; } + private Bindable currentRuleset { get; set; } = null!; [Resolved] - private Bindable> currentMods { get; set; } + private Bindable> currentMods { get; set; } = null!; - private ModSettingChangeTracker modSettingChangeTracker; - private ScheduledDelegate debouncedModSettingsChange; + private ModSettingChangeTracker? modSettingChangeTracker; + private ScheduledDelegate? debouncedModSettingsChange; protected override void LoadComplete() { @@ -91,7 +88,7 @@ namespace osu.Game.Beatmaps /// The to get the difficulty of. /// An optional which stops updating the star difficulty for the given . /// A bindable that is updated to contain the star difficulty when it becomes available. Will be null while in an initial calculating state (but not during updates to ruleset and mods if a stale value is already propagated). - public IBindable GetBindableDifficulty([NotNull] IBeatmapInfo beatmapInfo, CancellationToken cancellationToken = default) + public IBindable GetBindableDifficulty(IBeatmapInfo beatmapInfo, CancellationToken cancellationToken = default) { var bindable = createBindable(beatmapInfo, currentRuleset.Value, currentMods.Value, cancellationToken); @@ -112,7 +109,7 @@ namespace osu.Game.Beatmaps /// The s to get the difficulty with. If null, no mods will be assumed. /// An optional which stops updating the star difficulty for the given . /// A bindable that is updated to contain the star difficulty when it becomes available. Will be null while in an initial calculating state. - public IBindable GetBindableDifficulty([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo rulesetInfo, [CanBeNull] IEnumerable mods, + public IBindable GetBindableDifficulty(IBeatmapInfo beatmapInfo, IRulesetInfo? rulesetInfo, IEnumerable? mods, CancellationToken cancellationToken = default) => createBindable(beatmapInfo, rulesetInfo, mods, cancellationToken); @@ -128,8 +125,8 @@ namespace osu.Game.Beatmaps /// A return value indicates that the difficulty process failed or was interrupted early, /// and as such there is no usable star difficulty value to be returned. /// - public virtual Task GetDifficultyAsync([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo rulesetInfo = null, - [CanBeNull] IEnumerable mods = null, CancellationToken cancellationToken = default) + public virtual Task GetDifficultyAsync(IBeatmapInfo beatmapInfo, IRulesetInfo? rulesetInfo = null, + IEnumerable? mods = null, CancellationToken cancellationToken = default) { // In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset. rulesetInfo ??= beatmapInfo.Ruleset; @@ -204,7 +201,6 @@ namespace osu.Game.Beatmaps lock (bindableUpdateLock) { cancelTrackedBindableUpdate(); - trackedUpdateCancellationSource = new CancellationTokenSource(); foreach (var b in trackedBindables) { @@ -223,16 +219,13 @@ namespace osu.Game.Beatmaps { lock (bindableUpdateLock) { - trackedUpdateCancellationSource?.Cancel(); - trackedUpdateCancellationSource = null; + trackedUpdateCancellationSource.Cancel(); + trackedUpdateCancellationSource = new CancellationTokenSource(); - if (linkedCancellationSources != null) - { - foreach (var c in linkedCancellationSources) - c.Dispose(); + foreach (var c in linkedCancellationSources) + c.Dispose(); - linkedCancellationSources.Clear(); - } + linkedCancellationSources.Clear(); } } @@ -244,7 +237,7 @@ namespace osu.Game.Beatmaps /// The initial s to get the difficulty with. /// An optional which stops updating the star difficulty for the given . /// The . - private BindableStarDifficulty createBindable([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo initialRulesetInfo, [CanBeNull] IEnumerable initialMods, + private BindableStarDifficulty createBindable(IBeatmapInfo beatmapInfo, IRulesetInfo? initialRulesetInfo, IEnumerable? initialMods, CancellationToken cancellationToken) { var bindable = new BindableStarDifficulty(beatmapInfo, cancellationToken); @@ -259,7 +252,7 @@ namespace osu.Game.Beatmaps /// The to update with. /// The s to update with. /// A token that may be used to cancel this update. - private void updateBindable([NotNull] BindableStarDifficulty bindable, [CanBeNull] IRulesetInfo rulesetInfo, [CanBeNull] IEnumerable mods, CancellationToken cancellationToken = default) + private void updateBindable(BindableStarDifficulty bindable, IRulesetInfo? rulesetInfo, IEnumerable? mods, CancellationToken cancellationToken = default) { // GetDifficultyAsync will fall back to existing data from IBeatmapInfo if not locally available // (contrary to GetAsync) @@ -329,7 +322,7 @@ namespace osu.Game.Beatmaps modSettingChangeTracker?.Dispose(); cancelTrackedBindableUpdate(); - updateScheduler?.Dispose(); + updateScheduler.Dispose(); } public readonly struct DifficultyCacheLookup : IEquatable @@ -339,7 +332,7 @@ namespace osu.Game.Beatmaps public readonly Mod[] OrderedMods; - public DifficultyCacheLookup([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo ruleset, IEnumerable mods) + public DifficultyCacheLookup(BeatmapInfo beatmapInfo, RulesetInfo? ruleset, IEnumerable? mods) { BeatmapInfo = beatmapInfo; // In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset. From ef258122d23b4c2fe1a24756f38e266a7597b2e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 23 Jun 2022 19:46:59 +0900 Subject: [PATCH 141/211] Move `GetDifficultyRating` helper method to `StarDifficulty` --- .../TestSceneBeatmapDifficultyCache.cs | 2 +- osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 29 ----------------- osu.Game/Beatmaps/EFBeatmapInfo.cs | 2 +- osu.Game/Beatmaps/StarDifficulty.cs | 31 ++++++++++++++++++- osu.Game/Screens/Edit/Verify/VerifyScreen.cs | 2 +- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs index f87e5711a6..6eb103316f 100644 --- a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs +++ b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs @@ -157,7 +157,7 @@ namespace osu.Game.Tests.Beatmaps [TestCase(8.3, DifficultyRating.ExpertPlus)] public void TestDifficultyRatingMapping(double starRating, DifficultyRating expectedBracket) { - var actualBracket = BeatmapDifficultyCache.GetDifficultyRating(starRating); + var actualBracket = StarDifficulty.GetDifficultyRating(starRating); Assert.AreEqual(expectedBracket, actualBracket); } diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index b6314f5841..5e468e975a 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -13,7 +13,6 @@ using osu.Framework.Extensions; using osu.Framework.Lists; using osu.Framework.Logging; using osu.Framework.Threading; -using osu.Framework.Utils; using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Rulesets; @@ -165,34 +164,6 @@ namespace osu.Game.Beatmaps updateScheduler); } - /// - /// Retrieves the that describes a star rating. - /// - /// - /// For more information, see: https://osu.ppy.sh/help/wiki/Difficulties - /// - /// The star rating. - /// The that best describes . - public static DifficultyRating GetDifficultyRating(double starRating) - { - if (Precision.AlmostBigger(starRating, 6.5, 0.005)) - return DifficultyRating.ExpertPlus; - - if (Precision.AlmostBigger(starRating, 5.3, 0.005)) - return DifficultyRating.Expert; - - if (Precision.AlmostBigger(starRating, 4.0, 0.005)) - return DifficultyRating.Insane; - - if (Precision.AlmostBigger(starRating, 2.7, 0.005)) - return DifficultyRating.Hard; - - if (Precision.AlmostBigger(starRating, 2.0, 0.005)) - return DifficultyRating.Normal; - - return DifficultyRating.Easy; - } - /// /// Updates all tracked using the current ruleset and mods. /// diff --git a/osu.Game/Beatmaps/EFBeatmapInfo.cs b/osu.Game/Beatmaps/EFBeatmapInfo.cs index 34311448eb..20abdc686a 100644 --- a/osu.Game/Beatmaps/EFBeatmapInfo.cs +++ b/osu.Game/Beatmaps/EFBeatmapInfo.cs @@ -128,7 +128,7 @@ namespace osu.Game.Beatmaps public List Scores { get; set; } [JsonIgnore] - public DifficultyRating DifficultyRating => BeatmapDifficultyCache.GetDifficultyRating(StarRating); + public DifficultyRating DifficultyRating => StarDifficulty.GetDifficultyRating(StarRating); public override string ToString() => this.GetDisplayTitle(); diff --git a/osu.Game/Beatmaps/StarDifficulty.cs b/osu.Game/Beatmaps/StarDifficulty.cs index 91bc3aacf6..e042f1c698 100644 --- a/osu.Game/Beatmaps/StarDifficulty.cs +++ b/osu.Game/Beatmaps/StarDifficulty.cs @@ -4,6 +4,7 @@ #nullable disable using JetBrains.Annotations; +using osu.Framework.Utils; using osu.Game.Rulesets.Difficulty; namespace osu.Game.Beatmaps @@ -50,6 +51,34 @@ namespace osu.Game.Beatmaps Attributes = null; } - public DifficultyRating DifficultyRating => BeatmapDifficultyCache.GetDifficultyRating(Stars); + public DifficultyRating DifficultyRating => GetDifficultyRating(Stars); + + /// + /// Retrieves the that describes a star rating. + /// + /// + /// For more information, see: https://osu.ppy.sh/help/wiki/Difficulties + /// + /// The star rating. + /// The that best describes . + public static DifficultyRating GetDifficultyRating(double starRating) + { + if (Precision.AlmostBigger(starRating, 6.5, 0.005)) + return DifficultyRating.ExpertPlus; + + if (Precision.AlmostBigger(starRating, 5.3, 0.005)) + return DifficultyRating.Expert; + + if (Precision.AlmostBigger(starRating, 4.0, 0.005)) + return DifficultyRating.Insane; + + if (Precision.AlmostBigger(starRating, 2.7, 0.005)) + return DifficultyRating.Hard; + + if (Precision.AlmostBigger(starRating, 2.0, 0.005)) + return DifficultyRating.Normal; + + return DifficultyRating.Easy; + } } } diff --git a/osu.Game/Screens/Edit/Verify/VerifyScreen.cs b/osu.Game/Screens/Edit/Verify/VerifyScreen.cs index d5b32760c9..3030018138 100644 --- a/osu.Game/Screens/Edit/Verify/VerifyScreen.cs +++ b/osu.Game/Screens/Edit/Verify/VerifyScreen.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Edit.Verify [BackgroundDependencyLoader] private void load() { - InterpretedDifficulty.Default = BeatmapDifficultyCache.GetDifficultyRating(EditorBeatmap.BeatmapInfo.StarRating); + InterpretedDifficulty.Default = StarDifficulty.GetDifficultyRating(EditorBeatmap.BeatmapInfo.StarRating); InterpretedDifficulty.SetDefault(); Child = new Container From 9c46592e0e45279e4a92d4f9b415b61b17510787 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 23 Jun 2022 20:04:54 +0900 Subject: [PATCH 142/211] Move collection change event binding to LoadComplete --- osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs b/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs index a314992287..4cf2c3778a 100644 --- a/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs +++ b/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs @@ -33,8 +33,10 @@ namespace osu.Game.Graphics.Containers protected abstract OsuRearrangeableListItem CreateOsuDrawable(TModel item); - protected OsuRearrangeableListContainer() + protected override void LoadComplete() { + base.LoadComplete(); + Items.CollectionChanged += (_, args) => { if (args.Action == NotifyCollectionChangedAction.Move) From aaf619b35c8d6b8642c6d89d83cdb74a4758df00 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 23 Jun 2022 20:13:01 +0900 Subject: [PATCH 143/211] Don't play sample if there is no item being actively dragged --- osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs b/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs index 4cf2c3778a..b604ae73eb 100644 --- a/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs +++ b/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs @@ -46,6 +46,9 @@ namespace osu.Game.Graphics.Containers private void playSwapSample() { + if (!DragActive.Value) + return; + if (Time.Current - sampleLastPlaybackTime <= 35) return; From eaae600a49b08299a96fdae2ec44b57712184758 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 24 Jun 2022 04:57:44 +0300 Subject: [PATCH 144/211] Fix typo in auto-import ignore rule --- osu.sln.DotSettings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index e732b25951..8fd750a50d 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -793,7 +793,7 @@ See the LICENCE file in the repository root for full licence text. <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> True - True + True True True True From 129c90709252aa6fc4dd11b69b0616fb4915dee8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 13:58:02 +0900 Subject: [PATCH 145/211] Remove unused parameters --- osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs index f8304226e5..2adba3ae99 100644 --- a/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs @@ -36,9 +36,7 @@ namespace osu.Game.Beatmaps.Drawables /// Creates a new that follows the currently-selected ruleset and mods. /// /// The beatmap to show the difficulty of. - /// Whether to display a tooltip when hovered. - /// Whether to perform difficulty lookup (including calculation if necessary). - public CalculatingDifficultyIcon(IBeatmapInfo beatmapInfo, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true) + public CalculatingDifficultyIcon(IBeatmapInfo beatmapInfo) { this.beatmapInfo = beatmapInfo ?? throw new ArgumentNullException(nameof(beatmapInfo)); From d9c1a9d71fd16c10601654af54e652533cbb7b0d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 13:59:17 +0900 Subject: [PATCH 146/211] Use new property to specify no tooltip, rather than passing only ruleset --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 4 ++-- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 03ff0b29b0..679e9c3665 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -55,7 +55,7 @@ namespace osu.Game.Beatmaps.Drawables private IRulesetStore rulesets { get; set; } = null!; /// - /// Creates a new with a tooltip. Will use provided beatmap's for initial value. + /// Creates a new . Will use provided beatmap's for initial value. /// /// The beatmap to be displayed in the tooltip, and to be used for the initial star rating value. /// An optional ruleset to be used for the icon display, in place of the beatmap's ruleset. @@ -67,7 +67,7 @@ namespace osu.Game.Beatmaps.Drawables } /// - /// Creates a new with no tooltip. + /// Creates a new without an associated beatmap. /// /// The ruleset to be used for the icon display. public DifficultyIcon(IRulesetInfo ruleset) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 2efdb71204..1a57a89957 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -274,8 +274,9 @@ namespace osu.Game.Overlays.BeatmapSet Alpha = 0.5f } }, - icon = new DifficultyIcon(beatmapInfo.Ruleset) + icon = new DifficultyIcon(beatmapInfo) { + ShowTooltip = false, Current = { Value = new StarDifficulty(beatmapInfo.StarRating, 0) }, Anchor = Anchor.Centre, Origin = Anchor.Centre, From 12ea8369ee504caddcaf38488cae09bfedb091b6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 14:06:31 +0900 Subject: [PATCH 147/211] Update retriever to be relatively sized --- .../Beatmaps/Drawables/CalculatingDifficultyIcon.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs index 2adba3ae99..df9766c891 100644 --- a/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osuTK; @@ -28,8 +27,6 @@ namespace osu.Game.Beatmaps.Drawables set => difficultyIcon.ShowTooltip = value; } - private readonly IBeatmapInfo beatmapInfo; - private readonly DifficultyIcon difficultyIcon; /// @@ -38,17 +35,16 @@ namespace osu.Game.Beatmaps.Drawables /// The beatmap to show the difficulty of. public CalculatingDifficultyIcon(IBeatmapInfo beatmapInfo) { - this.beatmapInfo = beatmapInfo ?? throw new ArgumentNullException(nameof(beatmapInfo)); - AutoSizeAxes = Axes.Both; InternalChildren = new Drawable[] { difficultyIcon = new DifficultyIcon(beatmapInfo), - new DelayedLoadUnloadWrapper(createDifficultyRetriever, 0) + new DelayedLoadUnloadWrapper(() => new DifficultyRetriever(beatmapInfo) { StarDifficulty = { BindTarget = difficultyIcon.Current } }, 0) + { + RelativeSizeAxes = Axes.Both, + } }; } - - private Drawable createDifficultyRetriever() => new DifficultyRetriever(beatmapInfo) { StarDifficulty = { BindTarget = difficultyIcon.Current } }; } } From 28837693e5a72ccf692df76a7bc231a473987c4b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 14:22:38 +0900 Subject: [PATCH 148/211] Nuke calculating everything The whole component is pointless so I'm just going to nuke for now I guess. Kind of makes the whole refactor effort pointless but oh well? To expand on this, the implementation was actually incorrect as pointed out at https://github.com/ppy/osu/pull/18819#pullrequestreview-1017886035. --- .../Drawables/CalculatingDifficultyIcon.cs | 50 ----------- .../Beatmaps/Drawables/DifficultyRetriever.cs | 83 ------------------- .../Carousel/DrawableCarouselBeatmap.cs | 6 +- 3 files changed, 5 insertions(+), 134 deletions(-) delete mode 100644 osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs delete mode 100644 osu.Game/Beatmaps/Drawables/DifficultyRetriever.cs diff --git a/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs deleted file mode 100644 index df9766c891..0000000000 --- a/osu.Game/Beatmaps/Drawables/CalculatingDifficultyIcon.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osuTK; - -namespace osu.Game.Beatmaps.Drawables -{ - /// - /// A difficulty icon which automatically calculates difficulty in the background. - /// - public class CalculatingDifficultyIcon : CompositeDrawable - { - /// - /// Size of this difficulty icon. - /// - public new Vector2 Size - { - get => difficultyIcon.Size; - set => difficultyIcon.Size = value; - } - - public bool ShowTooltip - { - get => difficultyIcon.ShowTooltip; - set => difficultyIcon.ShowTooltip = value; - } - - private readonly DifficultyIcon difficultyIcon; - - /// - /// Creates a new that follows the currently-selected ruleset and mods. - /// - /// The beatmap to show the difficulty of. - public CalculatingDifficultyIcon(IBeatmapInfo beatmapInfo) - { - AutoSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] - { - difficultyIcon = new DifficultyIcon(beatmapInfo), - new DelayedLoadUnloadWrapper(() => new DifficultyRetriever(beatmapInfo) { StarDifficulty = { BindTarget = difficultyIcon.Current } }, 0) - { - RelativeSizeAxes = Axes.Both, - } - }; - } - } -} diff --git a/osu.Game/Beatmaps/Drawables/DifficultyRetriever.cs b/osu.Game/Beatmaps/Drawables/DifficultyRetriever.cs deleted file mode 100644 index 90ef89ee36..0000000000 --- a/osu.Game/Beatmaps/Drawables/DifficultyRetriever.cs +++ /dev/null @@ -1,83 +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.Collections.Generic; -using System.Threading; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; - -namespace osu.Game.Beatmaps.Drawables -{ - /// - /// A component solely responsible for calculating difficulty in the background. - /// Intended for use with to only run processing when usage is on-screen. - /// - public class DifficultyRetriever : Component - { - /// - /// The bindable star difficulty. - /// - public IBindable StarDifficulty => starDifficulty; - - private readonly Bindable starDifficulty = new Bindable(); - - private readonly IBeatmapInfo beatmapInfo; - - private readonly IRulesetInfo? ruleset; - private readonly IReadOnlyList? mods; - - private readonly CancellationTokenSource difficultyCancellation = new CancellationTokenSource(); - - [Resolved] - private BeatmapDifficultyCache difficultyCache { get; set; } = null!; - - /// - /// Construct a difficulty retriever that tracks the current ruleset / mod selection. - /// - /// The beatmap to use for calculation. - public DifficultyRetriever(IBeatmapInfo beatmapInfo) - { - this.beatmapInfo = beatmapInfo; - } - - /// - /// Construct a difficulty retriever that is calculated only once for the specified ruleset / mod combination. - /// This will not track global ruleset and mod changes. - /// - /// The beatmap to use for calculation. - /// The ruleset to use for calculation. - /// The mods to use for calculation. - public DifficultyRetriever(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, IReadOnlyList mods) - { - this.beatmapInfo = beatmapInfo; - this.ruleset = ruleset; - this.mods = mods; - } - - private IBindable localStarDifficulty = null!; - - [BackgroundDependencyLoader] - private void load() - { - localStarDifficulty = ruleset != null - ? difficultyCache.GetBindableDifficulty(beatmapInfo, ruleset, mods, difficultyCancellation.Token) - : difficultyCache.GetBindableDifficulty(beatmapInfo, difficultyCancellation.Token); - - localStarDifficulty.BindValueChanged(d => - { - if (d.NewValue is StarDifficulty diff) - starDifficulty.Value = diff; - }); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - difficultyCancellation.Cancel(); - } - } -} diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index e5fe03f929..1b3cab20e8 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -53,7 +53,9 @@ namespace osu.Game.Screens.Select.Carousel private Action hideRequested; private Triangles triangles; + private StarCounter starCounter; + private DifficultyIcon difficultyIcon; [Resolved(CanBeNull = true)] private BeatmapSetOverlay beatmapOverlay { get; set; } @@ -113,7 +115,7 @@ namespace osu.Game.Screens.Select.Carousel Origin = Anchor.CentreLeft, Children = new Drawable[] { - new CalculatingDifficultyIcon(beatmapInfo) + difficultyIcon = new DifficultyIcon(beatmapInfo) { ShowTooltip = false, Scale = new Vector2(1.8f), @@ -217,6 +219,8 @@ namespace osu.Game.Screens.Select.Carousel starDifficultyBindable.BindValueChanged(d => { starCounter.Current = (float)(d.NewValue?.Stars ?? 0); + if (d.NewValue != null) + difficultyIcon.Current.Value = d.NewValue.Value; }, true); } From f4173a3bff4a170e78e6215a6a82a556798bee31 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 14:48:32 +0900 Subject: [PATCH 149/211] Update c# language version to 10 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index dbc84fb88f..1f59f19eaa 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@  - 8.0 + 10.0 true enable From f71f6302fd494ec8d12136f6709f36b705ac70ab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 14:48:43 +0900 Subject: [PATCH 150/211] Remove unnecessary `null` casts --- osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs | 2 +- osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs | 4 ++-- osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs | 2 +- .../Visual/UserInterface/TestSceneLabelledDrawable.cs | 2 +- .../Visual/UserInterface/TestSceneOsuAnimatedButton.cs | 3 +-- osu.Game.Tests/Visual/UserInterface/TestSceneOsuButton.cs | 3 +-- osu.Game/Graphics/Containers/ScalingContainer.cs | 2 +- osu.Game/Graphics/UserInterface/ShearedToggleButton.cs | 3 +-- osu.Game/Graphics/UserInterface/ToggleMenuItem.cs | 2 +- osu.Game/OsuGameBase.cs | 4 ++-- osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs | 4 ++-- osu.Game/Overlays/Mods/ModColumn.cs | 2 +- osu.Game/Overlays/Mods/ModPanel.cs | 6 +++--- osu.Game/Rulesets/EFRulesetInfo.cs | 2 +- osu.Game/Rulesets/Objects/SliderPath.cs | 2 +- osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs | 2 +- .../Screens/Edit/Components/Menus/DifficultyMenuItem.cs | 2 +- .../Edit/Compose/Components/Timeline/SamplePointPiece.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/Play/MasterGameplayClockContainer.cs | 2 +- osu.Game/Screens/Select/Carousel/SetPanelContent.cs | 4 ++-- osu.Game/Screens/Utility/LatencyCertifierScreen.cs | 4 ++-- osu.Game/Storyboards/CommandTimelineGroup.cs | 2 +- 23 files changed, 30 insertions(+), 33 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs index be2e9c7cb5..5706955fc5 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs @@ -161,7 +161,7 @@ namespace osu.Game.Rulesets.Osu.Tests => addCheckPositionChangeSteps(timeAtRepeat(startTime, repeatIndex), positionAtRepeat(repeatIndex), positionRemainsSame); private Func timeAtRepeat(Func startTime, int repeatIndex) => () => startTime() + 100 + duration_of_span * repeatIndex; - private Func positionAtRepeat(int repeatIndex) => repeatIndex % 2 == 0 ? (Func)getSliderStart : getSliderEnd; + private Func positionAtRepeat(int repeatIndex) => repeatIndex % 2 == 0 ? getSliderStart : getSliderEnd; private List getSliderCurve() => ((PlaySliderBody)drawableSlider.Body.Drawable).CurrentCurve; private Vector2 getSliderStart() => getSliderCurve().First(); diff --git a/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs b/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs index 4a5bb6de46..541ad1e8bb 100644 --- a/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs +++ b/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs @@ -364,12 +364,12 @@ namespace osu.Game.Tests.NonVisual private void confirmCurrentFrame(int? frame) { - Assert.AreEqual(frame is int x ? replay.Frames[x].Time : (double?)null, handler.CurrentFrame?.Time, "Unexpected current frame"); + Assert.AreEqual(frame is int x ? replay.Frames[x].Time : null, handler.CurrentFrame?.Time, "Unexpected current frame"); } private void confirmNextFrame(int? frame) { - Assert.AreEqual(frame is int x ? replay.Frames[x].Time : (double?)null, handler.NextFrame?.Time, "Unexpected next frame"); + Assert.AreEqual(frame is int x ? replay.Frames[x].Time : null, handler.NextFrame?.Time, "Unexpected next frame"); } private class TestReplayFrame : ReplayFrame diff --git a/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs b/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs index 77ceef6402..1493c10969 100644 --- a/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs +++ b/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs @@ -58,7 +58,7 @@ namespace osu.Game.Tests.Skins { AddStep($"Set beatmap skin enabled to {allowBeatmapLookups}", () => config.SetValue(OsuSetting.BeatmapSkins, allowBeatmapLookups)); - ISkin expected() => allowBeatmapLookups ? (ISkin)beatmapSource : userSource; + ISkin expected() => allowBeatmapLookups ? beatmapSource : userSource; AddAssert("Check lookup is from correct source", () => requester.FindProvider(s => s.GetDrawableComponent(new TestSkinComponent()) != null) == expected()); } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs index f717bb4dee..7ce0fceff9 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs @@ -78,7 +78,7 @@ namespace osu.Game.Tests.Visual.UserInterface Origin = Anchor.Centre, Width = 500, AutoSizeAxes = Axes.Y, - Child = component = padded ? (LabelledDrawable)new PaddedLabelledDrawable() : new NonPaddedLabelledDrawable(), + Child = component = padded ? new PaddedLabelledDrawable() : new NonPaddedLabelledDrawable(), }; component.Label = "a sample component"; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuAnimatedButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuAnimatedButton.cs index 28599c740e..bab2121d70 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuAnimatedButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuAnimatedButton.cs @@ -3,7 +3,6 @@ #nullable disable -using System; using NUnit.Framework; using osu.Framework.Graphics; using osu.Game.Graphics.Sprites; @@ -89,7 +88,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddToggleStep("toggle enabled", toggle => { for (int i = 0; i < 6; i++) - button.Action = toggle ? () => { } : (Action)null; + button.Action = toggle ? () => { } : null; }); } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuButton.cs index 0e31a133ac..d4c2bfd422 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuButton.cs @@ -3,7 +3,6 @@ #nullable disable -using System; using NUnit.Framework; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; @@ -29,7 +28,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddToggleStep("toggle enabled", toggle => { for (int i = 0; i < 6; i++) - button.Action = toggle ? () => { } : (Action)null; + button.Action = toggle ? () => { } : null; }); } diff --git a/osu.Game/Graphics/Containers/ScalingContainer.cs b/osu.Game/Graphics/Containers/ScalingContainer.cs index 5c8579a144..17c51129a7 100644 --- a/osu.Game/Graphics/Containers/ScalingContainer.cs +++ b/osu.Game/Graphics/Containers/ScalingContainer.cs @@ -260,7 +260,7 @@ namespace osu.Game.Graphics.Containers if (host.Window == null) return; bool coversWholeScreen = Size == Vector2.One && safeArea.SafeAreaPadding.Value.Total == Vector2.Zero; - host.Window.CursorConfineRect = coversWholeScreen ? (RectangleF?)null : ToScreenSpace(DrawRectangle).AABBFloat; + host.Window.CursorConfineRect = coversWholeScreen ? null : ToScreenSpace(DrawRectangle).AABBFloat; } } } diff --git a/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs b/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs index 50682ddfe0..0bbcb2b976 100644 --- a/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs +++ b/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -47,7 +46,7 @@ namespace osu.Game.Graphics.UserInterface protected override void LoadComplete() { - Active.BindDisabledChanged(disabled => Action = disabled ? (Action?)null : Active.Toggle, true); + Active.BindDisabledChanged(disabled => Action = disabled ? null : Active.Toggle, true); Active.BindValueChanged(_ => { updateActiveState(); diff --git a/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs b/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs index 9d1650c970..6787e17113 100644 --- a/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs @@ -34,6 +34,6 @@ namespace osu.Game.Graphics.UserInterface { } - public override IconUsage? GetIconForState(bool state) => state ? (IconUsage?)FontAwesome.Solid.Check : null; + public override IconUsage? GetIconForState(bool state) => state ? FontAwesome.Solid.Check : null; } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 7bbad3bb72..1d9e2042ec 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -89,7 +89,7 @@ namespace osu.Game public virtual bool UseDevelopmentServer => DebugUtils.IsDebugBuild; internal EndpointConfiguration CreateEndpoints() => - UseDevelopmentServer ? (EndpointConfiguration)new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration(); + UseDevelopmentServer ? new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration(); public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(); @@ -583,6 +583,6 @@ namespace osu.Game ControlPointInfo IBeatSyncProvider.ControlPoints => Beatmap.Value.Beatmap.ControlPointInfo; IClock IBeatSyncProvider.Clock => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track : (IClock)null; - ChannelAmplitudes? IBeatSyncProvider.Amplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : (ChannelAmplitudes?)null; + ChannelAmplitudes? IBeatSyncProvider.Amplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : null; } } diff --git a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs index a6f412c00a..8cedd6b374 100644 --- a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs +++ b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs @@ -46,8 +46,8 @@ namespace osu.Game.Overlays.Mods && !ModUtils.CheckCompatibleSet(selectedMods.Value.Append(Mod)); } - protected override Colour4 BackgroundColour => incompatible.Value ? (Colour4)ColourProvider.Background6 : base.BackgroundColour; - protected override Colour4 ForegroundColour => incompatible.Value ? (Colour4)ColourProvider.Background5 : base.ForegroundColour; + protected override Colour4 BackgroundColour => incompatible.Value ? ColourProvider.Background6 : base.BackgroundColour; + protected override Colour4 ForegroundColour => incompatible.Value ? ColourProvider.Background5 : base.ForegroundColour; protected override void UpdateState() { diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index c51e6baa0d..3f788d10e3 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -442,7 +442,7 @@ namespace osu.Game.Overlays.Mods case ModType.DifficultyIncrease: case ModType.Automation: return hotkeyStyle == ModSelectHotkeyStyle.Sequential - ? (IModHotkeyHandler)SequentialModHotkeyHandler.Create(ModType) + ? SequentialModHotkeyHandler.Create(ModType) : new ClassicModHotkeyHandler(allowIncompatibleSelection); default: diff --git a/osu.Game/Overlays/Mods/ModPanel.cs b/osu.Game/Overlays/Mods/ModPanel.cs index 4d14a31189..02eb395bd9 100644 --- a/osu.Game/Overlays/Mods/ModPanel.cs +++ b/osu.Game/Overlays/Mods/ModPanel.cs @@ -216,9 +216,9 @@ namespace osu.Game.Overlays.Mods base.OnMouseUp(e); } - protected virtual Colour4 BackgroundColour => Active.Value ? activeColour.Darken(0.3f) : (Colour4)ColourProvider.Background3; - protected virtual Colour4 ForegroundColour => Active.Value ? activeColour : (Colour4)ColourProvider.Background2; - protected virtual Colour4 TextColour => Active.Value ? (Colour4)ColourProvider.Background6 : Colour4.White; + protected virtual Colour4 BackgroundColour => Active.Value ? activeColour.Darken(0.3f) : ColourProvider.Background3; + protected virtual Colour4 ForegroundColour => Active.Value ? activeColour : ColourProvider.Background2; + protected virtual Colour4 TextColour => Active.Value ? ColourProvider.Background6 : Colour4.White; protected virtual void UpdateState() { diff --git a/osu.Game/Rulesets/EFRulesetInfo.cs b/osu.Game/Rulesets/EFRulesetInfo.cs index 3c671496de..bd67bdb93c 100644 --- a/osu.Game/Rulesets/EFRulesetInfo.cs +++ b/osu.Game/Rulesets/EFRulesetInfo.cs @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets public int OnlineID { get => ID ?? -1; - set => ID = value >= 0 ? value : (int?)null; + set => ID = value >= 0 ? value : null; } #endregion diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index 2285715564..ddc121eb5b 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Objects } public SliderPath(PathType type, Vector2[] controlPoints, double? expectedDistance = null) - : this(controlPoints.Select((c, i) => new PathControlPoint(c, i == 0 ? (PathType?)type : null)).ToArray(), expectedDistance) + : this(controlPoints.Select((c, i) => new PathControlPoint(c, i == 0 ? type : null)).ToArray(), expectedDistance) { } diff --git a/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs b/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs index 09a090483d..020bae1c42 100644 --- a/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs +++ b/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs @@ -161,7 +161,7 @@ namespace osu.Game.Rulesets.Replays CurrentTime = Math.Clamp(time, frameStart, frameEnd); // In an important section, a mid-frame time cannot be used and a null is returned instead. - return inImportantSection && frameStart < time && time < frameEnd ? null : (double?)CurrentTime; + return inImportantSection && frameStart < time && time < frameEnd ? null : CurrentTime; } private double getFrameTime(int index) diff --git a/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs b/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs index ec1e621491..e14354222b 100644 --- a/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs +++ b/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs @@ -24,6 +24,6 @@ namespace osu.Game.Screens.Edit.Components.Menus Action.Value = () => difficultyChangeFunc.Invoke(beatmapInfo); } - public override IconUsage? GetIconForState(bool state) => state ? (IconUsage?)FontAwesome.Solid.Check : null; + public override IconUsage? GetIconForState(bool state) => state ? FontAwesome.Solid.Check : null; } } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs index 847c96b762..08fc8383c3 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs @@ -131,7 +131,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline } private static string? getCommonBank(SampleControlPoint[] relevantControlPoints) => relevantControlPoints.Select(point => point.SampleBank).Distinct().Count() == 1 ? relevantControlPoints.First().SampleBank : null; - private static int? getCommonVolume(SampleControlPoint[] relevantControlPoints) => relevantControlPoints.Select(point => point.SampleVolume).Distinct().Count() == 1 ? (int?)relevantControlPoints.First().SampleVolume : null; + private static int? getCommonVolume(SampleControlPoint[] relevantControlPoints) => relevantControlPoints.Select(point => point.SampleVolume).Distinct().Count() == 1 ? relevantControlPoints.First().SampleVolume : null; private void updateBankFor(IEnumerable objects, string? newBank) { diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 7a9dae33b4..20bdf75b7d 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -908,6 +908,6 @@ namespace osu.Game.Screens.Edit ControlPointInfo IBeatSyncProvider.ControlPoints => editorBeatmap.ControlPointInfo; IClock IBeatSyncProvider.Clock => clock; - ChannelAmplitudes? IBeatSyncProvider.Amplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : (ChannelAmplitudes?)null; + ChannelAmplitudes? IBeatSyncProvider.Amplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : null; } } diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 0994a7d9bb..cd37c541ec 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -255,7 +255,7 @@ namespace osu.Game.Screens.Play ControlPointInfo IBeatSyncProvider.ControlPoints => beatmap.Beatmap.ControlPointInfo; IClock IBeatSyncProvider.Clock => GameplayClock; - ChannelAmplitudes? IBeatSyncProvider.Amplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : (ChannelAmplitudes?)null; + ChannelAmplitudes? IBeatSyncProvider.Amplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : null; private class HardwareCorrectionOffsetClock : FramedOffsetClock { diff --git a/osu.Game/Screens/Select/Carousel/SetPanelContent.cs b/osu.Game/Screens/Select/Carousel/SetPanelContent.cs index 73a835d67f..0400e2c938 100644 --- a/osu.Game/Screens/Select/Carousel/SetPanelContent.cs +++ b/osu.Game/Screens/Select/Carousel/SetPanelContent.cs @@ -92,8 +92,8 @@ namespace osu.Game.Screens.Select.Carousel var beatmaps = carouselSet.Beatmaps.ToList(); return beatmaps.Count > maximum_difficulty_icons - ? (IEnumerable)beatmaps.GroupBy(b => b.BeatmapInfo.Ruleset) - .Select(group => new FilterableGroupedDifficultyIcon(group.ToList(), group.Last().BeatmapInfo.Ruleset)) + ? beatmaps.GroupBy(b => b.BeatmapInfo.Ruleset) + .Select(group => new FilterableGroupedDifficultyIcon(group.ToList(), group.Last().BeatmapInfo.Ruleset)) : beatmaps.Select(b => new FilterableDifficultyIcon(b)); } } diff --git a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs index 6754b65129..c9d4dc7811 100644 --- a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs +++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs @@ -448,14 +448,14 @@ namespace osu.Game.Screens.Utility mainArea.AddRange(new[] { - new LatencyArea(Key.Number1, betterSide == 1 ? mapDifficultyToTargetFrameRate(DifficultyLevel) : (int?)null) + new LatencyArea(Key.Number1, betterSide == 1 ? mapDifficultyToTargetFrameRate(DifficultyLevel) : null) { Width = 0.5f, VisualMode = { BindTarget = VisualMode }, IsActiveArea = { Value = true }, ReportUserBest = () => recordResult(betterSide == 0), }, - new LatencyArea(Key.Number2, betterSide == 0 ? mapDifficultyToTargetFrameRate(DifficultyLevel) : (int?)null) + new LatencyArea(Key.Number2, betterSide == 0 ? mapDifficultyToTargetFrameRate(DifficultyLevel) : null) { Width = 0.5f, VisualMode = { BindTarget = VisualMode }, diff --git a/osu.Game/Storyboards/CommandTimelineGroup.cs b/osu.Game/Storyboards/CommandTimelineGroup.cs index 20232012f6..6fc9f60177 100644 --- a/osu.Game/Storyboards/CommandTimelineGroup.cs +++ b/osu.Game/Storyboards/CommandTimelineGroup.cs @@ -56,7 +56,7 @@ namespace osu.Game.Storyboards { var first = Alpha.Commands.FirstOrDefault(); - return first?.StartValue == 0 ? first.StartTime : (double?)null; + return first?.StartValue == 0 ? first.StartTime : null; } } From 224c23df77c0430f78676377b8d155fb5375eb2e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 14:58:22 +0900 Subject: [PATCH 151/211] Downgrade to v9 to support iOS toolchain --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 1f59f19eaa..235feea8ce 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@  - 10.0 + 9.0 true enable From 545c04aaf5acfed70065131865821d9ce305dd64 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 16:18:51 +0900 Subject: [PATCH 152/211] Fix dangerous `File.Copy` causing intermittent realm migration test failures Resolves an issue I've been able to locally reproduce on windows. Basically, the `File.Copy` would begin while realm was blocking. The "restore" operation is posted to the `SynchronizationContext` to run on next update call, but in the mean time the copy would begin, causing a conflict of interest. Very dangerous. Only really noticeable on windows. --- osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs index 7d5f0bcd0c..a803974d30 100644 --- a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs +++ b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs @@ -254,7 +254,7 @@ namespace osu.Game.Tests.NonVisual Assert.That(File.Exists(Path.Combine(customPath, OsuGameBase.CLIENT_DATABASE_FILENAME))); Directory.CreateDirectory(customPath2); - File.Copy(Path.Combine(customPath, OsuGameBase.CLIENT_DATABASE_FILENAME), Path.Combine(customPath2, OsuGameBase.CLIENT_DATABASE_FILENAME)); + File.WriteAllText(Path.Combine(customPath2, OsuGameBase.CLIENT_DATABASE_FILENAME), "I am a text"); // Fails because file already exists. Assert.Throws(() => osu.Migrate(customPath2)); From 453b77e0dcac7c0f6742f5d51f046dd535abaf9a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 16:18:51 +0900 Subject: [PATCH 153/211] Fix dangerous `File.Copy` causing intermittent realm migration test failures Resolves an issue I've been able to locally reproduce on windows. Basically, the `File.Copy` would begin while realm was blocking. The "restore" operation is posted to the `SynchronizationContext` to run on next update call, but in the mean time the copy would begin, causing a conflict of interest. Very dangerous. Only really noticeable on windows. --- osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs index 7d5f0bcd0c..a803974d30 100644 --- a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs +++ b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs @@ -254,7 +254,7 @@ namespace osu.Game.Tests.NonVisual Assert.That(File.Exists(Path.Combine(customPath, OsuGameBase.CLIENT_DATABASE_FILENAME))); Directory.CreateDirectory(customPath2); - File.Copy(Path.Combine(customPath, OsuGameBase.CLIENT_DATABASE_FILENAME), Path.Combine(customPath2, OsuGameBase.CLIENT_DATABASE_FILENAME)); + File.WriteAllText(Path.Combine(customPath2, OsuGameBase.CLIENT_DATABASE_FILENAME), "I am a text"); // Fails because file already exists. Assert.Throws(() => osu.Migrate(customPath2)); From 0755430006d582dded0f6a01fcef137a95e666c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 16:53:04 +0900 Subject: [PATCH 154/211] Use `AddOnce` for update calls --- osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index 5e468e975a..7cab868e28 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -64,13 +64,13 @@ namespace osu.Game.Beatmaps { base.LoadComplete(); - currentRuleset.BindValueChanged(_ => updateTrackedBindables()); + currentRuleset.BindValueChanged(_ => Scheduler.AddOnce(updateTrackedBindables)); currentMods.BindValueChanged(mods => { modSettingChangeTracker?.Dispose(); - updateTrackedBindables(); + Scheduler.AddOnce(updateTrackedBindables); modSettingChangeTracker = new ModSettingChangeTracker(mods.NewValue); modSettingChangeTracker.SettingChanged += _ => From c1791276700bfcb0d368d44321063343d8263d0a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 16:53:14 +0900 Subject: [PATCH 155/211] Remove unused bindable retrieval flow --- osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 35 ++------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index 7cab868e28..ef0fa36b16 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -89,7 +89,9 @@ namespace osu.Game.Beatmaps /// A bindable that is updated to contain the star difficulty when it becomes available. Will be null while in an initial calculating state (but not during updates to ruleset and mods if a stale value is already propagated). public IBindable GetBindableDifficulty(IBeatmapInfo beatmapInfo, CancellationToken cancellationToken = default) { - var bindable = createBindable(beatmapInfo, currentRuleset.Value, currentMods.Value, cancellationToken); + var bindable = new BindableStarDifficulty(beatmapInfo, cancellationToken); + + updateBindable(bindable, currentRuleset.Value, currentMods.Value, cancellationToken); lock (bindableUpdateLock) trackedBindables.Add(bindable); @@ -97,21 +99,6 @@ namespace osu.Game.Beatmaps return bindable; } - /// - /// Retrieves a bindable containing the star difficulty of a with a given and combination. - /// - /// - /// The bindable will not update to follow the currently-selected ruleset and mods or its settings. - /// - /// The to get the difficulty of. - /// The to get the difficulty with. If null, the 's ruleset is used. - /// The s to get the difficulty with. If null, no mods will be assumed. - /// An optional which stops updating the star difficulty for the given . - /// A bindable that is updated to contain the star difficulty when it becomes available. Will be null while in an initial calculating state. - public IBindable GetBindableDifficulty(IBeatmapInfo beatmapInfo, IRulesetInfo? rulesetInfo, IEnumerable? mods, - CancellationToken cancellationToken = default) - => createBindable(beatmapInfo, rulesetInfo, mods, cancellationToken); - /// /// Retrieves the difficulty of a . /// @@ -200,22 +187,6 @@ namespace osu.Game.Beatmaps } } - /// - /// Creates a new and triggers an initial value update. - /// - /// The that star difficulty should correspond to. - /// The initial to get the difficulty with. - /// The initial s to get the difficulty with. - /// An optional which stops updating the star difficulty for the given . - /// The . - private BindableStarDifficulty createBindable(IBeatmapInfo beatmapInfo, IRulesetInfo? initialRulesetInfo, IEnumerable? initialMods, - CancellationToken cancellationToken) - { - var bindable = new BindableStarDifficulty(beatmapInfo, cancellationToken); - updateBindable(bindable, initialRulesetInfo, initialMods, cancellationToken); - return bindable; - } - /// /// Updates the value of a with a given ruleset + mods. /// From 26c5b59f6d55976d36a6007aecab4b1e7fb9f39a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 20 Jun 2022 14:39:47 +0200 Subject: [PATCH 156/211] Replace usages of `string.To{Lower,Upper}()` --- CodeAnalysis/BannedSymbols.txt | 2 ++ osu.Game.Rulesets.Catch/CatchSkinComponent.cs | 2 +- osu.Game.Rulesets.Mania/ManiaSkinComponent.cs | 2 +- osu.Game.Rulesets.Osu/OsuSkinComponent.cs | 2 +- .../Skinning/TestSceneDrawableTaikoMascot.cs | 6 +++--- osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs | 2 +- osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs | 4 ++-- osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs | 2 +- osu.Game.Tournament/Models/TournamentTeam.cs | 4 ++-- .../Screens/Ladder/Components/DrawableTournamentRound.cs | 4 ++-- osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs | 2 +- .../Beatmaps/Drawables/Cards/Buttons/FavouriteButton.cs | 2 +- osu.Game/Database/IModelImporter.cs | 2 +- osu.Game/Database/ModelManager.cs | 2 +- osu.Game/Database/RealmArchiveModelImporter.cs | 2 +- osu.Game/Online/API/Requests/GetSpotlightRankingsRequest.cs | 2 +- osu.Game/Online/API/Requests/GetUserRequest.cs | 2 +- osu.Game/Online/Leaderboards/UserTopScoreContainer.cs | 2 +- osu.Game/Overlays/Chat/DaySeparator.cs | 3 ++- osu.Game/Overlays/News/NewsCard.cs | 3 ++- osu.Game/Overlays/TabControlOverlayHeader.cs | 6 +++--- osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs | 2 +- osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs | 2 +- .../OnlinePlay/Match/Components/RoomSettingsOverlay.cs | 2 +- osu.Game/Screens/Select/FilterQueryParser.cs | 2 +- 25 files changed, 35 insertions(+), 31 deletions(-) diff --git a/CodeAnalysis/BannedSymbols.txt b/CodeAnalysis/BannedSymbols.txt index 77197c4c51..8b5431e2d6 100644 --- a/CodeAnalysis/BannedSymbols.txt +++ b/CodeAnalysis/BannedSymbols.txt @@ -17,3 +17,5 @@ M:Realms.CollectionExtensions.SubscribeForNotifications`1(System.Collections.Gen M:System.Threading.Tasks.Task.Wait();Don't use Task.Wait. Use Task.WaitSafely() to ensure we avoid deadlocks. P:System.Threading.Tasks.Task`1.Result;Don't use Task.Result. Use Task.GetResultSafely() to ensure we avoid deadlocks. M:System.Threading.ManualResetEventSlim.Wait();Specify a timeout to avoid waiting forever. +M:System.String.ToLower();string.ToLower() changes behaviour depending on CultureInfo.CurrentCulture. Use string.ToLowerInvariant() instead. If wanting culture-sensitive behaviour, explicitly provide CultureInfo.CurrentCulture or use LocalisableString. +M:System.String.ToUpper();string.ToUpper() changes behaviour depending on CultureInfo.CurrentCulture. Use string.ToUpperInvariant() instead. If wanting culture-sensitive behaviour, explicitly provide CultureInfo.CurrentCulture or use LocalisableString. diff --git a/osu.Game.Rulesets.Catch/CatchSkinComponent.cs b/osu.Game.Rulesets.Catch/CatchSkinComponent.cs index 0fcdd34ca3..e79da667da 100644 --- a/osu.Game.Rulesets.Catch/CatchSkinComponent.cs +++ b/osu.Game.Rulesets.Catch/CatchSkinComponent.cs @@ -16,6 +16,6 @@ namespace osu.Game.Rulesets.Catch protected override string RulesetPrefix => "catch"; // todo: use CatchRuleset.SHORT_NAME; - protected override string ComponentName => Component.ToString().ToLower(); + protected override string ComponentName => Component.ToString().ToLowerInvariant(); } } diff --git a/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs b/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs index b709f85523..21b362df00 100644 --- a/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs +++ b/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania protected override string RulesetPrefix => ManiaRuleset.SHORT_NAME; - protected override string ComponentName => Component.ToString().ToLower(); + protected override string ComponentName => Component.ToString().ToLowerInvariant(); } public enum ManiaSkinComponents diff --git a/osu.Game.Rulesets.Osu/OsuSkinComponent.cs b/osu.Game.Rulesets.Osu/OsuSkinComponent.cs index 82c4005c5e..0abaf2c924 100644 --- a/osu.Game.Rulesets.Osu/OsuSkinComponent.cs +++ b/osu.Game.Rulesets.Osu/OsuSkinComponent.cs @@ -16,6 +16,6 @@ namespace osu.Game.Rulesets.Osu protected override string RulesetPrefix => OsuRuleset.SHORT_NAME; - protected override string ComponentName => Component.ToString().ToLower(); + protected override string ComponentName => Component.ToString().ToLowerInvariant(); } } diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs index 1bf6c0560a..ef95358d34 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs @@ -144,7 +144,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning createDrawableRuleset(); assertStateAfterResult(new JudgementResult(new Swell(), new TaikoSwellJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Clear); - AddUntilStep($"state reverts to {expectedStateAfterClear.ToString().ToLower()}", () => allMascotsIn(expectedStateAfterClear)); + AddUntilStep($"state reverts to {expectedStateAfterClear.ToString().ToLowerInvariant()}", () => allMascotsIn(expectedStateAfterClear)); } private void setBeatmap(bool kiai = false) @@ -195,7 +195,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning { TaikoMascotAnimationState[] mascotStates = null; - AddStep($"{judgementResult.Type.ToString().ToLower()} result for {judgementResult.Judgement.GetType().Name.Humanize(LetterCasing.LowerCase)}", + AddStep($"{judgementResult.Type.ToString().ToLowerInvariant()} result for {judgementResult.Judgement.GetType().Name.Humanize(LetterCasing.LowerCase)}", () => { applyNewResult(judgementResult); @@ -204,7 +204,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning Schedule(() => mascotStates = animatedMascots.Select(mascot => mascot.State.Value).ToArray()); }); - AddAssert($"state is {expectedState.ToString().ToLower()}", () => mascotStates.All(state => state == expectedState)); + AddAssert($"state is {expectedState.ToString().ToLowerInvariant()}", () => mascotStates.All(state => state == expectedState)); } private void applyNewResult(JudgementResult judgementResult) diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs index 676a3d4bc3..63314a6822 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs @@ -16,6 +16,6 @@ namespace osu.Game.Rulesets.Taiko protected override string RulesetPrefix => TaikoRuleset.SHORT_NAME; - protected override string ComponentName => Component.ToString().ToLower(); + protected override string ComponentName => Component.ToString().ToLowerInvariant(); } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs index bacd9b41f8..26a37fc464 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs @@ -139,10 +139,10 @@ namespace osu.Game.Rulesets.Taiko.UI private static Texture getAnimationFrame(ISkin skin, TaikoMascotAnimationState state, int frameIndex) { - var texture = skin.GetTexture($"pippidon{state.ToString().ToLower()}{frameIndex}"); + var texture = skin.GetTexture($"pippidon{state.ToString().ToLowerInvariant()}{frameIndex}"); if (frameIndex == 0 && texture == null) - texture = skin.GetTexture($"pippidon{state.ToString().ToLower()}"); + texture = skin.GetTexture($"pippidon{state.ToString().ToLowerInvariant()}"); return texture; } diff --git a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs index f9c4985219..c4e8bbfccf 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs @@ -192,7 +192,7 @@ namespace osu.Game.Tests.Gameplay AddStep("apply perfect hit result", () => processor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], new Judgement()) { Type = HitResult.Perfect })); AddAssert("not failed", () => !processor.HasFailed); - AddStep($"apply {resultApplied.ToString().ToLower()} hit result", () => processor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], new Judgement()) { Type = resultApplied })); + AddStep($"apply {resultApplied.ToString().ToLowerInvariant()} hit result", () => processor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], new Judgement()) { Type = resultApplied })); AddAssert("failed", () => processor.HasFailed); } diff --git a/osu.Game.Tournament/Models/TournamentTeam.cs b/osu.Game.Tournament/Models/TournamentTeam.cs index 9dbe23b4b3..ac57f748da 100644 --- a/osu.Game.Tournament/Models/TournamentTeam.cs +++ b/osu.Game.Tournament/Models/TournamentTeam.cs @@ -66,14 +66,14 @@ namespace osu.Game.Tournament.Models { // use a sane default flag name based on acronym. if (val.OldValue.StartsWith(FlagName.Value, StringComparison.InvariantCultureIgnoreCase)) - FlagName.Value = val.NewValue.Length >= 2 ? val.NewValue?.Substring(0, 2).ToUpper() : string.Empty; + FlagName.Value = val.NewValue.Length >= 2 ? val.NewValue?.Substring(0, 2).ToUpperInvariant() : string.Empty; }; FullName.ValueChanged += val => { // use a sane acronym based on full name. if (val.OldValue.StartsWith(Acronym.Value, StringComparison.InvariantCultureIgnoreCase)) - Acronym.Value = val.NewValue.Length >= 3 ? val.NewValue?.Substring(0, 3).ToUpper() : string.Empty; + Acronym.Value = val.NewValue.Length >= 3 ? val.NewValue?.Substring(0, 3).ToUpperInvariant() : string.Empty; }; } diff --git a/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs b/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs index ac196130d6..544725996a 100644 --- a/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs +++ b/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs @@ -49,10 +49,10 @@ namespace osu.Game.Tournament.Screens.Ladder.Components }; name = round.Name.GetBoundCopy(); - name.BindValueChanged(n => textName.Text = ((losers ? "Losers " : "") + round.Name).ToUpper(), true); + name.BindValueChanged(n => textName.Text = ((losers ? "Losers " : "") + round.Name).ToUpperInvariant(), true); description = round.Description.GetBoundCopy(); - description.BindValueChanged(n => textDescription.Text = round.Description.Value?.ToUpper(), true); + description.BindValueChanged(n => textDescription.Text = round.Description.Value?.ToUpperInvariant(), true); } } } diff --git a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs index df6e8e816e..925c697346 100644 --- a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs +++ b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs @@ -198,7 +198,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro { row.Add(new Sprite { - Texture = textures.Get($"Mods/{mods.ToLower()}"), + Texture = textures.Get($"Mods/{mods.ToLowerInvariant()}"), Scale = new Vector2(0.5f) }); } diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/FavouriteButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/FavouriteButton.cs index 78481ac27a..bc0fcb92bb 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/FavouriteButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/FavouriteButton.cs @@ -64,7 +64,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons }; favouriteRequest.Failure += e => { - Logger.Error(e, $"Failed to {actionType.ToString().ToLower()} beatmap: {e.Message}"); + Logger.Error(e, $"Failed to {actionType.ToString().ToLowerInvariant()} beatmap: {e.Message}"); Enabled.Value = true; }; diff --git a/osu.Game/Database/IModelImporter.cs b/osu.Game/Database/IModelImporter.cs index 26342cb5fe..ebb8be39ef 100644 --- a/osu.Game/Database/IModelImporter.cs +++ b/osu.Game/Database/IModelImporter.cs @@ -26,7 +26,7 @@ namespace osu.Game.Database /// /// A user displayable name for the model type associated with this manager. /// - string HumanisedModelName => $"{typeof(TModel).Name.Replace(@"Info", "").ToLower()}"; + string HumanisedModelName => $"{typeof(TModel).Name.Replace(@"Info", "").ToLowerInvariant()}"; /// /// Fired when the user requests to view the resulting import. diff --git a/osu.Game/Database/ModelManager.cs b/osu.Game/Database/ModelManager.cs index e0c3dccf57..9603412178 100644 --- a/osu.Game/Database/ModelManager.cs +++ b/osu.Game/Database/ModelManager.cs @@ -201,6 +201,6 @@ namespace osu.Game.Database public Action? PostNotification { get; set; } - public virtual string HumanisedModelName => $"{typeof(TModel).Name.Replace(@"Info", "").ToLower()}"; + public virtual string HumanisedModelName => $"{typeof(TModel).Name.Replace(@"Info", "").ToLowerInvariant()}"; } } diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index 27bfaf05be..a3349d9918 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -549,6 +549,6 @@ namespace osu.Game.Database yield return f.Filename; } - public virtual string HumanisedModelName => $"{typeof(TModel).Name.Replace(@"Info", "").ToLower()}"; + public virtual string HumanisedModelName => $"{typeof(TModel).Name.Replace(@"Info", "").ToLowerInvariant()}"; } } diff --git a/osu.Game/Online/API/Requests/GetSpotlightRankingsRequest.cs b/osu.Game/Online/API/Requests/GetSpotlightRankingsRequest.cs index 75b0cf8027..2d8a8b3b61 100644 --- a/osu.Game/Online/API/Requests/GetSpotlightRankingsRequest.cs +++ b/osu.Game/Online/API/Requests/GetSpotlightRankingsRequest.cs @@ -26,7 +26,7 @@ namespace osu.Game.Online.API.Requests var req = base.CreateWebRequest(); req.AddParameter("spotlight", spotlight.ToString()); - req.AddParameter("filter", sort.ToString().ToLower()); + req.AddParameter("filter", sort.ToString().ToLowerInvariant()); return req; } diff --git a/osu.Game/Online/API/Requests/GetUserRequest.cs b/osu.Game/Online/API/Requests/GetUserRequest.cs index ab45e8e48f..7dcf75950e 100644 --- a/osu.Game/Online/API/Requests/GetUserRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRequest.cs @@ -45,7 +45,7 @@ namespace osu.Game.Online.API.Requests Ruleset = ruleset; } - protected override string Target => Lookup != null ? $@"users/{Lookup}/{Ruleset?.ShortName}?key={lookupType.ToString().ToLower()}" : $@"me/{Ruleset?.ShortName}"; + protected override string Target => Lookup != null ? $@"users/{Lookup}/{Ruleset?.ShortName}?key={lookupType.ToString().ToLowerInvariant()}" : $@"me/{Ruleset?.ShortName}"; private enum LookupType { diff --git a/osu.Game/Online/Leaderboards/UserTopScoreContainer.cs b/osu.Game/Online/Leaderboards/UserTopScoreContainer.cs index df8717fe6d..2d2d82821c 100644 --- a/osu.Game/Online/Leaderboards/UserTopScoreContainer.cs +++ b/osu.Game/Online/Leaderboards/UserTopScoreContainer.cs @@ -48,7 +48,7 @@ namespace osu.Game.Online.Leaderboards { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = @"your personal best".ToUpper(), + Text = @"your personal best".ToUpperInvariant(), Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold), }, scoreContainer = new Container diff --git a/osu.Game/Overlays/Chat/DaySeparator.cs b/osu.Game/Overlays/Chat/DaySeparator.cs index c7961d1a39..be0b53785c 100644 --- a/osu.Game/Overlays/Chat/DaySeparator.cs +++ b/osu.Game/Overlays/Chat/DaySeparator.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -79,7 +80,7 @@ namespace osu.Game.Overlays.Chat { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Text = time.ToLocalTime().ToString("dd MMMM yyyy").ToUpper(), + Text = time.ToLocalTime().ToLocalisableString(@"dd MMMM yyyy").ToUpper(), Font = OsuFont.Torus.With(size: TextSize, weight: FontWeight.SemiBold), Colour = colourProvider?.Content1 ?? Colour4.White, }, diff --git a/osu.Game/Overlays/News/NewsCard.cs b/osu.Game/Overlays/News/NewsCard.cs index 69094a0df7..eb76522e11 100644 --- a/osu.Game/Overlays/News/NewsCard.cs +++ b/osu.Game/Overlays/News/NewsCard.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; @@ -146,7 +147,7 @@ namespace osu.Game.Overlays.News }, new OsuSpriteText { - Text = date.ToString("d MMM yyyy").ToUpper(), + Text = date.ToLocalisableString(@"d MMM yyyy").ToUpper(), Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), Margin = new MarginPadding { diff --git a/osu.Game/Overlays/TabControlOverlayHeader.cs b/osu.Game/Overlays/TabControlOverlayHeader.cs index 4e32afb86f..84a5bf1144 100644 --- a/osu.Game/Overlays/TabControlOverlayHeader.cs +++ b/osu.Game/Overlays/TabControlOverlayHeader.cs @@ -109,15 +109,15 @@ namespace osu.Game.Overlays : base(value) { if (!(Value is Enum enumValue)) - Text.Text = Value.ToString().ToLower(); + Text.Text = Value.ToString().ToLowerInvariant(); else { var localisableDescription = enumValue.GetLocalisableDescription(); string nonLocalisableDescription = enumValue.GetDescription(); - // If localisable == non-localisable, then we must have a basic string, so .ToLower() is used. + // If localisable == non-localisable, then we must have a basic string, so .ToLowerInvariant() is used. Text.Text = localisableDescription.Equals(nonLocalisableDescription) - ? nonLocalisableDescription.ToLower() + ? nonLocalisableDescription.ToLowerInvariant() : localisableDescription; } diff --git a/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs b/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs index cb6c4a9928..00b1ca9dc9 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs @@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Edit.Checks if (edgeType == EdgeType.None) yield break; - string postfix = hitObject is IHasDuration ? edgeType.ToString().ToLower() : null; + string postfix = hitObject is IHasDuration ? edgeType.ToString().ToLowerInvariant() : null; if (maxVolume <= muted_threshold) { diff --git a/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs b/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs index a461f63d2d..2a222aece0 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs @@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Edit.Checks } } - private bool hasAudioExtension(string filename) => audioExtensions.Any(filename.ToLower().EndsWith); + private bool hasAudioExtension(string filename) => audioExtensions.Any(filename.ToLowerInvariant().EndsWith); private bool probablyHasAudioData(Stream data) => data.Length > min_bytes_threshold; public class IssueTemplateTooShort : IssueTemplate diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs index c295e9f85e..71447b15e2 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs @@ -135,7 +135,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components new OsuSpriteText { Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 12), - Text = title.ToUpper(), + Text = title.ToUpperInvariant(), }, content = new Container { diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 92f707ae3e..03b72bf5e9 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Select { foreach (Match match in query_syntax_regex.Matches(query)) { - string key = match.Groups["key"].Value.ToLower(); + string key = match.Groups["key"].Value.ToLowerInvariant(); var op = parseOperator(match.Groups["op"].Value); string value = match.Groups["value"].Value; From 2ae48d5a87f3a71c67742869973d452106697e3c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 17:46:46 +0900 Subject: [PATCH 157/211] Rename incorrect parameter name in `BeatmapManager.GetWorkingBeatmap` --- osu.Game/Beatmaps/BeatmapManager.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 816808638f..73c879226b 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -418,22 +418,22 @@ namespace osu.Game.Beatmaps #region Implementation of IWorkingBeatmapCache - public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo? importedBeatmap) + public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo? beatmapInfo) { // Detached sets don't come with files. // If we seem to be missing files, now is a good time to re-fetch. - if (importedBeatmap?.BeatmapSet?.Files.Count == 0) + if (beatmapInfo?.BeatmapSet?.Files.Count == 0) { Realm.Run(r => { - var refetch = r.Find(importedBeatmap.ID)?.Detach(); + var refetch = r.Find(beatmapInfo.ID)?.Detach(); if (refetch != null) - importedBeatmap = refetch; + beatmapInfo = refetch; }); } - return workingBeatmapCache.GetWorkingBeatmap(importedBeatmap); + return workingBeatmapCache.GetWorkingBeatmap(beatmapInfo); } void IWorkingBeatmapCache.Invalidate(BeatmapSetInfo beatmapSetInfo) => workingBeatmapCache.Invalidate(beatmapSetInfo); From 823b3c1c0fcc74b4260c7ab09bdf13468f8984e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 19:04:29 +0900 Subject: [PATCH 158/211] Ensure `WorkingBeatmap` is always using a detached instance --- osu.Game/Beatmaps/BeatmapManager.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 73c879226b..670dba14ec 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -422,7 +422,7 @@ namespace osu.Game.Beatmaps { // Detached sets don't come with files. // If we seem to be missing files, now is a good time to re-fetch. - if (beatmapInfo?.BeatmapSet?.Files.Count == 0) + if (beatmapInfo?.IsManaged == true || beatmapInfo?.BeatmapSet?.Files.Count == 0) { Realm.Run(r => { @@ -433,6 +433,8 @@ namespace osu.Game.Beatmaps }); } + Debug.Assert(beatmapInfo?.IsManaged != true); + return workingBeatmapCache.GetWorkingBeatmap(beatmapInfo); } From 31a447fda0532fcf15f8c8251ca890c533386492 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 21:25:23 +0900 Subject: [PATCH 159/211] Update parameter discards --- osu.Desktop/DiscordRichPresence.cs | 2 +- osu.Desktop/Program.cs | 8 +++--- osu.Game.Benchmarks/BenchmarkRealmReads.cs | 2 +- .../JuiceStreamPathTest.cs | 2 +- .../TestSceneHyperDash.cs | 2 +- .../Edit/CatchHitObjectComposer.cs | 6 ++--- .../Edit/CatchHitObjectUtils.cs | 4 +-- .../Edit/CatchSelectionHandler.cs | 2 +- osu.Game.Rulesets.Catch/UI/Catcher.cs | 6 ++--- .../Beatmaps/ManiaBeatmapConverter.cs | 2 +- .../Difficulty/ManiaDifficultyCalculator.cs | 6 ++--- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 26 +++++++++---------- .../Mods/ManiaModRandom.cs | 2 +- .../Replays/ManiaAutoGenerator.cs | 4 +-- .../LegacyMainCirclePieceTest.cs | 2 +- .../Mods/TestSceneOsuModSpunOut.cs | 4 +-- .../Edit/OsuHitObjectComposer.cs | 4 +-- .../Mods/OsuModApproachDifferent.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs | 8 +++--- .../Mods/OsuModObjectScaleTween.cs | 8 +++--- osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs | 8 +++--- osu.Game.Rulesets.Osu/Objects/Slider.cs | 2 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 8 +++--- .../Replays/OsuAutoGenerator.cs | 2 +- .../Scoring/OsuScoreProcessor.cs | 2 +- .../Skinning/Legacy/LegacyNewStyleSpinner.cs | 2 +- .../UI/ObjectOrderedHitPolicy.cs | 2 +- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 2 +- .../OsuHitObjectGenerationUtils_Reposition.cs | 4 +-- .../TestSceneTaikoSuddenDeath.cs | 2 +- .../Mods/TaikoModHidden.cs | 4 +-- osu.Game.Rulesets.Taiko/Objects/Hit.cs | 2 +- .../Objects/TaikoStrongableHitObject.cs | 2 +- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 8 +++--- .../Collections/IO/ImportCollectionsTest.cs | 2 +- osu.Game.Tests/Database/GeneralUsageTests.cs | 2 +- osu.Game.Tests/Database/RealmLiveTests.cs | 2 +- .../Skinning/LegacySkinTextureFallbackTest.cs | 2 +- .../TestSceneDrawableScrollingRuleset.cs | 4 +-- .../Visual/Gameplay/TestSceneFailAnimation.cs | 2 +- .../Visual/Gameplay/TestSceneFailJudgement.cs | 2 +- .../Visual/Gameplay/TestSceneSkinEditor.cs | 2 +- .../Gameplay/TestSceneSkinnableDrawable.cs | 6 ++--- .../Gameplay/TestSceneStoryboardWithOutro.cs | 4 +-- ...MultiplayerGameplayLeaderboardTestScene.cs | 2 +- .../TestSceneDrawableLoungeRoom.cs | 2 +- .../Multiplayer/TestSceneMatchStartControl.cs | 2 +- .../Visual/Online/TestSceneNewsSidebar.cs | 2 +- .../TestScenePlaylistsResultsScreen.cs | 4 +-- .../Visual/Settings/TestSceneSettingsPanel.cs | 2 +- .../SongSelect/TestSceneBeatmapInfoWedge.cs | 8 +++--- .../TestSceneBeatSyncedContainer.cs | 8 +++--- .../TestSceneBeatmapListingSearchControl.cs | 6 ++--- .../TestSceneFirstRunSetupOverlay.cs | 2 +- .../TestSceneModSelectOverlay.cs | 2 +- osu.Game.Tournament/Components/DateTextBox.cs | 2 +- .../Components/DrawableTeamFlag.cs | 2 +- .../Components/DrawableTeamTitle.cs | 2 +- .../Components/DrawableTournamentTeam.cs | 2 +- .../Screens/Drawings/DrawingsScreen.cs | 2 +- .../Screens/Editors/LadderEditorScreen.cs | 2 +- .../Components/DrawableTournamentRound.cs | 4 +-- .../Screens/Ladder/LadderScreen.cs | 2 +- osu.Game.Tournament/TournamentGame.cs | 2 +- osu.Game.Tournament/TournamentGameBase.cs | 2 +- osu.Game.Tournament/TournamentSceneManager.cs | 4 +-- .../ControlPoints/ControlPointInfo.cs | 4 +-- .../Drawables/BundledBeatmapDownloader.cs | 2 +- .../Beatmaps/Formats/JsonBeatmapDecoder.cs | 2 +- .../Beatmaps/Formats/LegacyBeatmapEncoder.cs | 4 +-- .../Formats/LegacyStoryboardDecoder.cs | 2 +- .../Beatmaps/Legacy/LegacyControlPointInfo.cs | 4 +-- osu.Game/Collections/BeatmapCollection.cs | 2 +- .../Collections/CollectionFilterDropdown.cs | 4 +-- osu.Game/Collections/CollectionManager.cs | 2 +- osu.Game/Database/RealmAccess.cs | 2 +- osu.Game/Database/RealmObjectExtensions.cs | 14 +++++----- osu.Game/Extensions/TaskExtensions.cs | 2 +- .../Markdown/OsuMarkdownContainer.cs | 2 +- osu.Game/Graphics/UserInterface/BarGraph.cs | 2 +- .../Graphics/UserInterface/LoadingLayer.cs | 4 +-- .../Graphics/UserInterface/StarCounter.cs | 2 +- .../Bindings/DatabasedKeyBindingContainer.cs | 2 +- osu.Game/Input/IdleTracker.cs | 10 +++---- osu.Game/Online/BeatmapDownloadTracker.cs | 2 +- osu.Game/Online/Chat/ChannelManager.cs | 2 +- osu.Game/Online/HubClientConnector.cs | 2 +- .../OnlinePlayBeatmapAvailabilityTracker.cs | 2 +- osu.Game/Online/ScoreDownloadTracker.cs | 2 +- osu.Game/OsuGameBase.cs | 2 +- .../BeatmapListingFilterControl.cs | 6 ++--- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 2 +- .../BeatmapSet/Scores/ScoresContainer.cs | 2 +- osu.Game/Overlays/Comments/CommentEditor.cs | 2 +- .../Overlays/Comments/CommentsContainer.cs | 4 +-- .../Dashboard/Friends/FriendDisplay.cs | 2 +- osu.Game/Overlays/Login/LoginForm.cs | 2 +- .../Overlays/MedalSplash/DrawableMedal.cs | 2 +- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 6 ++--- osu.Game/Overlays/Music/PlaylistOverlay.cs | 2 +- .../Notifications/ProgressNotification.cs | 2 +- osu.Game/Overlays/OSD/TrackedSettingToast.cs | 2 +- .../Sections/Graphics/LayoutSettings.cs | 6 ++--- .../Sections/Maintenance/BeatmapSettings.cs | 10 +++---- .../Maintenance/CollectionsSettings.cs | 2 +- .../Sections/Maintenance/ScoreSettings.cs | 4 +-- .../Sections/Maintenance/SkinSettings.cs | 4 +-- .../Overlays/Settings/Sections/SkinSection.cs | 4 +-- .../Configuration/RulesetConfigManager.cs | 2 +- osu.Game/Rulesets/Edit/PlacementBlueprint.cs | 4 +-- .../Mods/DifficultyAdjustSettingsControl.cs | 4 +-- osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs | 4 +-- osu.Game/Rulesets/Mods/ModTimeRamp.cs | 2 +- osu.Game/Rulesets/Ruleset.cs | 26 +++++++++---------- osu.Game/Rulesets/UI/RulesetInputManager.cs | 2 +- .../TernaryButtons/DrawableTernaryButton.cs | 2 +- .../Summary/Parts/ControlPointPart.cs | 2 +- .../Summary/Parts/GroupVisualisation.cs | 8 +++--- .../Timelines/Summary/Parts/TimelinePart.cs | 2 +- .../Compose/Components/BeatDivisorControl.cs | 2 +- .../Compose/Components/BlueprintContainer.cs | 2 +- .../Components/EditorSelectionHandler.cs | 2 +- .../Compose/Components/SelectionHandler.cs | 2 +- .../Components/Timeline/SamplePointPiece.cs | 6 ++--- .../Timeline/TimelineControlPointDisplay.cs | 2 +- .../Timeline/TimelineControlPointGroup.cs | 2 +- .../Screens/Edit/Compose/ComposeScreen.cs | 2 +- osu.Game/Screens/Edit/EditorBeatmap.cs | 4 +-- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 2 +- osu.Game/Screens/Edit/Setup/DesignSection.cs | 2 +- .../Screens/Edit/Timing/ControlPointTable.cs | 4 +-- .../Edit/Timing/LabelledTimeSignature.cs | 2 +- .../Edit/Timing/SliderWithTextBoxInput.cs | 2 +- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 2 +- osu.Game/Screens/Edit/Timing/TimingSection.cs | 2 +- .../Edit/Timing/WaveformComparisonDisplay.cs | 2 +- osu.Game/Screens/Edit/Verify/IssueList.cs | 2 +- osu.Game/Screens/Menu/Disclaimer.cs | 2 +- .../OnlinePlay/Components/BeatmapTitle.cs | 2 +- .../Components/MatchBeatmapDetailArea.cs | 2 +- .../Components/OnlinePlayBackgroundSprite.cs | 2 +- .../Components/OverlinedPlaylistHeader.cs | 2 +- .../OnlinePlay/Components/ParticipantsList.cs | 2 +- .../Components/StarRatingRangeDisplay.cs | 2 +- .../OnlinePlay/DrawableRoomPlaylist.cs | 2 +- osu.Game/Screens/OnlinePlay/Header.cs | 4 +-- .../Lounge/Components/PlaylistCountPill.cs | 2 +- .../OnlinePlay/Lounge/DrawableLoungeRoom.cs | 2 +- .../Lounge/LoungeBackgroundScreen.cs | 2 +- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 2 +- .../Match/MultiplayerReadyButton.cs | 2 +- .../Match/MultiplayerSpectateButton.cs | 2 +- .../Playlist/MultiplayerPlaylistTabControl.cs | 2 +- .../Match/Playlist/MultiplayerQueueList.cs | 2 +- .../Multiplayer/MultiplayerLoungeSubScreen.cs | 2 +- .../Multiplayer/MultiplayerPlayer.cs | 2 +- .../Spectate/MultiSpectatorScreen.cs | 2 +- .../Screens/OnlinePlay/OnlinePlayComposite.cs | 2 +- .../Playlists/PlaylistsRoomSubScreen.cs | 2 +- osu.Game/Screens/Play/FailAnimation.cs | 2 +- osu.Game/Screens/Play/GameplayMenuOverlay.cs | 4 +-- .../Screens/Play/HUD/HoldForMenuButton.cs | 2 +- osu.Game/Screens/Play/HUDOverlay.cs | 2 +- osu.Game/Screens/Play/KeyCounterDisplay.cs | 8 +++--- osu.Game/Screens/Play/Player.cs | 4 +-- osu.Game/Screens/Play/ReplayPlayer.cs | 2 +- .../Expanded/Statistics/ComboStatistic.cs | 2 +- .../Ranking/Statistics/StatisticsPanel.cs | 2 +- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- osu.Game/Screens/Select/BeatmapDetailArea.cs | 2 +- osu.Game/Screens/Select/BeatmapDetails.cs | 2 +- .../Screens/Select/Carousel/TopLocalRank.cs | 2 +- .../Screens/Select/Details/AdvancedStats.cs | 2 +- .../Screens/Select/PlayBeatmapDetailArea.cs | 2 +- osu.Game/Skinning/DefaultSkin.cs | 2 +- osu.Game/Skinning/Editor/SkinEditor.cs | 4 +-- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 2 +- osu.Game/Skinning/LegacyManiaSkinDecoder.cs | 12 ++++----- osu.Game/Skinning/SkinImporter.cs | 2 +- osu.Game/Skinning/SkinProvidingContainer.cs | 6 ++--- osu.Game/Storyboards/StoryboardSprite.cs | 10 +++---- osu.Game/Tests/Visual/ScreenTestScene.cs | 4 +-- 182 files changed, 309 insertions(+), 309 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index f2531c1cae..d0b6953c30 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -57,7 +57,7 @@ namespace osu.Desktop client.OnReady += onReady; // safety measure for now, until we performance test / improve backoff for failed connections. - client.OnConnectionFailed += (_, __) => client.Deinitialize(); + client.OnConnectionFailed += (_, _) => client.Deinitialize(); client.OnError += (_, e) => Logger.Log($"An error occurred with Discord RPC Client: {e.Code} {e.Message}", LoggingTarget.Network); diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs index 7a5809e915..712f300671 100644 --- a/osu.Desktop/Program.cs +++ b/osu.Desktop/Program.cs @@ -129,18 +129,18 @@ namespace osu.Desktop [SupportedOSPlatform("windows")] private static void setupSquirrel() { - SquirrelAwareApp.HandleEvents(onInitialInstall: (version, tools) => + SquirrelAwareApp.HandleEvents(onInitialInstall: (_, tools) => { tools.CreateShortcutForThisExe(); tools.CreateUninstallerRegistryEntry(); - }, onAppUpdate: (version, tools) => + }, onAppUpdate: (_, tools) => { tools.CreateUninstallerRegistryEntry(); - }, onAppUninstall: (version, tools) => + }, onAppUninstall: (_, tools) => { tools.RemoveShortcutForThisExe(); tools.RemoveUninstallerRegistryEntry(); - }, onEveryRun: (version, tools, firstRun) => + }, onEveryRun: (_, _, _) => { // While setting the `ProcessAppUserModelId` fixes duplicate icons/shortcuts on the taskbar, it currently // causes the right-click context menu to function incorrectly. diff --git a/osu.Game.Benchmarks/BenchmarkRealmReads.cs b/osu.Game.Benchmarks/BenchmarkRealmReads.cs index b26fc3fd59..5ffda6504e 100644 --- a/osu.Game.Benchmarks/BenchmarkRealmReads.cs +++ b/osu.Game.Benchmarks/BenchmarkRealmReads.cs @@ -31,7 +31,7 @@ namespace osu.Game.Benchmarks realm = new RealmAccess(storage, OsuGameBase.CLIENT_DATABASE_FILENAME); - realm.Run(r => + realm.Run(_ => { realm.Write(c => c.Add(TestResources.CreateTestBeatmapSetInfo(rulesets: new[] { new OsuRuleset().RulesetInfo }))); }); diff --git a/osu.Game.Rulesets.Catch.Tests/JuiceStreamPathTest.cs b/osu.Game.Rulesets.Catch.Tests/JuiceStreamPathTest.cs index 54d26a0f3d..0de992c1df 100644 --- a/osu.Game.Rulesets.Catch.Tests/JuiceStreamPathTest.cs +++ b/osu.Game.Rulesets.Catch.Tests/JuiceStreamPathTest.cs @@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Catch.Tests new JuiceStreamPathVertex(20, -5) })); - removeCount = path.RemoveVertices((_, i) => true); + removeCount = path.RemoveVertices((_, _) => true); Assert.That(removeCount, Is.EqualTo(1)); Assert.That(path.Vertices, Is.EqualTo(new[] { diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs index 655edf7e08..4886942dc6 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.Tests hyperDashCount = 0; // this needs to be done within the frame stable context due to how quickly hyperdash state changes occur. - Player.DrawableRuleset.FrameStableComponents.OnUpdate += d => + Player.DrawableRuleset.FrameStableComponents.OnUpdate += _ => { var catcher = Player.ChildrenOfType().FirstOrDefault(); diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index 01156ab021..f31dc3ef9c 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -135,15 +135,15 @@ namespace osu.Game.Rulesets.Catch.Edit { switch (BlueprintContainer.CurrentTool) { - case SelectTool _: + case SelectTool: if (EditorBeatmap.SelectedHitObjects.Count == 0) return null; double minTime = EditorBeatmap.SelectedHitObjects.Min(hitObject => hitObject.StartTime); return getLastSnappableHitObject(minTime); - case FruitCompositionTool _: - case JuiceStreamCompositionTool _: + case FruitCompositionTool: + case JuiceStreamCompositionTool: if (!CursorInPlacementArea) return null; diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectUtils.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectUtils.cs index 4390234b59..889d3909bd 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectUtils.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectUtils.cs @@ -42,10 +42,10 @@ namespace osu.Game.Rulesets.Catch.Edit case Droplet droplet: return droplet is TinyDroplet ? PositionRange.EMPTY : new PositionRange(droplet.OriginalX); - case JuiceStream _: + case JuiceStream: return GetPositionRange(hitObject.NestedHitObjects); - case BananaShower _: + case BananaShower: // A banana shower occupies the whole screen width. return new PositionRange(0, CatchPlayfield.WIDTH); diff --git a/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs b/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs index 319cb1bfc9..5aac521d0b 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs @@ -131,7 +131,7 @@ namespace osu.Game.Rulesets.Catch.Edit { switch (hitObject) { - case BananaShower _: + case BananaShower: return false; case JuiceStream juiceStream: diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index 6a3ec336d1..efc841dfac 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -389,13 +389,13 @@ namespace osu.Game.Rulesets.Catch.UI { switch (source) { - case Fruit _: + case Fruit: return caughtFruitPool.Get(); - case Banana _: + case Banana: return caughtBananaPool.Get(); - case Droplet _: + case Droplet: return caughtDropletPool.Get(); default: diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 2b4f497785..90cd7f57b5 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -173,7 +173,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps switch (original) { - case IHasDistance _: + case IHasDistance: { var generator = new DistanceObjectPatternGenerator(Random, original, beatmap, lastPattern, originalBeatmap); conversion = generator; diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index 8002410f70..979aaa1cf5 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -156,9 +156,9 @@ namespace osu.Game.Rulesets.Mania.Difficulty { switch (m) { - case ManiaModNoFail _: - case ManiaModEasy _: - case ManiaModHalfTime _: + case ManiaModNoFail: + case ManiaModEasy: + case ManiaModHalfTime: scoreMultiplier *= 0.5; break; } diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 98a492450e..4723416c30 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -146,56 +146,56 @@ namespace osu.Game.Rulesets.Mania { switch (mod) { - case ManiaModKey1 _: + case ManiaModKey1: value |= LegacyMods.Key1; break; - case ManiaModKey2 _: + case ManiaModKey2: value |= LegacyMods.Key2; break; - case ManiaModKey3 _: + case ManiaModKey3: value |= LegacyMods.Key3; break; - case ManiaModKey4 _: + case ManiaModKey4: value |= LegacyMods.Key4; break; - case ManiaModKey5 _: + case ManiaModKey5: value |= LegacyMods.Key5; break; - case ManiaModKey6 _: + case ManiaModKey6: value |= LegacyMods.Key6; break; - case ManiaModKey7 _: + case ManiaModKey7: value |= LegacyMods.Key7; break; - case ManiaModKey8 _: + case ManiaModKey8: value |= LegacyMods.Key8; break; - case ManiaModKey9 _: + case ManiaModKey9: value |= LegacyMods.Key9; break; - case ManiaModDualStages _: + case ManiaModDualStages: value |= LegacyMods.KeyCoop; break; - case ManiaModFadeIn _: + case ManiaModFadeIn: value |= LegacyMods.FadeIn; value &= ~LegacyMods.Hidden; // this is toggled on in the base call due to inheritance, but we don't want that. break; - case ManiaModMirror _: + case ManiaModMirror: value |= LegacyMods.Mirror; break; - case ManiaModRandom _: + case ManiaModRandom: value |= LegacyMods.Random; break; } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs index c7c7a6003e..22347d21b8 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Mania.Mods var rng = new Random((int)Seed.Value); int availableColumns = ((ManiaBeatmap)beatmap).TotalColumns; - var shuffledColumns = Enumerable.Range(0, availableColumns).OrderBy(item => rng.Next()).ToList(); + var shuffledColumns = Enumerable.Range(0, availableColumns).OrderBy(_ => rng.Next()).ToList(); beatmap.HitObjects.OfType().ForEach(h => h.Column = shuffledColumns[h.Column]); } diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs index 3814ad84f1..26572de412 100644 --- a/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs +++ b/osu.Game.Rulesets.Mania/Replays/ManiaAutoGenerator.cs @@ -57,11 +57,11 @@ namespace osu.Game.Rulesets.Mania.Replays { switch (point) { - case HitPoint _: + case HitPoint: actions.Add(columnActions[point.Column]); break; - case ReleasePoint _: + case ReleasePoint: actions.Remove(columnActions[point.Column]); break; } diff --git a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs index 2c4310202e..7c4ab2f5f4 100644 --- a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Osu.Tests skin.Setup(s => s.GetTexture(It.IsAny())).CallBase(); skin.Setup(s => s.GetTexture(It.IsIn(textureFilenames), It.IsAny(), It.IsAny())) - .Returns((string componentName, WrapMode _, WrapMode __) => new Texture(1, 1) { AssetName = componentName }); + .Returns((string componentName, WrapMode _, WrapMode _) => new Texture(1, 1) { AssetName = componentName }); Child = new DependencyProvidingContainer { diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs index fe8bba3ed8..4f6d6376bf 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs @@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods lastResult = null; spinner = nextSpinner; - spinner.OnNewResult += (o, result) => lastResult = result; + spinner.OnNewResult += (_, result) => lastResult = result; } return lastResult?.Type == HitResult.Great; @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods return false; spinner = nextSpinner; - spinner.OnNewResult += (o, result) => results.Add(result); + spinner.OnNewResult += (_, result) => results.Add(result); results.Clear(); } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 066a114f66..60896b17bf 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Osu.Edit }); selectedHitObjects = EditorBeatmap.SelectedHitObjects.GetBoundCopy(); - selectedHitObjects.CollectionChanged += (_, __) => updateDistanceSnapGrid(); + selectedHitObjects.CollectionChanged += (_, _) => updateDistanceSnapGrid(); placementObject = EditorBeatmap.PlacementObject.GetBoundCopy(); placementObject.ValueChanged += _ => updateDistanceSnapGrid(); @@ -204,7 +204,7 @@ namespace osu.Game.Rulesets.Osu.Edit switch (BlueprintContainer.CurrentTool) { - case SelectTool _: + case SelectTool: if (!EditorBeatmap.SelectedHitObjects.Any()) return; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs index 3d4a26b3ff..e25845f5ab 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableHitObject(DrawableHitObject drawable) { - drawable.ApplyCustomUpdateState += (drawableObject, state) => + drawable.ApplyCustomUpdateState += (drawableObject, _) => { if (!(drawableObject is DrawableHitCircle drawableHitCircle)) return; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs index f9422e1ff9..11ceb0f710 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs @@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Osu.Mods switch (drawableObject) { - case DrawableSliderTail _: + case DrawableSliderTail: using (drawableObject.BeginAbsoluteSequence(fadeStartTime)) drawableObject.FadeOut(fadeDuration); @@ -165,14 +165,14 @@ namespace osu.Game.Rulesets.Osu.Mods switch (hitObject) { - case Slider _: + case Slider: return (fadeOutStartTime, longFadeDuration); - case SliderTick _: + case SliderTick: double tickFadeOutDuration = Math.Min(hitObject.TimePreempt - DrawableSliderTick.ANIM_DURATION, 1000); return (hitObject.StartTime - tickFadeOutDuration, tickFadeOutDuration); - case Spinner _: + case Spinner: return (fadeOutStartTime + longFadeDuration, fadeOutDuration); default: diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs b/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs index d96724929f..44942e9e37 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs @@ -44,13 +44,13 @@ namespace osu.Game.Rulesets.Osu.Mods // apply grow effect switch (drawable) { - case DrawableSliderHead _: - case DrawableSliderTail _: + case DrawableSliderHead: + case DrawableSliderTail: // special cases we should *not* be scaling. break; - case DrawableSlider _: - case DrawableHitCircle _: + case DrawableSlider: + case DrawableHitCircle: { using (drawable.BeginAbsoluteSequence(h.StartTime - h.TimePreempt)) drawable.ScaleTo(StartScale.Value).Then().ScaleTo(EndScale, h.TimePreempt, Easing.OutSine); diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs index 51994a3e1a..5a08df3803 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs @@ -34,10 +34,10 @@ namespace osu.Game.Rulesets.Osu.Mods { switch (drawable) { - case DrawableSliderHead _: - case DrawableSliderTail _: - case DrawableSliderTick _: - case DrawableSliderRepeat _: + case DrawableSliderHead: + case DrawableSliderTail: + case DrawableSliderTick: + case DrawableSliderRepeat: return; default: diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index dcb47347ef..a5468ff613 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -156,7 +156,7 @@ namespace osu.Game.Rulesets.Osu.Objects public Slider() { - SamplesBindable.CollectionChanged += (_, __) => UpdateNestedSamples(); + SamplesBindable.CollectionChanged += (_, _) => UpdateNestedSamples(); Path.Version.ValueChanged += _ => updateNestedPositions(); } diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 8b9dc71a8b..120ce32612 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -120,19 +120,19 @@ namespace osu.Game.Rulesets.Osu { switch (mod) { - case OsuModAutopilot _: + case OsuModAutopilot: value |= LegacyMods.Autopilot; break; - case OsuModSpunOut _: + case OsuModSpunOut: value |= LegacyMods.SpunOut; break; - case OsuModTarget _: + case OsuModTarget: value |= LegacyMods.Target; break; - case OsuModTouchDevice _: + case OsuModTouchDevice: value |= LegacyMods.TouchDevice; break; } diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs index 27029afece..b0155c02cf 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs @@ -107,7 +107,7 @@ namespace osu.Game.Rulesets.Osu.Replays hitWindows = slider.TailCircle.HitWindows; break; - case Spinner _: + case Spinner: hitWindows = defaultHitWindows; break; } diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 7a71ef6c65..34a1bd40e9 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Scoring { switch (hitObject) { - case HitCircle _: + case HitCircle: return new OsuHitCircleJudgementResult(hitObject, judgement); default: diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs index e4ca0d2ea8..d5cc469ca9 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs @@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy break; - case DrawableSpinnerBonusTick _: + case DrawableSpinnerBonusTick: if (state == ArmedState.Hit) glow.FlashColour(Color4.White, 200); diff --git a/osu.Game.Rulesets.Osu/UI/ObjectOrderedHitPolicy.cs b/osu.Game.Rulesets.Osu/UI/ObjectOrderedHitPolicy.cs index fba225d464..6330208d37 100644 --- a/osu.Game.Rulesets.Osu/UI/ObjectOrderedHitPolicy.cs +++ b/osu.Game.Rulesets.Osu/UI/ObjectOrderedHitPolicy.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.UI switch (obj) { - case DrawableSpinner _: + case DrawableSpinner: continue; case DrawableSlider slider: diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index ad27428010..3179b37d5a 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Osu.UI // note: `Slider`'s `ProxiedLayer` is added when its nested `DrawableHitCircle` is loaded. switch (drawable) { - case DrawableSpinner _: + case DrawableSpinner: spinnerProxies.Add(drawable.CreateProxy()); break; diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils_Reposition.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils_Reposition.cs index c413226e63..3a156d4d25 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils_Reposition.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils_Reposition.cs @@ -88,11 +88,11 @@ namespace osu.Game.Rulesets.Osu.Utils switch (hitObject) { - case HitCircle _: + case HitCircle: shift = clampHitCircleToPlayfield(current); break; - case Slider _: + case Slider: shift = clampSliderToPlayfield(current); break; } diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs index 51772df4a7..cdfab4a215 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Taiko.Tests AddStep("Setup judgements", () => { judged = false; - Player.ScoreProcessor.NewJudgement += b => judged = true; + Player.ScoreProcessor.NewJudgement += _ => judged = true; }); AddUntilStep("swell judged", () => judged); AddAssert("failed", () => Player.GameplayState.HasFailed); diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs index 69eace4302..e065bb43fd 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs @@ -48,8 +48,8 @@ namespace osu.Game.Rulesets.Taiko.Mods { switch (hitObject) { - case DrawableDrumRollTick _: - case DrawableHit _: + case DrawableDrumRollTick: + case DrawableHit: double preempt = drawableRuleset.TimeRange.Value / drawableRuleset.ControlPointAt(hitObject.HitObject.StartTime).Multiplier; double start = hitObject.HitObject.StartTime - preempt * fade_out_start_time; double duration = preempt * fade_out_duration; diff --git a/osu.Game.Rulesets.Taiko/Objects/Hit.cs b/osu.Game.Rulesets.Taiko/Objects/Hit.cs index 8bc0dc6df0..20f3304c30 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Hit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Hit.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Objects DisplayColour.Value = Type == HitType.Centre ? COLOUR_CENTRE : COLOUR_RIM; }); - SamplesBindable.BindCollectionChanged((_, __) => updateTypeFromSamples()); + SamplesBindable.BindCollectionChanged((_, _) => updateTypeFromSamples()); } private void updateTypeFromSamples() diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs index b7bdd98d2a..d4d59d5d44 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoStrongableHitObject.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Taiko.Objects protected TaikoStrongableHitObject() { IsStrongBindable.BindValueChanged(_ => updateSamplesFromType()); - SamplesBindable.BindCollectionChanged((_, __) => updateTypeFromSamples()); + SamplesBindable.BindCollectionChanged((_, _) => updateTypeFromSamples()); } private void updateTypeFromSamples() diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 4e0c8029fb..4ef7c24464 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -245,7 +245,7 @@ namespace osu.Game.Rulesets.Taiko.UI barLinePlayfield.Add(barLine); break; - case DrawableTaikoHitObject _: + case DrawableTaikoHitObject: base.Add(h); break; @@ -261,7 +261,7 @@ namespace osu.Game.Rulesets.Taiko.UI case DrawableBarLine barLine: return barLinePlayfield.Remove(barLine); - case DrawableTaikoHitObject _: + case DrawableTaikoHitObject: return base.Remove(h); default: @@ -280,12 +280,12 @@ namespace osu.Game.Rulesets.Taiko.UI switch (result.Judgement) { - case TaikoStrongJudgement _: + case TaikoStrongJudgement: if (result.IsHit) hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).ParentHitObject)?.VisualiseSecondHit(result); break; - case TaikoDrumRollTickJudgement _: + case TaikoDrumRollTickJudgement: if (!result.IsHit) break; diff --git a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs index 7f466925a4..c31aafa67f 100644 --- a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs +++ b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs @@ -99,7 +99,7 @@ namespace osu.Game.Tests.Collections.IO public async Task TestImportMalformedDatabase() { bool exceptionThrown = false; - UnhandledExceptionEventHandler setException = (_, __) => exceptionThrown = true; + UnhandledExceptionEventHandler setException = (_, _) => exceptionThrown = true; using (HeadlessGameHost host = new CleanRunHeadlessGameHost()) { diff --git a/osu.Game.Tests/Database/GeneralUsageTests.cs b/osu.Game.Tests/Database/GeneralUsageTests.cs index c28a0c63af..65f805bafb 100644 --- a/osu.Game.Tests/Database/GeneralUsageTests.cs +++ b/osu.Game.Tests/Database/GeneralUsageTests.cs @@ -46,7 +46,7 @@ namespace osu.Game.Tests.Database realm.RegisterCustomSubscription(r => { - var subscription = r.All().QueryAsyncWithNotifications((sender, changes, error) => + var subscription = r.All().QueryAsyncWithNotifications((_, _, _) => { realm.Run(_ => { diff --git a/osu.Game.Tests/Database/RealmLiveTests.cs b/osu.Game.Tests/Database/RealmLiveTests.cs index 416216062e..00a667521d 100644 --- a/osu.Game.Tests/Database/RealmLiveTests.cs +++ b/osu.Game.Tests/Database/RealmLiveTests.cs @@ -189,7 +189,7 @@ namespace osu.Game.Tests.Database }); // Can't be used, even from within a valid context. - realm.Run(threadContext => + realm.Run(_ => { Assert.Throws(() => { diff --git a/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs b/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs index efab884d37..22aa78838a 100644 --- a/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs +++ b/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs @@ -157,7 +157,7 @@ namespace osu.Game.Tests.NonVisual.Skinning { // use an incrementing width to allow assertion matching on correct textures as they turn from uploads into actual textures. int width = 1; - Textures = fileNames.ToDictionary(fileName => fileName, fileName => new TextureUpload(new Image(width, width++))); + Textures = fileNames.ToDictionary(fileName => fileName, _ => new TextureUpload(new Image(width, width++))); } public TextureUpload Get(string name) => Textures.GetValueOrDefault(name); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs index f9a3695d65..a79ba0ae5d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs @@ -322,8 +322,8 @@ namespace osu.Game.Tests.Visual.Gameplay { switch (h) { - case TestPooledHitObject _: - case TestPooledParentHitObject _: + case TestPooledHitObject: + case TestPooledParentHitObject: return null; case TestParentHitObject p: diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs index 0b737f5110..ce01bf2fb5 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs @@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override void LoadComplete() { base.LoadComplete(); - HealthProcessor.FailConditions += (_, __) => true; + HealthProcessor.FailConditions += (_, _) => true; } private double lastFrequency = double.MaxValue; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs index 90a4b536bb..5e87eff717 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs @@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override void LoadComplete() { base.LoadComplete(); - HealthProcessor.FailConditions += (_, __) => true; + HealthProcessor.FailConditions += (_, _) => true; } } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs index 3bebf2b68b..f319290441 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs @@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestToggleEditor() { - AddToggleStep("toggle editor visibility", visible => skinEditor.ToggleVisibility()); + AddToggleStep("toggle editor visibility", _ => skinEditor.ToggleVisibility()); } [Test] diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs index 757a261de6..16593effd6 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs @@ -103,7 +103,7 @@ namespace osu.Game.Tests.Visual.Gameplay Child = new SkinProvidingContainer(secondarySource) { RelativeSizeAxes = Axes.Both, - Child = consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation")) + Child = consumer = new SkinConsumer("test", _ => new NamedBox("Default Implementation")) } }; }); @@ -132,7 +132,7 @@ namespace osu.Game.Tests.Visual.Gameplay }; }); - AddStep("add permissive", () => target.Add(consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation")))); + AddStep("add permissive", () => target.Add(consumer = new SkinConsumer("test", _ => new NamedBox("Default Implementation")))); AddAssert("consumer using override source", () => consumer.Drawable is SecondarySourceBox); AddAssert("skinchanged only called once", () => consumer.SkinChangedCount == 1); } @@ -155,7 +155,7 @@ namespace osu.Game.Tests.Visual.Gameplay }; }); - AddStep("add permissive", () => target.Add(consumer = new SkinConsumer("test", name => new NamedBox("Default Implementation")))); + AddStep("add permissive", () => target.Add(consumer = new SkinConsumer("test", _ => new NamedBox("Default Implementation")))); AddAssert("consumer using override source", () => consumer.Drawable is SecondarySourceBox); AddStep("disable", () => target.Disable()); AddAssert("consumer using base source", () => consumer.Drawable is BaseSourceBox); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs index 68d024e63f..002e35f742 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs @@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.Gameplay base.SetUpSteps(); AddStep("enable storyboard", () => LocalConfig.SetValue(OsuSetting.ShowStoryboard, true)); AddStep("set dim level to 0", () => LocalConfig.SetValue(OsuSetting.DimLevel, 0)); - AddStep("reset fail conditions", () => currentFailConditions = (_, __) => false); + AddStep("reset fail conditions", () => currentFailConditions = (_, _) => false); AddStep("set storyboard duration to 2s", () => currentStoryboardDuration = 2000); AddStep("set ShowResults = true", () => showResults = true); } @@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual.Gameplay { CreateTest(() => { - AddStep("fail on first judgement", () => currentFailConditions = (_, __) => true); + AddStep("fail on first judgement", () => currentFailConditions = (_, _) => true); // Fail occurs at 164ms with the provided beatmap. // Fail animation runs for 2.5s realtime but the gameplay time change is *variable* due to the frequency transform being applied, so we need a bit of lenience. diff --git a/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs index 43ca47778a..631f2e707a 100644 --- a/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs @@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Multiplayer // To emulate `MultiplayerClient.CurrentMatchPlayingUserIds` we need a bindable list of *only IDs*. // This tracks the list of users 1:1. - MultiplayerUsers.BindCollectionChanged((c, e) => + MultiplayerUsers.BindCollectionChanged((_, e) => { switch (e.Action) { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs index 5b4e0a88aa..be1f21a7b2 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Multiplayer var mockLounge = new Mock(); mockLounge .Setup(l => l.Join(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>())) - .Callback, Action>((a, b, c, d) => + .Callback, Action>((_, _, _, d) => { Task.Run(() => { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs index 0cdc144b6a..a800b21bc9 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs @@ -90,7 +90,7 @@ namespace osu.Game.Tests.Visual.Multiplayer setRoomCountdown(countdownStart.Duration); break; - case StopCountdownRequest _: + case StopCountdownRequest: multiplayerRoom.Countdown = null; raiseRoomUpdated(); break; diff --git a/osu.Game.Tests/Visual/Online/TestSceneNewsSidebar.cs b/osu.Game.Tests/Visual/Online/TestSceneNewsSidebar.cs index f28eaf5ad0..266e98db15 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNewsSidebar.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNewsSidebar.cs @@ -219,7 +219,7 @@ namespace osu.Game.Tests.Visual.Online { base.LoadComplete(); - Metadata.BindValueChanged(metadata => + Metadata.BindValueChanged(_ => { foreach (var b in this.ChildrenOfType()) b.Action = () => YearChanged?.Invoke(b.Year); diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs index a46e675370..8a04cd96fe 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs @@ -187,8 +187,8 @@ namespace osu.Game.Tests.Visual.Playlists // pre-check for requests we should be handling (as they are scheduled below). switch (request) { - case ShowPlaylistUserScoreRequest _: - case IndexPlaylistScoresRequest _: + case ShowPlaylistUserScoreRequest: + case IndexPlaylistScoresRequest: break; default: diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs index abf65602f9..9791bb6248 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs @@ -76,7 +76,7 @@ namespace osu.Game.Tests.Visual.Settings public void ToggleVisibility() { AddWaitStep("wait some", 5); - AddToggleStep("toggle visibility", visible => settings.ToggleVisibility()); + AddToggleStep("toggle visibility", _ => settings.ToggleVisibility()); } [Test] diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs index 6490fd822e..f9d18f4236 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs @@ -91,19 +91,19 @@ namespace osu.Game.Tests.Visual.SongSelect switch (instance) { - case OsuRuleset _: + case OsuRuleset: testInfoLabels(5); break; - case TaikoRuleset _: + case TaikoRuleset: testInfoLabels(5); break; - case CatchRuleset _: + case CatchRuleset: testInfoLabels(5); break; - case ManiaRuleset _: + case ManiaRuleset: testInfoLabels(4); break; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs index 6cf66963a5..368babc9b5 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs @@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Set time before zero", () => { - beatContainer.NewBeat = (i, timingControlPoint, effectControlPoint, channelAmplitudes) => + beatContainer.NewBeat = (i, timingControlPoint, _, _) => { lastActuationTime = gameplayClockContainer.CurrentTime; lastTimingPoint = timingControlPoint; @@ -105,7 +105,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Set time before zero", () => { - beatContainer.NewBeat = (i, timingControlPoint, effectControlPoint, channelAmplitudes) => + beatContainer.NewBeat = (i, timingControlPoint, _, _) => { lastBeatIndex = i; lastBpm = timingControlPoint.BPM; @@ -126,7 +126,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("bind event", () => { - beatContainer.NewBeat = (i, timingControlPoint, effectControlPoint, channelAmplitudes) => lastBpm = timingControlPoint.BPM; + beatContainer.NewBeat = (_, timingControlPoint, _, _) => lastBpm = timingControlPoint.BPM; }); AddUntilStep("wait for trigger", () => lastBpm != null); @@ -157,7 +157,7 @@ namespace osu.Game.Tests.Visual.UserInterface actualEffectPoint = null; beatContainer.AllowMistimedEventFiring = false; - beatContainer.NewBeat = (i, timingControlPoint, effectControlPoint, channelAmplitudes) => + beatContainer.NewBeat = (_, _, effectControlPoint, _) => { if (Precision.AlmostEquals(gameplayClockContainer.CurrentTime + earlyActivationMilliseconds, expectedEffectPoint.Time, BeatSyncedContainer.MISTIMED_ALLOWANCE)) actualEffectPoint = effectControlPoint; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs index 1107fad834..44f2da2b95 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs @@ -77,13 +77,13 @@ namespace osu.Game.Tests.Visual.UserInterface }; control.Query.BindValueChanged(q => query.Text = $"Query: {q.NewValue}", true); - control.General.BindCollectionChanged((u, v) => general.Text = $"General: {(control.General.Any() ? string.Join('.', control.General.Select(i => i.ToString().Underscore())) : "")}", true); + control.General.BindCollectionChanged((_, _) => general.Text = $"General: {(control.General.Any() ? string.Join('.', control.General.Select(i => i.ToString().Underscore())) : "")}", true); control.Ruleset.BindValueChanged(r => ruleset.Text = $"Ruleset: {r.NewValue}", true); control.Category.BindValueChanged(c => category.Text = $"Category: {c.NewValue}", true); control.Genre.BindValueChanged(g => genre.Text = $"Genre: {g.NewValue}", true); control.Language.BindValueChanged(l => language.Text = $"Language: {l.NewValue}", true); - control.Extra.BindCollectionChanged((u, v) => extra.Text = $"Extra: {(control.Extra.Any() ? string.Join('.', control.Extra.Select(i => i.ToString().ToLowerInvariant())) : "")}", true); - control.Ranks.BindCollectionChanged((u, v) => ranks.Text = $"Ranks: {(control.Ranks.Any() ? string.Join('.', control.Ranks.Select(i => i.ToString())) : "")}", true); + control.Extra.BindCollectionChanged((_, _) => extra.Text = $"Extra: {(control.Extra.Any() ? string.Join('.', control.Extra.Select(i => i.ToString().ToLowerInvariant())) : "")}", true); + control.Ranks.BindCollectionChanged((_, _) => ranks.Text = $"Ranks: {(control.Ranks.Any() ? string.Join('.', control.Ranks.Select(i => i.ToString())) : "")}", true); control.Played.BindValueChanged(p => played.Text = $"Played: {p.NewValue}", true); control.ExplicitContent.BindValueChanged(e => explicitMap.Text = $"Explicit Maps: {e.NewValue}", true); }); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs index a3ae55670a..b845b85e1f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs @@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.UserInterface notificationOverlay.Reset(); performer.Setup(g => g.PerformFromScreen(It.IsAny>(), It.IsAny>())) - .Callback((Action action, IEnumerable types) => action(null)); + .Callback((Action action, IEnumerable _) => action(null)); notificationOverlay.Setup(n => n.Post(It.IsAny())) .Callback((Notification n) => lastNotification = n); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 31061dc109..006707d064 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -387,7 +387,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("double time not visible", () => modSelectOverlay.ChildrenOfType().Where(panel => panel.Mod is OsuModDoubleTime).All(panel => panel.Filtered.Value)); AddAssert("nightcore still visible", () => modSelectOverlay.ChildrenOfType().Where(panel => panel.Mod is OsuModNightcore).Any(panel => !panel.Filtered.Value)); - AddStep("make double time valid again", () => modSelectOverlay.IsValidMod = m => true); + AddStep("make double time valid again", () => modSelectOverlay.IsValidMod = _ => true); AddUntilStep("double time visible", () => modSelectOverlay.ChildrenOfType().Where(panel => panel.Mod is OsuModDoubleTime).Any(panel => !panel.Filtered.Value)); AddAssert("nightcore still visible", () => modSelectOverlay.ChildrenOfType().Where(b => b.Mod is OsuModNightcore).Any(panel => !panel.Filtered.Value)); } diff --git a/osu.Game.Tournament/Components/DateTextBox.cs b/osu.Game.Tournament/Components/DateTextBox.cs index 8eccb9e0e0..76d12a6b03 100644 --- a/osu.Game.Tournament/Components/DateTextBox.cs +++ b/osu.Game.Tournament/Components/DateTextBox.cs @@ -30,7 +30,7 @@ namespace osu.Game.Tournament.Components { base.Current = new Bindable(string.Empty); - ((OsuTextBox)Control).OnCommit += (sender, newText) => + ((OsuTextBox)Control).OnCommit += (sender, _) => { try { diff --git a/osu.Game.Tournament/Components/DrawableTeamFlag.cs b/osu.Game.Tournament/Components/DrawableTeamFlag.cs index 6e9c1120e4..348fd8cd76 100644 --- a/osu.Game.Tournament/Components/DrawableTeamFlag.cs +++ b/osu.Game.Tournament/Components/DrawableTeamFlag.cs @@ -45,7 +45,7 @@ namespace osu.Game.Tournament.Components FillMode = FillMode.Fill }; - (flag = team.FlagName.GetBoundCopy()).BindValueChanged(acronym => flagSprite.Texture = textures.Get($@"Flags/{team.FlagName}"), true); + (flag = team.FlagName.GetBoundCopy()).BindValueChanged(_ => flagSprite.Texture = textures.Get($@"Flags/{team.FlagName}"), true); } } } diff --git a/osu.Game.Tournament/Components/DrawableTeamTitle.cs b/osu.Game.Tournament/Components/DrawableTeamTitle.cs index b7e936026c..e64e08a921 100644 --- a/osu.Game.Tournament/Components/DrawableTeamTitle.cs +++ b/osu.Game.Tournament/Components/DrawableTeamTitle.cs @@ -27,7 +27,7 @@ namespace osu.Game.Tournament.Components { if (team == null) return; - (acronym = team.Acronym.GetBoundCopy()).BindValueChanged(acronym => Text.Text = team?.FullName.Value ?? string.Empty, true); + (acronym = team.Acronym.GetBoundCopy()).BindValueChanged(_ => Text.Text = team?.FullName.Value ?? string.Empty, true); } } } diff --git a/osu.Game.Tournament/Components/DrawableTournamentTeam.cs b/osu.Game.Tournament/Components/DrawableTournamentTeam.cs index 84cae92a39..eb1dde21e7 100644 --- a/osu.Game.Tournament/Components/DrawableTournamentTeam.cs +++ b/osu.Game.Tournament/Components/DrawableTournamentTeam.cs @@ -38,7 +38,7 @@ namespace osu.Game.Tournament.Components { if (Team == null) return; - (acronym = Team.Acronym.GetBoundCopy()).BindValueChanged(acronym => AcronymText.Text = Team?.Acronym.Value?.ToUpperInvariant() ?? string.Empty, true); + (acronym = Team.Acronym.GetBoundCopy()).BindValueChanged(_ => AcronymText.Text = Team?.Acronym.Value?.ToUpperInvariant() ?? string.Empty, true); } } } diff --git a/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs b/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs index 58ba3c1e8b..32da4d1b36 100644 --- a/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs +++ b/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs @@ -219,7 +219,7 @@ namespace osu.Game.Tournament.Screens.Drawings } } - writeOp = writeOp?.ContinueWith(t => { writeAction(); }) ?? Task.Run(writeAction); + writeOp = writeOp?.ContinueWith(_ => { writeAction(); }) ?? Task.Run(writeAction); } private void reloadTeams() diff --git a/osu.Game.Tournament/Screens/Editors/LadderEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/LadderEditorScreen.cs index 6052bcdeb7..4261828df2 100644 --- a/osu.Game.Tournament/Screens/Editors/LadderEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/LadderEditorScreen.cs @@ -44,7 +44,7 @@ namespace osu.Game.Tournament.Screens.Editors AddInternal(rightClickMessage = new WarningBox("Right click to place and link matches")); - LadderInfo.Matches.CollectionChanged += (_, __) => updateMessage(); + LadderInfo.Matches.CollectionChanged += (_, _) => updateMessage(); updateMessage(); } diff --git a/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs b/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs index 544725996a..466b9ed482 100644 --- a/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs +++ b/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs @@ -49,10 +49,10 @@ namespace osu.Game.Tournament.Screens.Ladder.Components }; name = round.Name.GetBoundCopy(); - name.BindValueChanged(n => textName.Text = ((losers ? "Losers " : "") + round.Name).ToUpperInvariant(), true); + name.BindValueChanged(_ => textName.Text = ((losers ? "Losers " : "") + round.Name).ToUpperInvariant(), true); description = round.Description.GetBoundCopy(); - description.BindValueChanged(n => textDescription.Text = round.Description.Value?.ToUpperInvariant(), true); + description.BindValueChanged(_ => textDescription.Text = round.Description.Value?.ToUpperInvariant(), true); } } } diff --git a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs index f274503894..23bfa84afc 100644 --- a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs +++ b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs @@ -75,7 +75,7 @@ namespace osu.Game.Tournament.Screens.Ladder foreach (var match in LadderInfo.Matches) addMatch(match); - LadderInfo.Rounds.CollectionChanged += (_, __) => layout.Invalidate(); + LadderInfo.Rounds.CollectionChanged += (_, _) => layout.Invalidate(); LadderInfo.Matches.CollectionChanged += (_, args) => { switch (args.Action) diff --git a/osu.Game.Tournament/TournamentGame.cs b/osu.Game.Tournament/TournamentGame.cs index c2c6c271cb..537fbfc038 100644 --- a/osu.Game.Tournament/TournamentGame.cs +++ b/osu.Game.Tournament/TournamentGame.cs @@ -137,7 +137,7 @@ namespace osu.Game.Tournament heightWarning.Alpha = size.NewValue.Width < minWidth ? 1 : 0; }), true); - windowMode.BindValueChanged(mode => ScheduleAfterChildren(() => + windowMode.BindValueChanged(_ => ScheduleAfterChildren(() => { windowMode.Value = WindowMode.Windowed; }), true); diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 95d2adc4fa..ccbe77fa95 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -267,7 +267,7 @@ namespace osu.Game.Tournament } else { - req.Success += res => { populate(); }; + req.Success += _ => { populate(); }; req.Failure += _ => { user.OnlineID = 1; diff --git a/osu.Game.Tournament/TournamentSceneManager.cs b/osu.Game.Tournament/TournamentSceneManager.cs index afbfc2d368..296b259d72 100644 --- a/osu.Game.Tournament/TournamentSceneManager.cs +++ b/osu.Game.Tournament/TournamentSceneManager.cs @@ -204,12 +204,12 @@ namespace osu.Game.Tournament switch (currentScreen) { - case MapPoolScreen _: + case MapPoolScreen: chatContainer.FadeIn(TournamentScreen.FADE_DELAY); chatContainer.ResizeWidthTo(1, 500, Easing.OutQuint); break; - case GameplayScreen _: + case GameplayScreen: chatContainer.FadeIn(TournamentScreen.FADE_DELAY); chatContainer.ResizeWidthTo(0.5f, 500, Easing.OutQuint); break; diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index eda7ef0bcc..4be6b5eede 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -254,12 +254,12 @@ namespace osu.Game.Beatmaps.ControlPoints switch (newPoint) { - case TimingControlPoint _: + case TimingControlPoint: // Timing points are a special case and need to be added regardless of fallback availability. existing = BinarySearch(TimingPoints, time); break; - case EffectControlPoint _: + case EffectControlPoint: existing = EffectPointAt(time); break; } diff --git a/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs b/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs index 9b97df906b..80af4108c7 100644 --- a/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs +++ b/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs @@ -102,7 +102,7 @@ namespace osu.Game.Beatmaps.Drawables // Matches osu-stable, in order to provide new users with roughly the same randomised selection of bundled beatmaps. var random = new LegacyRandom(DateTime.UtcNow.Year * 1000 + (DateTime.UtcNow.DayOfYear / 7)); - downloadableFilenames.AddRange(sourceFilenames.OrderBy(x => random.NextDouble()).Take(limit ?? int.MaxValue)); + downloadableFilenames.AddRange(sourceFilenames.OrderBy(_ => random.NextDouble()).Take(limit ?? int.MaxValue)); } catch { } } diff --git a/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs index 2f11c18993..4f292a9a1f 100644 --- a/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs @@ -12,7 +12,7 @@ namespace osu.Game.Beatmaps.Formats { public static void Register() { - AddDecoder("{", m => new JsonBeatmapDecoder()); + AddDecoder("{", _ => new JsonBeatmapDecoder()); } protected override void ParseStreamInto(LineBufferedReader stream, Beatmap output) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index 984e88d3a9..03c63ff4f2 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -373,11 +373,11 @@ namespace osu.Game.Beatmaps.Formats switch (hitObject) { - case IHasPath _: + case IHasPath: type |= LegacyHitObjectType.Slider; break; - case IHasDuration _: + case IHasDuration: if (onlineRulesetID == 3) type |= LegacyHitObjectType.Hold; else diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index 3021688aaf..b8f60f0bc6 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -35,7 +35,7 @@ namespace osu.Game.Beatmaps.Formats { // note that this isn't completely correct AddDecoder(@"osu file format v", m => new LegacyStoryboardDecoder(Parsing.ParseInt(m.Split('v').Last()))); - AddDecoder(@"[Events]", m => new LegacyStoryboardDecoder()); + AddDecoder(@"[Events]", _ => new LegacyStoryboardDecoder()); SetFallbackDecoder(() => new LegacyStoryboardDecoder()); } diff --git a/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs b/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs index 19432f0c58..5c3c72c9e4 100644 --- a/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs +++ b/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs @@ -56,12 +56,12 @@ namespace osu.Game.Beatmaps.Legacy { switch (newPoint) { - case SampleControlPoint _: + case SampleControlPoint: // intentionally don't use SamplePointAt (we always need to consider the first sample point). var existing = BinarySearch(SamplePoints, time); return newPoint.IsRedundant(existing); - case DifficultyControlPoint _: + case DifficultyControlPoint: return newPoint.IsRedundant(DifficultyPointAt(time)); default: diff --git a/osu.Game/Collections/BeatmapCollection.cs b/osu.Game/Collections/BeatmapCollection.cs index 23b2ef60dd..742d757bec 100644 --- a/osu.Game/Collections/BeatmapCollection.cs +++ b/osu.Game/Collections/BeatmapCollection.cs @@ -36,7 +36,7 @@ namespace osu.Game.Collections public BeatmapCollection() { - BeatmapHashes.CollectionChanged += (_, __) => onChange(); + BeatmapHashes.CollectionChanged += (_, _) => onChange(); Name.ValueChanged += _ => onChange(); } diff --git a/osu.Game/Collections/CollectionFilterDropdown.cs b/osu.Game/Collections/CollectionFilterDropdown.cs index 46d90b930c..d099eb6e1b 100644 --- a/osu.Game/Collections/CollectionFilterDropdown.cs +++ b/osu.Game/Collections/CollectionFilterDropdown.cs @@ -67,7 +67,7 @@ namespace osu.Game.Collections // An extra bindable is enough to subvert this behaviour. base.Current = Current; - collections.BindCollectionChanged((_, __) => collectionsChanged(), true); + collections.BindCollectionChanged((_, _) => collectionsChanged(), true); Current.BindValueChanged(filterChanged, true); } @@ -233,7 +233,7 @@ namespace osu.Game.Collections if (collectionBeatmaps != null) { - collectionBeatmaps.CollectionChanged += (_, __) => collectionChanged(); + collectionBeatmaps.CollectionChanged += (_, _) => collectionChanged(); beatmap.BindValueChanged(_ => collectionChanged(), true); } diff --git a/osu.Game/Collections/CollectionManager.cs b/osu.Game/Collections/CollectionManager.cs index c6e52a1b75..796b3c426c 100644 --- a/osu.Game/Collections/CollectionManager.cs +++ b/osu.Game/Collections/CollectionManager.cs @@ -261,7 +261,7 @@ namespace osu.Game.Collections private void backgroundSave() { int current = Interlocked.Increment(ref lastSave); - Task.Delay(100).ContinueWith(task => + Task.Delay(100).ContinueWith(_ => { if (current != lastSave) return; diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 68f9dcb541..3ea7a14826 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -454,7 +454,7 @@ namespace osu.Game.Database public IDisposable SubscribeToPropertyChanged(Func modelAccessor, Expression> propertyLookup, Action onChanged) where TModel : RealmObjectBase { - return RegisterCustomSubscription(r => + return RegisterCustomSubscription(_ => { string propertyName = getMemberName(propertyLookup); diff --git a/osu.Game/Database/RealmObjectExtensions.cs b/osu.Game/Database/RealmObjectExtensions.cs index 25416c7fa2..a771aa04df 100644 --- a/osu.Game/Database/RealmObjectExtensions.cs +++ b/osu.Game/Database/RealmObjectExtensions.cs @@ -20,7 +20,7 @@ namespace osu.Game.Database { private static readonly IMapper write_mapper = new MapperConfiguration(c => { - c.ShouldMapField = fi => false; + c.ShouldMapField = _ => false; c.ShouldMapProperty = pi => pi.SetMethod?.IsPublic == true; c.CreateMap() @@ -70,7 +70,7 @@ namespace osu.Game.Database } }); - c.Internal().ForAllMaps((typeMap, expression) => + c.Internal().ForAllMaps((_, expression) => { expression.ForAllMembers(m => { @@ -87,7 +87,7 @@ namespace osu.Game.Database c.CreateMap() .ConstructUsing(_ => new BeatmapSetInfo(null)) .MaxDepth(2) - .AfterMap((s, d) => + .AfterMap((_, d) => { foreach (var beatmap in d.Beatmaps) beatmap.BeatmapSet = d; @@ -97,7 +97,7 @@ namespace osu.Game.Database // Only hasn't been done yet as we detach at the point of BeatmapInfo less often. c.CreateMap() .MaxDepth(2) - .AfterMap((s, d) => + .AfterMap((_, d) => { for (int i = 0; i < d.BeatmapSet?.Beatmaps.Count; i++) { @@ -121,7 +121,7 @@ namespace osu.Game.Database .ConstructUsing(_ => new BeatmapSetInfo(null)) .MaxDepth(2) .ForMember(b => b.Files, cc => cc.Ignore()) - .AfterMap((s, d) => + .AfterMap((_, d) => { foreach (var beatmap in d.Beatmaps) beatmap.BeatmapSet = d; @@ -135,14 +135,14 @@ namespace osu.Game.Database private static void applyCommonConfiguration(IMapperConfigurationExpression c) { - c.ShouldMapField = fi => false; + c.ShouldMapField = _ => false; // This is specifically to avoid mapping explicit interface implementations. // If we want to limit this further, we can avoid mapping properties with no setter that are not IList<>. // Takes a bit of effort to determine whether this is the case though, see https://stackoverflow.com/questions/951536/how-do-i-tell-whether-a-type-implements-ilist c.ShouldMapProperty = pi => pi.GetMethod?.IsPublic == true; - c.Internal().ForAllMaps((typeMap, expression) => + c.Internal().ForAllMaps((_, expression) => { expression.ForAllMembers(m => { diff --git a/osu.Game/Extensions/TaskExtensions.cs b/osu.Game/Extensions/TaskExtensions.cs index 5165ae59b5..b4a0c02e35 100644 --- a/osu.Game/Extensions/TaskExtensions.cs +++ b/osu.Game/Extensions/TaskExtensions.cs @@ -31,7 +31,7 @@ namespace osu.Game.Extensions { var tcs = new TaskCompletionSource(); - task.ContinueWith(t => + task.ContinueWith(_ => { // the previous task has finished execution or been cancelled, so we can run the provided continuation. diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs index aa156efee9..a2370a76cb 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs @@ -27,7 +27,7 @@ namespace osu.Game.Graphics.Containers.Markdown { switch (markdownObject) { - case YamlFrontMatterBlock _: + case YamlFrontMatterBlock: // Don't parse YAML Frontmatter break; diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index 00ed6c1c92..f55875ac58 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -74,7 +74,7 @@ namespace osu.Game.Graphics.UserInterface } //I'm using ToList() here because Where() returns an Enumerable which can change it's elements afterwards - RemoveRange(Children.Where((bar, index) => index >= value.Count()).ToList()); + RemoveRange(Children.Where((_, index) => index >= value.Count()).ToList()); } } } diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index 407823fc2a..b3655eaab4 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -55,12 +55,12 @@ namespace osu.Game.Graphics.UserInterface switch (e) { // blocking scroll can cause weird behaviour when this layer is used within a ScrollContainer. - case ScrollEvent _: + case ScrollEvent: return false; // blocking touch events causes the ISourcedFromTouch versions to not be fired, potentially impeding behaviour of drawables *above* the loading layer that may utilise these. // note that this will not work well if touch handling elements are beneath this loading layer (something to consider for the future). - case TouchEvent _: + case TouchEvent: return false; } diff --git a/osu.Game/Graphics/UserInterface/StarCounter.cs b/osu.Game/Graphics/UserInterface/StarCounter.cs index a8051a94d9..d9274bf2cb 100644 --- a/osu.Game/Graphics/UserInterface/StarCounter.cs +++ b/osu.Game/Graphics/UserInterface/StarCounter.cs @@ -68,7 +68,7 @@ namespace osu.Game.Graphics.UserInterface AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, Spacing = new Vector2(star_spacing), - ChildrenEnumerable = Enumerable.Range(0, StarCount).Select(i => CreateStar()) + ChildrenEnumerable = Enumerable.Range(0, StarCount).Select(_ => CreateStar()) } }; } diff --git a/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs b/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs index 974abc4036..14a041b459 100644 --- a/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs +++ b/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs @@ -51,7 +51,7 @@ namespace osu.Game.Input.Bindings protected override void LoadComplete() { - realmSubscription = realm.RegisterForNotifications(queryRealmKeyBindings, (sender, changes, error) => + realmSubscription = realm.RegisterForNotifications(queryRealmKeyBindings, (sender, _, _) => { // The first fire of this is a bit redundant as this is being called in base.LoadComplete, // but this is safest in case the subscription is restored after a context recycle. diff --git a/osu.Game/Input/IdleTracker.cs b/osu.Game/Input/IdleTracker.cs index 279cfb5a4e..45036b3e41 100644 --- a/osu.Game/Input/IdleTracker.cs +++ b/osu.Game/Input/IdleTracker.cs @@ -80,11 +80,11 @@ namespace osu.Game.Input switch (e) { - case KeyDownEvent _: - case KeyUpEvent _: - case MouseDownEvent _: - case MouseUpEvent _: - case MouseMoveEvent _: + case KeyDownEvent: + case KeyUpEvent: + case MouseDownEvent: + case MouseUpEvent: + case MouseMoveEvent: return updateLastInteractionTime(); default: diff --git a/osu.Game/Online/BeatmapDownloadTracker.cs b/osu.Game/Online/BeatmapDownloadTracker.cs index 1e3add6201..19708cc07d 100644 --- a/osu.Game/Online/BeatmapDownloadTracker.cs +++ b/osu.Game/Online/BeatmapDownloadTracker.cs @@ -40,7 +40,7 @@ namespace osu.Game.Online // Used to interact with manager classes that don't support interface types. Will eventually be replaced. var beatmapSetInfo = new BeatmapSetInfo { OnlineID = TrackedItem.OnlineID }; - realmSubscription = realm.RegisterForNotifications(r => r.All().Where(s => s.OnlineID == TrackedItem.OnlineID && !s.DeletePending), (items, changes, ___) => + realmSubscription = realm.RegisterForNotifications(r => r.All().Where(s => s.OnlineID == TrackedItem.OnlineID && !s.DeletePending), (items, _, _) => { if (items.Any()) Schedule(() => UpdateState(DownloadState.LocallyAvailable)); diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 4c762d002d..48dfaadfa5 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -465,7 +465,7 @@ namespace osu.Game.Online.Chat default: var req = new JoinChannelRequest(channel); req.Success += () => joinChannel(channel, fetchInitialMessages); - req.Failure += ex => LeaveChannel(channel); + req.Failure += _ => LeaveChannel(channel); api.Queue(req); return channel; } diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index f9000c01ef..61e9eaa8c0 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -64,7 +64,7 @@ namespace osu.Game.Online this.preferMessagePack = preferMessagePack; apiState.BindTo(api.State); - apiState.BindValueChanged(state => connectIfPossible(), true); + apiState.BindValueChanged(_ => connectIfPossible(), true); } public void Reconnect() diff --git a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs index 032215f5d3..2fd8445980 100644 --- a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs @@ -101,7 +101,7 @@ namespace osu.Game.Online.Rooms // handles changes to hash that didn't occur from the import process (ie. a user editing the beatmap in the editor, somehow). realmSubscription?.Dispose(); - realmSubscription = realm.RegisterForNotifications(r => filteredBeatmaps(), (items, changes, ___) => + realmSubscription = realm.RegisterForNotifications(_ => filteredBeatmaps(), (_, changes, _) => { if (changes == null) return; diff --git a/osu.Game/Online/ScoreDownloadTracker.cs b/osu.Game/Online/ScoreDownloadTracker.cs index cab6bd0722..680bb16264 100644 --- a/osu.Game/Online/ScoreDownloadTracker.cs +++ b/osu.Game/Online/ScoreDownloadTracker.cs @@ -48,7 +48,7 @@ namespace osu.Game.Online realmSubscription = realm.RegisterForNotifications(r => r.All().Where(s => ((s.OnlineID > 0 && s.OnlineID == TrackedItem.OnlineID) || (!string.IsNullOrEmpty(s.Hash) && s.Hash == TrackedItem.Hash)) - && !s.DeletePending), (items, changes, ___) => + && !s.DeletePending), (items, _, _) => { if (items.Any()) Schedule(() => UpdateState(DownloadState.LocallyAvailable)); diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 1d9e2042ec..b0ba62a6ac 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -481,7 +481,7 @@ namespace osu.Game { switch (handler) { - case MidiHandler _: + case MidiHandler: return new InputSection.HandlerSection(handler); // return null for handlers that shouldn't have settings. diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs index 4457705676..767b8646e3 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs @@ -161,13 +161,13 @@ namespace osu.Game.Overlays.BeatmapListing queueUpdateSearch(true); }); - searchControl.General.CollectionChanged += (_, __) => queueUpdateSearch(); + searchControl.General.CollectionChanged += (_, _) => queueUpdateSearch(); searchControl.Ruleset.BindValueChanged(_ => queueUpdateSearch()); searchControl.Category.BindValueChanged(_ => queueUpdateSearch()); searchControl.Genre.BindValueChanged(_ => queueUpdateSearch()); searchControl.Language.BindValueChanged(_ => queueUpdateSearch()); - searchControl.Extra.CollectionChanged += (_, __) => queueUpdateSearch(); - searchControl.Ranks.CollectionChanged += (_, __) => queueUpdateSearch(); + searchControl.Extra.CollectionChanged += (_, _) => queueUpdateSearch(); + searchControl.Ranks.CollectionChanged += (_, _) => queueUpdateSearch(); searchControl.Played.BindValueChanged(_ => queueUpdateSearch()); searchControl.ExplicitContent.BindValueChanged(_ => queueUpdateSearch()); diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 1a57a89957..b27d9b3f1e 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -156,7 +156,7 @@ namespace osu.Game.Overlays.BeatmapSet { base.LoadComplete(); - ruleset.ValueChanged += r => updateDisplay(); + ruleset.ValueChanged += _ => updateDisplay(); // done here so everything can bind in intialization and get the first trigger Beatmap.TriggerChange(); diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 2ea94bb412..c2e54d0d7b 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -217,7 +217,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores scope.BindValueChanged(_ => getScores()); ruleset.BindValueChanged(_ => getScores()); - modSelector.SelectedMods.CollectionChanged += (_, __) => getScores(); + modSelector.SelectedMods.CollectionChanged += (_, _) => getScores(); Beatmap.BindValueChanged(onBeatmapChanged); user.BindValueChanged(onUserChanged, true); diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index 2e8080ba43..e2a7e78356 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -117,7 +117,7 @@ namespace osu.Game.Overlays.Comments } }); - textBox.OnCommit += (u, v) => + textBox.OnCommit += (_, _) => { if (commitButton.IsBlocked.Value) return; diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 4ab6f4f88d..4a836e0e62 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -251,8 +251,8 @@ namespace osu.Game.Overlays.Comments if (bundle.HasMore) { int loadedTopLevelComments = 0; - pinnedContent.Children.OfType().ForEach(p => loadedTopLevelComments++); - content.Children.OfType().ForEach(p => loadedTopLevelComments++); + pinnedContent.Children.OfType().ForEach(_ => loadedTopLevelComments++); + content.Children.OfType().ForEach(_ => loadedTopLevelComments++); moreButton.Current.Value = bundle.TopLevelCount - loadedTopLevelComments; moreButton.IsLoading = false; diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs index bfeaf50b53..bfd356193d 100644 --- a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs +++ b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs @@ -145,7 +145,7 @@ namespace osu.Game.Overlays.Dashboard.Friends controlBackground.Colour = colourProvider.Background5; apiFriends.BindTo(api.Friends); - apiFriends.BindCollectionChanged((_, __) => Schedule(() => Users = apiFriends.ToList()), true); + apiFriends.BindCollectionChanged((_, _) => Schedule(() => Users = apiFriends.ToList()), true); } protected override void LoadComplete() diff --git a/osu.Game/Overlays/Login/LoginForm.cs b/osu.Game/Overlays/Login/LoginForm.cs index 08522b2921..f545e2892f 100644 --- a/osu.Game/Overlays/Login/LoginForm.cs +++ b/osu.Game/Overlays/Login/LoginForm.cs @@ -109,7 +109,7 @@ namespace osu.Game.Overlays.Login } }; - password.OnCommit += (sender, newText) => performLogin(); + password.OnCommit += (_, _) => performLogin(); if (api?.LastLoginError?.Message is string error) errorText.AddErrors(new[] { error }); diff --git a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs index 53e8452dd1..1c007c913e 100644 --- a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs +++ b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs @@ -112,7 +112,7 @@ namespace osu.Game.Overlays.MedalSplash s.Font = s.Font.With(size: 16); }); - medalContainer.OnLoadComplete += d => + medalContainer.OnLoadComplete += _ => { unlocked.Position = new Vector2(0f, medalContainer.DrawSize.Y / 2 + 10); infoFlow.Position = new Vector2(0f, unlocked.Position.Y + 90); diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 811db393d6..69cb3a49fc 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -40,7 +40,7 @@ namespace osu.Game.Overlays.Mods /// public Bindable>> AvailableMods { get; } = new Bindable>>(new Dictionary>()); - private Func isValidMod = m => true; + private Func isValidMod = _ => true; /// /// A function determining whether each mod in the column should be displayed. @@ -689,11 +689,11 @@ namespace osu.Game.Overlays.Mods switch (e) { - case ClickEvent _: + case ClickEvent: OnClicked?.Invoke(); return true; - case MouseEvent _: + case MouseEvent: return true; } diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 3c25fc0421..e33fc8064f 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -85,7 +85,7 @@ namespace osu.Game.Overlays.Music }, }; - filter.Search.OnCommit += (sender, newText) => + filter.Search.OnCommit += (_, _) => { list.FirstVisibleSet?.PerformRead(set => { diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index d76df5b1ed..719e77db83 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -129,7 +129,7 @@ namespace osu.Game.Overlays.Notifications case ProgressNotificationState.Completed: loadingSpinner.Hide(); NotificationContent.MoveToY(-DrawSize.Y / 2, 200, Easing.OutQuint); - this.FadeOut(200).Finally(d => Completed()); + this.FadeOut(200).Finally(_ => Completed()); break; } } diff --git a/osu.Game/Overlays/OSD/TrackedSettingToast.cs b/osu.Game/Overlays/OSD/TrackedSettingToast.cs index c66811a3e9..3bed5e7e4c 100644 --- a/osu.Game/Overlays/OSD/TrackedSettingToast.cs +++ b/osu.Game/Overlays/OSD/TrackedSettingToast.cs @@ -68,7 +68,7 @@ namespace osu.Game.Overlays.OSD if (val) selectedOption = 0; break; - case Enum _: + case Enum: var values = Enum.GetValues(description.RawValue.GetType()); optionCount = values.Length; selectedOption = Convert.ToInt32(description.RawValue); diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 2c8e809379..28642f12a1 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -160,13 +160,13 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics scalingSettings.ForEach(s => bindPreviewEvent(s.Current)); - windowModeDropdown.Current.BindValueChanged(mode => + windowModeDropdown.Current.BindValueChanged(_ => { updateDisplayModeDropdowns(); updateScreenModeWarning(); }, true); - windowModes.BindCollectionChanged((sender, args) => + windowModes.BindCollectionChanged((_, _) => { if (windowModes.Count > 1) windowModeDropdown.Show(); @@ -190,7 +190,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics updateDisplayModeDropdowns(); }), true); - scalingMode.BindValueChanged(mode => + scalingMode.BindValueChanged(_ => { scalingSettings.ClearTransforms(); scalingSettings.AutoSizeDuration = transition_duration; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs index 8c8c2c96ff..453dbd2e18 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { importBeatmapsButton.Enabled.Value = false; - legacyImportManager.ImportFromStableAsync(StableContent.Beatmaps).ContinueWith(t => Schedule(() => importBeatmapsButton.Enabled.Value = true)); + legacyImportManager.ImportFromStableAsync(StableContent.Beatmaps).ContinueWith(_ => Schedule(() => importBeatmapsButton.Enabled.Value = true)); } }); } @@ -45,7 +45,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => { deleteBeatmapsButton.Enabled.Value = false; - Task.Run(() => beatmaps.Delete()).ContinueWith(t => Schedule(() => deleteBeatmapsButton.Enabled.Value = true)); + Task.Run(() => beatmaps.Delete()).ContinueWith(_ => Schedule(() => deleteBeatmapsButton.Enabled.Value = true)); })); } }); @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance dialogOverlay?.Push(new MassVideoDeleteConfirmationDialog(() => { deleteBeatmapVideosButton.Enabled.Value = false; - Task.Run(beatmaps.DeleteAllVideos).ContinueWith(t => Schedule(() => deleteBeatmapVideosButton.Enabled.Value = true)); + Task.Run(beatmaps.DeleteAllVideos).ContinueWith(_ => Schedule(() => deleteBeatmapVideosButton.Enabled.Value = true)); })); } }); @@ -70,7 +70,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { restoreButton.Enabled.Value = false; - Task.Run(beatmaps.RestoreAll).ContinueWith(t => Schedule(() => restoreButton.Enabled.Value = true)); + Task.Run(beatmaps.RestoreAll).ContinueWith(_ => Schedule(() => restoreButton.Enabled.Value = true)); } }, undeleteButton = new SettingsButton @@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { undeleteButton.Enabled.Value = false; - Task.Run(beatmaps.UndeleteAll).ContinueWith(t => Schedule(() => undeleteButton.Enabled.Value = true)); + Task.Run(beatmaps.UndeleteAll).ContinueWith(_ => Schedule(() => undeleteButton.Enabled.Value = true)); } } }); diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs index 74e9ebc084..5367f644ca 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { importCollectionsButton.Enabled.Value = false; - legacyImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(t => Schedule(() => importCollectionsButton.Enabled.Value = true)); + legacyImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(_ => Schedule(() => importCollectionsButton.Enabled.Value = true)); } }); } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs index 9c1281f371..70e11d45dc 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { importScoresButton.Enabled.Value = false; - legacyImportManager.ImportFromStableAsync(StableContent.Scores).ContinueWith(t => Schedule(() => importScoresButton.Enabled.Value = true)); + legacyImportManager.ImportFromStableAsync(StableContent.Scores).ContinueWith(_ => Schedule(() => importScoresButton.Enabled.Value = true)); } }); } @@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => { deleteScoresButton.Enabled.Value = false; - Task.Run(() => scores.Delete()).ContinueWith(t => Schedule(() => deleteScoresButton.Enabled.Value = true)); + Task.Run(() => scores.Delete()).ContinueWith(_ => Schedule(() => deleteScoresButton.Enabled.Value = true)); })); } }); diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs index 0fff9fef26..c95b1d4dd8 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Action = () => { importSkinsButton.Enabled.Value = false; - legacyImportManager.ImportFromStableAsync(StableContent.Skins).ContinueWith(t => Schedule(() => importSkinsButton.Enabled.Value = true)); + legacyImportManager.ImportFromStableAsync(StableContent.Skins).ContinueWith(_ => Schedule(() => importSkinsButton.Enabled.Value = true)); } }); } @@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => { deleteSkinsButton.Enabled.Value = false; - Task.Run(() => skins.Delete()).ContinueWith(t => Schedule(() => deleteSkinsButton.Enabled.Value = true)); + Task.Run(() => skins.Delete()).ContinueWith(_ => Schedule(() => deleteSkinsButton.Enabled.Value = true)); })); } }); diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 6494b59b09..741b6b5815 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -82,12 +82,12 @@ namespace osu.Game.Overlays.Settings.Sections skinDropdown.Current = dropdownBindable; - realmSubscription = realm.RegisterForNotifications(r => realm.Realm.All() + realmSubscription = realm.RegisterForNotifications(_ => realm.Realm.All() .Where(s => !s.DeletePending) .OrderByDescending(s => s.Protected) // protected skins should be at the top. .ThenBy(s => s.Name, StringComparer.OrdinalIgnoreCase), skinsChanged); - configBindable.BindValueChanged(id => Scheduler.AddOnce(updateSelectedSkinFromConfig)); + configBindable.BindValueChanged(_ => Scheduler.AddOnce(updateSelectedSkinFromConfig)); dropdownBindable.BindValueChanged(dropdownSelectionChanged); } diff --git a/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs b/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs index 6c56f3a912..5a03d66b84 100644 --- a/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs +++ b/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs @@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Configuration databasedSettings.Add(setting); } - bindable.ValueChanged += b => + bindable.ValueChanged += _ => { lock (pendingWrites) pendingWrites.Add(lookup); diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs index 3e93e576ba..c8196b6865 100644 --- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -129,10 +129,10 @@ namespace osu.Game.Rulesets.Edit switch (e) { - case ScrollEvent _: + case ScrollEvent: return false; - case DoubleClickEvent _: + case DoubleClickEvent: return false; case MouseButtonEvent mouse: diff --git a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs index 9307e36b99..a42d4a049a 100644 --- a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs +++ b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs @@ -55,8 +55,8 @@ namespace osu.Game.Rulesets.Mods { base.LoadComplete(); - Current.BindValueChanged(current => updateCurrentFromSlider()); - beatmap.BindValueChanged(b => updateCurrentFromSlider(), true); + Current.BindValueChanged(_ => updateCurrentFromSlider()); + beatmap.BindValueChanged(_ => updateCurrentFromSlider(), true); sliderDisplayCurrent.BindValueChanged(number => { diff --git a/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs b/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs index 2f5707562e..aea6e12a07 100644 --- a/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs +++ b/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs @@ -165,7 +165,7 @@ namespace osu.Game.Rulesets.Mods public void ApplyToDrawableHitObject(DrawableHitObject drawable) { - drawable.OnNewResult += (o, result) => + drawable.OnNewResult += (_, result) => { if (ratesForRewinding.ContainsKey(result.HitObject)) return; if (!shouldProcessResult(result)) return; @@ -177,7 +177,7 @@ namespace osu.Game.Rulesets.Mods updateTargetRate(); }; - drawable.OnRevertResult += (o, result) => + drawable.OnRevertResult += (_, result) => { if (!ratesForRewinding.ContainsKey(result.HitObject)) return; if (!shouldProcessResult(result)) return; diff --git a/osu.Game/Rulesets/Mods/ModTimeRamp.cs b/osu.Game/Rulesets/Mods/ModTimeRamp.cs index a1aad3a6b9..daa4b7c797 100644 --- a/osu.Game/Rulesets/Mods/ModTimeRamp.cs +++ b/osu.Game/Rulesets/Mods/ModTimeRamp.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Mods protected ModTimeRamp() { // for preview purpose at song select. eventually we'll want to be able to update every frame. - FinalRate.BindValueChanged(val => applyRateAdjustment(double.PositiveInfinity), true); + FinalRate.BindValueChanged(_ => applyRateAdjustment(double.PositiveInfinity), true); AdjustPitch.BindValueChanged(applyPitchAdjustment); } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 8bde71dcd7..e098472999 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -126,55 +126,55 @@ namespace osu.Game.Rulesets { switch (mod) { - case ModNoFail _: + case ModNoFail: value |= LegacyMods.NoFail; break; - case ModEasy _: + case ModEasy: value |= LegacyMods.Easy; break; - case ModHidden _: + case ModHidden: value |= LegacyMods.Hidden; break; - case ModHardRock _: + case ModHardRock: value |= LegacyMods.HardRock; break; - case ModPerfect _: + case ModPerfect: value |= LegacyMods.Perfect; break; - case ModSuddenDeath _: + case ModSuddenDeath: value |= LegacyMods.SuddenDeath; break; - case ModNightcore _: + case ModNightcore: value |= LegacyMods.Nightcore; break; - case ModDoubleTime _: + case ModDoubleTime: value |= LegacyMods.DoubleTime; break; - case ModRelax _: + case ModRelax: value |= LegacyMods.Relax; break; - case ModHalfTime _: + case ModHalfTime: value |= LegacyMods.HalfTime; break; - case ModFlashlight _: + case ModFlashlight: value |= LegacyMods.Flashlight; break; - case ModCinema _: + case ModCinema: value |= LegacyMods.Cinema; break; - case ModAutoplay _: + case ModAutoplay: value |= LegacyMods.Autoplay; break; } diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index f1ed23bb21..7c37913576 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -123,7 +123,7 @@ namespace osu.Game.Rulesets.UI { switch (e) { - case MouseDownEvent _: + case MouseDownEvent: if (mouseDisabled.Value) return true; // importantly, block upwards propagation so global bindings also don't fire. diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs index 82a9db956a..55302833c1 100644 --- a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs @@ -67,7 +67,7 @@ namespace osu.Game.Screens.Edit.Components.TernaryButtons { base.LoadComplete(); - Button.Bindable.BindValueChanged(selected => updateSelectionState(), true); + Button.Bindable.BindValueChanged(_ => updateSelectionState(), true); Action = onAction; } diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs index ee82ded39d..54ef5a2bd7 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts controlPointGroups.UnbindAll(); controlPointGroups.BindTo(beatmap.ControlPointInfo.Groups); - controlPointGroups.BindCollectionChanged((sender, args) => + controlPointGroups.BindCollectionChanged((_, args) => { switch (args.Action) { diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/GroupVisualisation.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/GroupVisualisation.cs index cccb646ba4..e058cae191 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/GroupVisualisation.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/GroupVisualisation.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts // Run in constructor so IsRedundant calls can work correctly. controlPoints.BindTo(Group.ControlPoints); - controlPoints.BindCollectionChanged((_, __) => + controlPoints.BindCollectionChanged((_, _) => { ClearInternal(); @@ -40,15 +40,15 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts { switch (point) { - case TimingControlPoint _: + case TimingControlPoint: AddInternal(new ControlPointVisualisation(point) { Y = 0, }); break; - case DifficultyControlPoint _: + case DifficultyControlPoint: AddInternal(new ControlPointVisualisation(point) { Y = 0.25f, }); break; - case SampleControlPoint _: + case SampleControlPoint: AddInternal(new ControlPointVisualisation(point) { Y = 0.5f, }); break; diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs index c1ae2ff8d1..54914f4b23 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs @@ -38,7 +38,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts { AddInternal(this.content = content ?? new Container { RelativeSizeAxes = Axes.Both }); - beatmap.ValueChanged += b => + beatmap.ValueChanged += _ => { updateRelativeChildSize(); }; diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 6a94fce78a..40403e08ad 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -293,7 +293,7 @@ namespace osu.Game.Screens.Edit.Compose.Components { base.LoadComplete(); BeatDivisor.BindValueChanged(_ => updateState(), true); - divisorTextBox.OnCommit += (_, __) => setPresets(); + divisorTextBox.OnCommit += (_, _) => setPresets(); Schedule(() => GetContainingInputManager().ChangeFocus(divisorTextBox)); } diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index d38aac1173..540fbf9a72 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -55,7 +55,7 @@ namespace osu.Game.Screens.Edit.Compose.Components [BackgroundDependencyLoader] private void load() { - SelectedItems.CollectionChanged += (selectedObjects, args) => + SelectedItems.CollectionChanged += (_, args) => { switch (args.Action) { diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs index 1c9faadda1..0bdfc5b0a0 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Edit.Compose.Components // bring in updates from selection changes EditorBeatmap.HitObjectUpdated += _ => Scheduler.AddOnce(UpdateTernaryStates); - SelectedItems.CollectionChanged += (sender, args) => Scheduler.AddOnce(UpdateTernaryStates); + SelectedItems.CollectionChanged += (_, _) => Scheduler.AddOnce(UpdateTernaryStates); } protected override void DeleteItems(IEnumerable items) => EditorBeatmap.RemoveRange(items); diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 91af3fde16..8419d3b380 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -64,7 +64,7 @@ namespace osu.Game.Screens.Edit.Compose.Components { InternalChild = SelectionBox = CreateSelectionBox(); - SelectedItems.CollectionChanged += (sender, args) => + SelectedItems.CollectionChanged += (_, _) => { Scheduler.AddOnce(updateVisibility); }; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs index 08fc8383c3..648ffd9609 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs @@ -38,8 +38,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline [BackgroundDependencyLoader] private void load() { - volume.BindValueChanged(volume => updateText()); - bank.BindValueChanged(bank => updateText(), true); + volume.BindValueChanged(_ => updateText()); + bank.BindValueChanged(_ => updateText(), true); } protected override bool OnClick(ClickEvent e) @@ -119,7 +119,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline }); // on commit, ensure that the value is correct by sourcing it from the objects' control points again. // this ensures that committing empty text causes a revert to the previous value. - bank.OnCommit += (_, __) => bank.Current.Value = getCommonBank(relevantControlPoints); + bank.OnCommit += (_, _) => bank.Current.Value = getCommonBank(relevantControlPoints); volume.Current.BindValueChanged(val => updateVolumeFor(relevantObjects, val.NewValue)); } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs index 544c3f8369..cfc71256e8 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline controlPointGroups.UnbindAll(); controlPointGroups.BindTo(beatmap.ControlPointInfo.Groups); - controlPointGroups.BindCollectionChanged((sender, args) => + controlPointGroups.BindCollectionChanged((_, args) => { switch (args.Action) { diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs index 4017a745e1..10355045be 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline base.LoadComplete(); controlPoints.BindTo(Group.ControlPoints); - controlPoints.BindCollectionChanged((_, __) => + controlPoints.BindCollectionChanged((_, _) => { ClearInternal(); diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index ef670c9fcf..3d18b00e75 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -89,7 +89,7 @@ namespace osu.Game.Screens.Edit.Compose if (composer == null) return; - EditorBeatmap.SelectedHitObjects.BindCollectionChanged((_, __) => updateClipboardActionAvailability()); + EditorBeatmap.SelectedHitObjects.BindCollectionChanged((_, _) => updateClipboardActionAvailability()); clipboard.BindValueChanged(_ => updateClipboardActionAvailability()); composer.OnLoadComplete += _ => updateClipboardActionAvailability(); updateClipboardActionAvailability(); diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 582c8f5272..0a6f9974b0 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -105,8 +105,8 @@ namespace osu.Game.Screens.Edit { switch (controlPoint) { - case DifficultyControlPoint _: - case SampleControlPoint _: + case DifficultyControlPoint: + case SampleControlPoint: // skip legacy types. continue; diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index 244fd5f1e9..475c894b30 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Edit ComboColours = new BindableList(); if (Skin.Configuration.ComboColours != null) ComboColours.AddRange(Skin.Configuration.ComboColours.Select(c => (Colour4)c)); - ComboColours.BindCollectionChanged((_, __) => updateColours()); + ComboColours.BindCollectionChanged((_, _) => updateColours()); } private void invokeSkinChanged() => BeatmapSkinChanged?.Invoke(); diff --git a/osu.Game/Screens/Edit/Setup/DesignSection.cs b/osu.Game/Screens/Edit/Setup/DesignSection.cs index 12a6843067..40bbfeaf7d 100644 --- a/osu.Game/Screens/Edit/Setup/DesignSection.cs +++ b/osu.Game/Screens/Edit/Setup/DesignSection.cs @@ -100,7 +100,7 @@ namespace osu.Game.Screens.Edit.Setup EnableCountdown.Current.BindValueChanged(_ => updateBeatmap()); CountdownSpeed.Current.BindValueChanged(_ => updateBeatmap()); - CountdownOffset.OnCommit += (_, __) => onOffsetCommitted(); + CountdownOffset.OnCommit += (_, _) => onOffsetCommitted(); widescreenSupport.Current.BindValueChanged(_ => updateBeatmap()); epilepsyWarning.Current.BindValueChanged(_ => updateBeatmap()); diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs index b5c162ab11..b51da2c53d 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs @@ -63,7 +63,7 @@ namespace osu.Game.Screens.Edit.Timing { base.LoadComplete(); - selectedGroup.BindValueChanged(group => + selectedGroup.BindValueChanged(_ => { // TODO: This should scroll the selected row into view. updateSelectedGroup(); @@ -153,7 +153,7 @@ namespace osu.Game.Screens.Edit.Timing protected override void LoadComplete() { base.LoadComplete(); - controlPoints.CollectionChanged += (_, __) => createChildren(); + controlPoints.CollectionChanged += (_, _) => createChildren(); } private void createChildren() diff --git a/osu.Game/Screens/Edit/Timing/LabelledTimeSignature.cs b/osu.Game/Screens/Edit/Timing/LabelledTimeSignature.cs index d05777e793..998e49a6ab 100644 --- a/osu.Game/Screens/Edit/Timing/LabelledTimeSignature.cs +++ b/osu.Game/Screens/Edit/Timing/LabelledTimeSignature.cs @@ -76,7 +76,7 @@ namespace osu.Game.Screens.Edit.Timing base.LoadComplete(); Current.BindValueChanged(_ => updateFromCurrent(), true); - numeratorBox.OnCommit += (_, __) => updateFromNumeratorBox(); + numeratorBox.OnCommit += (_, _) => updateFromNumeratorBox(); } private void updateFromCurrent() diff --git a/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs b/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs index 6a804c7e3e..4dcb5ad2ba 100644 --- a/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs +++ b/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs @@ -70,7 +70,7 @@ namespace osu.Game.Screens.Edit.Timing Current.TriggerChange(); }; - Current.BindValueChanged(val => + Current.BindValueChanged(_ => { decimal decimalValue = slider.Current.Value.ToDecimal(NumberFormatInfo.InvariantInfo); textBox.Text = decimalValue.ToString($@"N{FormatUtils.FindPrecision(decimalValue)}"); diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index c33dcc6e91..fd218209d4 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -137,7 +137,7 @@ namespace osu.Game.Screens.Edit.Timing }, true); controlPointGroups.BindTo(Beatmap.ControlPointInfo.Groups); - controlPointGroups.BindCollectionChanged((sender, args) => + controlPointGroups.BindCollectionChanged((_, _) => { table.ControlGroups = controlPointGroups; changeHandler?.SaveState(); diff --git a/osu.Game/Screens/Edit/Timing/TimingSection.cs b/osu.Game/Screens/Edit/Timing/TimingSection.cs index 8413409d84..9b86969db1 100644 --- a/osu.Game/Screens/Edit/Timing/TimingSection.cs +++ b/osu.Game/Screens/Edit/Timing/TimingSection.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Edit.Timing { Label = "BPM"; - OnCommit += (val, isNew) => + OnCommit += (_, isNew) => { if (!isNew) return; diff --git a/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs b/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs index 1cdcfdf167..2956a28547 100644 --- a/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs @@ -91,7 +91,7 @@ namespace osu.Game.Screens.Edit.Timing selectedGroup.BindValueChanged(_ => updateTimingGroup(), true); controlPointGroups.BindTo(editorBeatmap.ControlPointInfo.Groups); - controlPointGroups.BindCollectionChanged((_, __) => updateTimingGroup()); + controlPointGroups.BindCollectionChanged((_, _) => updateTimingGroup()); beatLength.BindValueChanged(_ => regenerateDisplay(true), true); diff --git a/osu.Game/Screens/Edit/Verify/IssueList.cs b/osu.Game/Screens/Edit/Verify/IssueList.cs index 7ce70b4b5f..bffda4ec41 100644 --- a/osu.Game/Screens/Edit/Verify/IssueList.cs +++ b/osu.Game/Screens/Edit/Verify/IssueList.cs @@ -87,7 +87,7 @@ namespace osu.Game.Screens.Edit.Verify base.LoadComplete(); verify.InterpretedDifficulty.BindValueChanged(_ => refresh()); - verify.HiddenIssueTypes.BindCollectionChanged((_, __) => refresh()); + verify.HiddenIssueTypes.BindCollectionChanged((_, _) => refresh()); refresh(); } diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index f77123af52..a81658a4b6 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -222,7 +222,7 @@ namespace osu.Game.Screens.Menu .Then(5500) .FadeOut(250) .ScaleTo(0.9f, 250, Easing.InQuint) - .Finally(d => + .Finally(_ => { if (nextScreen != null) this.Push(nextScreen); diff --git a/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs b/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs index 1dc05def0f..39a887f820 100644 --- a/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs +++ b/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs @@ -27,7 +27,7 @@ namespace osu.Game.Screens.OnlinePlay.Components [BackgroundDependencyLoader] private void load() { - Playlist.CollectionChanged += (_, __) => updateText(); + Playlist.CollectionChanged += (_, _) => updateText(); updateText(); } diff --git a/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs b/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs index bed55e8a79..9a48769405 100644 --- a/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs +++ b/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs @@ -86,7 +86,7 @@ namespace osu.Game.Screens.OnlinePlay.Components switch (tab) { - case BeatmapDetailAreaPlaylistTabItem _: + case BeatmapDetailAreaPlaylistTabItem: playlistArea.Show(); break; diff --git a/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs index 795f776496..fe89eaf591 100644 --- a/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.OnlinePlay.Components InternalChild = sprite = CreateBackgroundSprite(); CurrentPlaylistItem.BindValueChanged(_ => updateBeatmap()); - Playlist.CollectionChanged += (_, __) => updateBeatmap(); + Playlist.CollectionChanged += (_, _) => updateBeatmap(); updateBeatmap(); } diff --git a/osu.Game/Screens/OnlinePlay/Components/OverlinedPlaylistHeader.cs b/osu.Game/Screens/OnlinePlay/Components/OverlinedPlaylistHeader.cs index 43ad5e97ec..a268d4d917 100644 --- a/osu.Game/Screens/OnlinePlay/Components/OverlinedPlaylistHeader.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OverlinedPlaylistHeader.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.OnlinePlay.Components { base.LoadComplete(); - Playlist.BindCollectionChanged((_, __) => Details.Value = Playlist.GetTotalDuration(), true); + Playlist.BindCollectionChanged((_, _) => Details.Value = Playlist.GetTotalDuration(), true); } } } diff --git a/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs index d8515d2bd2..2f38321e13 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs @@ -60,7 +60,7 @@ namespace osu.Game.Screens.OnlinePlay.Components [BackgroundDependencyLoader] private void load() { - RecentParticipants.CollectionChanged += (_, __) => updateParticipants(); + RecentParticipants.CollectionChanged += (_, _) => updateParticipants(); updateParticipants(); } diff --git a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs index 4cf785ce60..b6ef080e44 100644 --- a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.OnlinePlay.Components base.LoadComplete(); DifficultyRange.BindValueChanged(_ => updateRange()); - Playlist.BindCollectionChanged((_, __) => updateRange(), true); + Playlist.BindCollectionChanged((_, _) => updateRange(), true); } private void updateRange() diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs index 489bf128e8..5193fe5cbf 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs @@ -181,7 +181,7 @@ namespace osu.Game.Screens.OnlinePlay // schedules added as the properties may change value while the drawable items haven't been created yet. SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(scrollToSelection)); - Items.BindCollectionChanged((_, __) => Scheduler.AddOnce(scrollToSelection), true); + Items.BindCollectionChanged((_, _) => Scheduler.AddOnce(scrollToSelection), true); } private void scrollToSelection() diff --git a/osu.Game/Screens/OnlinePlay/Header.cs b/osu.Game/Screens/OnlinePlay/Header.cs index 06befe0971..a9e9f046e2 100644 --- a/osu.Game/Screens/OnlinePlay/Header.cs +++ b/osu.Game/Screens/OnlinePlay/Header.cs @@ -38,8 +38,8 @@ namespace osu.Game.Screens.OnlinePlay }; // unnecessary to unbind these as this header has the same lifetime as the screen stack we are attaching to. - stack.ScreenPushed += (_, __) => updateSubScreenTitle(); - stack.ScreenExited += (_, __) => updateSubScreenTitle(); + stack.ScreenPushed += (_, _) => updateSubScreenTitle(); + stack.ScreenExited += (_, _) => updateSubScreenTitle(); } private void updateSubScreenTitle() => title.Screen = stack.CurrentScreen as IOnlinePlaySubScreen; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs index 5bdd24221c..474463d5f1 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components base.LoadComplete(); PlaylistItemStats.BindValueChanged(_ => updateCount()); - Playlist.BindCollectionChanged((_, __) => updateCount(), true); + Playlist.BindCollectionChanged((_, _) => updateCount(), true); } private void updateCount() diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs index 9784e5aace..8a2aeb9e5e 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs @@ -250,7 +250,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge base.LoadComplete(); ScheduleAfterChildren(() => GetContainingInputManager().ChangeFocus(passwordTextBox)); - passwordTextBox.OnCommit += (_, __) => performJoin(); + passwordTextBox.OnCommit += (_, _) => performJoin(); } private void performJoin() diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs index d81fee24e0..58ccb24f7a 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge public LoungeBackgroundScreen() { SelectedRoom.BindValueChanged(onSelectedRoomChanged); - playlist.BindCollectionChanged((_, __) => PlaylistItem = playlist.GetCurrentItem()); + playlist.BindCollectionChanged((_, _) => PlaylistItem = playlist.GetCurrentItem()); } private void onSelectedRoomChanged(ValueChangedEvent room) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index f7f3c27ede..09bc496da5 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -304,7 +304,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge joiningRoomOperation = ongoingOperationTracker?.BeginOperation(); - RoomManager?.JoinRoom(room, password, r => + RoomManager?.JoinRoom(room, password, _ => { Open(room); joiningRoomOperation?.Dispose(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs index 20762b2f22..c5d6da1ebc 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs @@ -61,7 +61,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match switch (room?.Countdown) { - case MatchStartCountdown _: + case MatchStartCountdown: newCountdown = room.Countdown; break; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs index b5bb4a766f..b55a7d0731 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { var clickOperation = ongoingOperationTracker.BeginOperation(); - Client.ToggleSpectate().ContinueWith(t => endOperation()); + Client.ToggleSpectate().ContinueWith(_ => endOperation()); void endOperation() => clickOperation?.Dispose(); } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs index 9877c15f2f..f7abc91227 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist protected override void LoadComplete() { base.LoadComplete(); - QueueItems.BindCollectionChanged((_, __) => Text.Text = QueueItems.Count > 0 ? $"Queue ({QueueItems.Count})" : "Queue", true); + QueueItems.BindCollectionChanged((_, _) => Text.Text = QueueItems.Count > 0 ? $"Queue ({QueueItems.Count})" : "Queue", true); } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerQueueList.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerQueueList.cs index 04342788db..39740e650f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerQueueList.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerQueueList.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist protected override void LoadComplete() { base.LoadComplete(); - roomPlaylist.BindCollectionChanged((_, __) => InvalidateLayout()); + roomPlaylist.BindCollectionChanged((_, _) => InvalidateLayout()); } public override IEnumerable FlowingChildren => base.FlowingChildren.OfType>().OrderBy(item => item.Model.PlaylistOrder); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index ae65e1d969..d49f894ad7 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -81,7 +81,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private void load() { isConnected.BindTo(client.IsConnected); - isConnected.BindValueChanged(c => Scheduler.AddOnce(poll), true); + isConnected.BindValueChanged(_ => Scheduler.AddOnce(poll), true); } private void poll() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index df0f94688b..a82da7b185 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -125,7 +125,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer client.GameplayStarted += onGameplayStarted; client.ResultsReady += onResultsReady; - ScoreProcessor.HasCompleted.BindValueChanged(completed => + ScoreProcessor.HasCompleted.BindValueChanged(_ => { // wait for server to tell us that results are ready (see SubmitScore implementation) loadingDisplay.Show(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index e048c12686..8270bb3b6f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -133,7 +133,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate LoadComponentAsync(leaderboard = new MultiSpectatorLeaderboard(users) { Expanded = { Value = true }, - }, l => + }, _ => { foreach (var instance in instances) leaderboard.AddClock(instance.UserId, instance.GameplayClock); diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs index 1d9ea5f77d..0bf5f2604c 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs @@ -94,7 +94,7 @@ namespace osu.Game.Screens.OnlinePlay base.LoadComplete(); subScreenSelectedItem?.BindValueChanged(_ => UpdateSelectedItem()); - Playlist.BindCollectionChanged((_, __) => UpdateSelectedItem(), true); + Playlist.BindCollectionChanged((_, _) => UpdateSelectedItem(), true); } protected void UpdateSelectedItem() diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index ff657e16fb..8a9c4db6ad 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -68,7 +68,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists } }, true); - Room.MaxAttempts.BindValueChanged(attempts => progressSection.Alpha = Room.MaxAttempts.Value != null ? 1 : 0, true); + Room.MaxAttempts.BindValueChanged(_ => progressSection.Alpha = Room.MaxAttempts.Value != null ? 1 : 0, true); } protected override Drawable CreateMainContent() => new Container diff --git a/osu.Game/Screens/Play/FailAnimation.cs b/osu.Game/Screens/Play/FailAnimation.cs index ca485aa8ea..c1223d7262 100644 --- a/osu.Game/Screens/Play/FailAnimation.cs +++ b/osu.Game/Screens/Play/FailAnimation.cs @@ -198,7 +198,7 @@ namespace osu.Game.Screens.Play dropOffScreen(obj, failTime, rotation, originalScale, originalPosition); // need to reapply the fail drop after judgement state changes - obj.ApplyCustomUpdateState += (o, _) => dropOffScreen(obj, failTime, rotation, originalScale, originalPosition); + obj.ApplyCustomUpdateState += (_, _) => dropOffScreen(obj, failTime, rotation, originalScale, originalPosition); appliedObjects.Add(obj); } diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index 99b9362700..c2652e9212 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -142,7 +142,7 @@ namespace osu.Game.Screens.Play }, }; - State.ValueChanged += s => InternalButtons.Deselect(); + State.ValueChanged += _ => InternalButtons.Deselect(); updateRetryCount(); } @@ -267,7 +267,7 @@ namespace osu.Game.Screens.Play { switch (e) { - case ScrollEvent _: + case ScrollEvent: if (ReceivePositionalInputAt(e.ScreenSpaceMousePosition)) return globalAction.TriggerEvent(e); diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index aa9a2ab242..39a8f1e783 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -218,7 +218,7 @@ namespace osu.Game.Screens.Play.HUD overlayCircle.ScaleTo(0, 100) .Then().FadeOut().ScaleTo(1).FadeIn(500) - .OnComplete(a => + .OnComplete(_ => { icon.ScaleTo(1, 100); circularProgress.FadeOut(100).OnComplete(_ => diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index fe27e1fc24..8f80644d52 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -352,7 +352,7 @@ namespace osu.Game.Screens.Play // When the scoring mode changes, relative positions of elements may change (see DefaultSkin.GetDrawableComponent). // This is a best effort implementation for cases where users haven't customised layouts. scoringMode = config.GetBindable(OsuSetting.ScoreDisplayMode); - scoringMode.BindValueChanged(val => Reload()); + scoringMode.BindValueChanged(_ => Reload()); } } } diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs index ef28632d76..b6094726c0 100644 --- a/osu.Game/Screens/Play/KeyCounterDisplay.cs +++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs @@ -157,10 +157,10 @@ namespace osu.Game.Screens.Play { switch (e) { - case KeyDownEvent _: - case KeyUpEvent _: - case MouseDownEvent _: - case MouseUpEvent _: + case KeyDownEvent: + case KeyUpEvent: + case MouseDownEvent: + case MouseUpEvent: return Target.Children.Any(c => c.TriggerEvent(e)); } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 4a8460ff46..4040adc48d 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -173,7 +173,7 @@ namespace osu.Game.Screens.Play PrepareReplay(); - ScoreProcessor.NewJudgement += result => ScoreProcessor.PopulateScore(Score.ScoreInfo); + ScoreProcessor.NewJudgement += _ => ScoreProcessor.PopulateScore(Score.ScoreInfo); ScoreProcessor.OnResetFromReplayFrame += () => ScoreProcessor.PopulateScore(Score.ScoreInfo); gameActive.BindValueChanged(_ => updatePauseOnFocusLostState(), true); @@ -315,7 +315,7 @@ namespace osu.Game.Screens.Play GameplayClockContainer.Start(); }); - DrawableRuleset.IsPaused.BindValueChanged(paused => + DrawableRuleset.IsPaused.BindValueChanged(_ => { updateGameplayState(); updateSampleDisabledState(); diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 2a5e356df8..64b4853a67 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.Play protected override bool CheckModsAllowFailure() => false; public ReplayPlayer(Score score, PlayerConfiguration configuration = null) - : this((_, __) => score, configuration) + : this((_, _) => score, configuration) { } diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs index 5d7b04743e..3505786b64 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs @@ -53,7 +53,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics Spacing = new Vector2(10, 0), Children = new[] { - base.CreateContent().With(d => + base.CreateContent().With(_ => { Anchor = Anchor.CentreLeft; Origin = Anchor.CentreLeft; diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index 384f4c4d4f..ab68dec92d 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -87,7 +87,7 @@ namespace osu.Game.Screens.Ranking.Statistics Task.Run(() => { playableBeatmap = beatmapManager.GetWorkingBeatmap(newScore.BeatmapInfo).GetPlayableBeatmap(newScore.Ruleset, newScore.Mods); - }, loadCancellation.Token).ContinueWith(t => Schedule(() => + }, loadCancellation.Token).ContinueWith(_ => Schedule(() => { bool hitEventsAvailable = newScore.HitEvents.Count != 0; Container container; diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 87a1fb4ccb..72e6c7d159 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -959,7 +959,7 @@ namespace osu.Game.Screens.Select { // root should always remain selected. if not, PerformSelection will not be called. State.Value = CarouselItemState.Selected; - State.ValueChanged += state => State.Value = CarouselItemState.Selected; + State.ValueChanged += _ => State.Value = CarouselItemState.Selected; this.carousel = carousel; } diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs index dfcd43189b..bf6803f551 100644 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs @@ -86,7 +86,7 @@ namespace osu.Game.Screens.Select { switch (tab) { - case BeatmapDetailAreaDetailTabItem _: + case BeatmapDetailAreaDetailTabItem: Details.Show(); break; diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index fdc0d4efdd..2fe62c4a4e 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -217,7 +217,7 @@ namespace osu.Game.Screens.Select }); }; - lookup.Failure += e => + lookup.Failure += _ => { Schedule(() => { diff --git a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs index a948e5b0bd..cc01f61c57 100644 --- a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs +++ b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs @@ -57,7 +57,7 @@ namespace osu.Game.Screens.Select.Carousel + $" && {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $2" + $" && {nameof(ScoreInfo.DeletePending)} == false", api.LocalUser.Value.Id, beatmapInfo.ID, ruleset.Value.ShortName) .OrderByDescending(s => s.TotalScore), - (items, changes, ___) => + (items, _, _) => { Rank = items.FirstOrDefault()?.Rank; // Required since presence is changed via IsPresent override diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index 59eb3fa607..693f182065 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -96,7 +96,7 @@ namespace osu.Game.Screens.Select.Details modSettingChangeTracker?.Dispose(); modSettingChangeTracker = new ModSettingChangeTracker(mods.NewValue); - modSettingChangeTracker.SettingChanged += m => + modSettingChangeTracker.SettingChanged += _ => { debouncedStatisticsUpdate?.Cancel(); debouncedStatisticsUpdate = Scheduler.AddDelayed(updateStatistics, 100); diff --git a/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs b/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs index 4d3c844753..a19acddb48 100644 --- a/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs @@ -113,7 +113,7 @@ namespace osu.Game.Screens.Select { switch (item) { - case BeatmapDetailAreaDetailTabItem _: + case BeatmapDetailAreaDetailTabItem: return TabType.Details; case BeatmapDetailAreaLeaderboardTabItem leaderboardTab: diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/DefaultSkin.cs index 43b3cb0aa4..2467b7d039 100644 --- a/osu.Game/Skinning/DefaultSkin.cs +++ b/osu.Game/Skinning/DefaultSkin.cs @@ -74,7 +74,7 @@ namespace osu.Game.Skinning switch (target.Target) { case SkinnableTarget.SongSelect: - var songSelectComponents = new SkinnableTargetComponentsContainer(container => + var songSelectComponents = new SkinnableTargetComponentsContainer(_ => { // do stuff when we need to. }); diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index 7e9f1d0e8e..649b63dda4 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -190,13 +190,13 @@ namespace osu.Game.Skinning.Editor // schedule ensures this only happens when the skin editor is visible. // also avoid some weird endless recursion / bindable feedback loop (something to do with tracking skins across three different bindable types). // probably something which will be factored out in a future database refactor so not too concerning for now. - currentSkin.BindValueChanged(skin => + currentSkin.BindValueChanged(_ => { hasBegunMutating = false; Scheduler.AddOnce(skinChanged); }, true); - SelectedComponents.BindCollectionChanged((_, __) => Scheduler.AddOnce(populateSettings), true); + SelectedComponents.BindCollectionChanged((_, _) => Scheduler.AddOnce(populateSettings), true); } public void UpdateTargetScreen(Drawable targetScreen) diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index de33d49941..000917f728 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -70,7 +70,7 @@ namespace osu.Game.Skinning.Editor var editor = new SkinEditor(); - editor.State.BindValueChanged(visibility => updateComponentVisibility()); + editor.State.BindValueChanged(_ => updateComponentVisibility()); skinEditor = editor; diff --git a/osu.Game/Skinning/LegacyManiaSkinDecoder.cs b/osu.Game/Skinning/LegacyManiaSkinDecoder.cs index 2aaf0ba18e..49914c53aa 100644 --- a/osu.Game/Skinning/LegacyManiaSkinDecoder.cs +++ b/osu.Game/Skinning/LegacyManiaSkinDecoder.cs @@ -120,16 +120,16 @@ namespace osu.Game.Skinning currentConfig.MinimumColumnWidth = minWidth; break; - case string _ when pair.Key.StartsWith("Colour", StringComparison.Ordinal): + case string when pair.Key.StartsWith("Colour", StringComparison.Ordinal): HandleColours(currentConfig, line); break; // Custom sprite paths - case string _ when pair.Key.StartsWith("NoteImage", StringComparison.Ordinal): - case string _ when pair.Key.StartsWith("KeyImage", StringComparison.Ordinal): - case string _ when pair.Key.StartsWith("Hit", StringComparison.Ordinal): - case string _ when pair.Key.StartsWith("Stage", StringComparison.Ordinal): - case string _ when pair.Key.StartsWith("Lighting", StringComparison.Ordinal): + case string when pair.Key.StartsWith("NoteImage", StringComparison.Ordinal): + case string when pair.Key.StartsWith("KeyImage", StringComparison.Ordinal): + case string when pair.Key.StartsWith("Hit", StringComparison.Ordinal): + case string when pair.Key.StartsWith("Stage", StringComparison.Ordinal): + case string when pair.Key.StartsWith("Lighting", StringComparison.Ordinal): currentConfig.ImageLookups[pair.Key] = pair.Value; break; } diff --git a/osu.Game/Skinning/SkinImporter.cs b/osu.Game/Skinning/SkinImporter.cs index 1b5de9abb5..ed31a8c3f5 100644 --- a/osu.Game/Skinning/SkinImporter.cs +++ b/osu.Game/Skinning/SkinImporter.cs @@ -214,7 +214,7 @@ namespace osu.Game.Skinning { try { - realm.Write(r => skin.Hash = ComputeHash(skin)); + realm.Write(_ => skin.Hash = ComputeHash(skin)); } catch (Exception e) { diff --git a/osu.Game/Skinning/SkinProvidingContainer.cs b/osu.Game/Skinning/SkinProvidingContainer.cs index d7399b0141..e447570931 100644 --- a/osu.Game/Skinning/SkinProvidingContainer.cs +++ b/osu.Game/Skinning/SkinProvidingContainer.cs @@ -269,9 +269,9 @@ namespace osu.Game.Skinning { switch (lookup) { - case GlobalSkinColours _: - case SkinComboColourLookup _: - case SkinCustomColourLookup _: + case GlobalSkinColours: + case SkinComboColourLookup: + case SkinCustomColourLookup: if (provider.AllowColourLookup) return skin.GetConfig(lookup); diff --git a/osu.Game/Storyboards/StoryboardSprite.cs b/osu.Game/Storyboards/StoryboardSprite.cs index 838dc618f2..a759482b5d 100644 --- a/osu.Game/Storyboards/StoryboardSprite.cs +++ b/osu.Game/Storyboards/StoryboardSprite.cs @@ -109,20 +109,20 @@ namespace osu.Game.Storyboards generateCommands(generated, getCommands(g => g.Rotation, triggeredGroups), (d, value) => d.Rotation = value, (d, value, duration, easing) => d.RotateTo(value, duration, easing)); generateCommands(generated, getCommands(g => g.Colour, triggeredGroups), (d, value) => d.Colour = value, (d, value, duration, easing) => d.FadeColour(value, duration, easing)); generateCommands(generated, getCommands(g => g.Alpha, triggeredGroups), (d, value) => d.Alpha = value, (d, value, duration, easing) => d.FadeTo(value, duration, easing)); - generateCommands(generated, getCommands(g => g.BlendingParameters, triggeredGroups), (d, value) => d.Blending = value, (d, value, duration, easing) => d.TransformBlendingMode(value, duration), + generateCommands(generated, getCommands(g => g.BlendingParameters, triggeredGroups), (d, value) => d.Blending = value, (d, value, duration, _) => d.TransformBlendingMode(value, duration), false); if (drawable is IVectorScalable vectorScalable) { - generateCommands(generated, getCommands(g => g.VectorScale, triggeredGroups), (d, value) => vectorScalable.VectorScale = value, - (d, value, duration, easing) => vectorScalable.VectorScaleTo(value, duration, easing)); + generateCommands(generated, getCommands(g => g.VectorScale, triggeredGroups), (_, value) => vectorScalable.VectorScale = value, + (_, value, duration, easing) => vectorScalable.VectorScaleTo(value, duration, easing)); } if (drawable is IFlippable flippable) { - generateCommands(generated, getCommands(g => g.FlipH, triggeredGroups), (d, value) => flippable.FlipH = value, (d, value, duration, easing) => flippable.TransformFlipH(value, duration), + generateCommands(generated, getCommands(g => g.FlipH, triggeredGroups), (_, value) => flippable.FlipH = value, (_, value, duration, _) => flippable.TransformFlipH(value, duration), false); - generateCommands(generated, getCommands(g => g.FlipV, triggeredGroups), (d, value) => flippable.FlipV = value, (d, value, duration, easing) => flippable.TransformFlipV(value, duration), + generateCommands(generated, getCommands(g => g.FlipV, triggeredGroups), (_, value) => flippable.FlipV = value, (_, value, duration, _) => flippable.TransformFlipV(value, duration), false); } diff --git a/osu.Game/Tests/Visual/ScreenTestScene.cs b/osu.Game/Tests/Visual/ScreenTestScene.cs index 9adf6458cd..803db07fa0 100644 --- a/osu.Game/Tests/Visual/ScreenTestScene.cs +++ b/osu.Game/Tests/Visual/ScreenTestScene.cs @@ -49,8 +49,8 @@ namespace osu.Game.Tests.Visual } }); - Stack.ScreenPushed += (lastScreen, newScreen) => Logger.Log($"{nameof(ScreenTestScene)} screen changed → {newScreen}"); - Stack.ScreenExited += (lastScreen, newScreen) => Logger.Log($"{nameof(ScreenTestScene)} screen changed ← {newScreen}"); + Stack.ScreenPushed += (_, newScreen) => Logger.Log($"{nameof(ScreenTestScene)} screen changed → {newScreen}"); + Stack.ScreenExited += (_, newScreen) => Logger.Log($"{nameof(ScreenTestScene)} screen changed ← {newScreen}"); } protected void LoadScreen(OsuScreen screen) => Stack.Push(screen); From 81bfe1406386a8c40132ccdc39afefdbf5049609 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 21:28:24 +0900 Subject: [PATCH 160/211] Update `DotSettings` to match framework (in most cases) --- osu.sln.DotSettings | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 8fd750a50d..32dbb62e5e 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -7,19 +7,22 @@ ExplicitlyExcluded SOLUTION WARNING + WARNING + WARNING WARNING WARNING HINT HINT WARNING + WARNING + WARNING WARNING True WARNING WARNING HINT DO_NOT_SHOW - WARNING - WARNING + HINT HINT HINT WARNING @@ -58,14 +61,17 @@ HINT HINT HINT - WARNING + HINT + DO_NOT_SHOW WARNING WARNING WARNING WARNING + DO_NOT_SHOW WARNING WARNING WARNING + DO_NOT_SHOW WARNING WARNING WARNING @@ -73,7 +79,7 @@ WARNING HINT WARNING - HINT + DO_NOT_SHOW DO_NOT_SHOW WARNING DO_NOT_SHOW @@ -107,7 +113,6 @@ HINT HINT WARNING - DO_NOT_SHOW DO_NOT_SHOW WARNING WARNING @@ -118,16 +123,13 @@ WARNING WARNING WARNING - HINT + HINT WARNING WARNING WARNING WARNING HINT - HINT WARNING - HINT - HINT HINT HINT HINT @@ -135,8 +137,10 @@ HINT HINT WARNING + HINT + HINT WARNING - WARNING + HINT WARNING WARNING WARNING @@ -145,6 +149,7 @@ DO_NOT_SHOW DO_NOT_SHOW DO_NOT_SHOW + WARNING WARNING WARNING WARNING @@ -213,8 +218,7 @@ WARNING SUGGESTION DO_NOT_SHOW - - True + HINT DO_NOT_SHOW WARNING WARNING @@ -230,8 +234,8 @@ HINT HINT HINT - HINT HINT + HINT HINT DO_NOT_SHOW WARNING @@ -265,6 +269,7 @@ Explicit ExpressionBody BlockBody + ExplicitlyTyped True NEXT_LINE True From 14327943a2d0eb550ed1d4f8bddaef9a2c8d8246 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 24 Jun 2022 21:28:30 +0900 Subject: [PATCH 161/211] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index f2790d2520..9cd1709211 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 0802a98858..9e7c0020c3 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index a272df20d4..5315831a33 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From df30bedab6f14d45466dd1c6391dec1ad99bf871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 24 Jun 2022 16:01:52 +0200 Subject: [PATCH 162/211] Update framework again --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 9cd1709211..8f4a102cce 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9e7c0020c3..b9033f1bb9 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 5315831a33..a1e4cf3ba0 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From a83c45b50e4f126bfa218d4bd8e4d8a2bf1e5145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 24 Jun 2022 16:07:14 +0200 Subject: [PATCH 163/211] Fix compile failures from framework breaking change --- osu.Game.Tournament/TournamentGameBase.cs | 2 +- osu.Game/OsuGameBase.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index ccbe77fa95..75c9f17d4c 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -62,7 +62,7 @@ namespace osu.Game.Tournament dependencies.Cache(new TournamentVideoResourceStore(storage)); - Textures.AddStore(new TextureLoaderStore(new StorageBackedResourceStore(storage))); + Textures.AddTextureSource(new TextureLoaderStore(new StorageBackedResourceStore(storage))); dependencies.CacheAs(new StableInfo(storage)); } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index b0ba62a6ac..7d39aad226 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -244,7 +244,7 @@ namespace osu.Game dependencies.CacheAs(Storage); var largeStore = new LargeTextureStore(Host.CreateTextureLoaderStore(new NamespacedResourceStore(Resources, @"Textures"))); - largeStore.AddStore(Host.CreateTextureLoaderStore(new OnlineStore())); + largeStore.AddTextureSource(Host.CreateTextureLoaderStore(new OnlineStore())); dependencies.Cache(largeStore); dependencies.CacheAs(this); From e0c2228b4181d707702873c9d4943003debb7b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 24 Jun 2022 16:40:35 +0200 Subject: [PATCH 164/211] Revert downgrades in code inspection settings --- osu.sln.DotSettings | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 32dbb62e5e..a55b3b5074 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -22,7 +22,8 @@ WARNING HINT DO_NOT_SHOW - HINT + WARNING + WARNING HINT HINT WARNING @@ -61,7 +62,7 @@ HINT HINT HINT - HINT + WARNING DO_NOT_SHOW WARNING WARNING @@ -79,7 +80,7 @@ WARNING HINT WARNING - DO_NOT_SHOW + HINT DO_NOT_SHOW WARNING DO_NOT_SHOW @@ -113,6 +114,7 @@ HINT HINT WARNING + DO_NOT_SHOW DO_NOT_SHOW WARNING WARNING @@ -129,7 +131,10 @@ WARNING WARNING HINT + HINT WARNING + HINT + HINT HINT HINT HINT @@ -140,7 +145,7 @@ HINT HINT WARNING - HINT + WARNING WARNING WARNING WARNING @@ -218,7 +223,8 @@ WARNING SUGGESTION DO_NOT_SHOW - HINT + + True DO_NOT_SHOW WARNING WARNING @@ -234,8 +240,8 @@ HINT HINT HINT - HINT HINT + HINT HINT DO_NOT_SHOW WARNING From a039f9878a6b4eca158982dce24fdd4ca0dd8584 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 25 Jun 2022 19:33:44 +0900 Subject: [PATCH 165/211] Adjust menu cursor rotation to follow mouse, rather than be fixated around original click location --- osu.Game/Graphics/Cursor/MenuCursor.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs index 4544633318..b387dbf9a8 100644 --- a/osu.Game/Graphics/Cursor/MenuCursor.cs +++ b/osu.Game/Graphics/Cursor/MenuCursor.cs @@ -51,6 +51,9 @@ namespace osu.Game.Graphics.Cursor { if (dragRotationState != DragRotationState.NotDragging) { + if (Vector2.Distance(positionMouseDown, e.MousePosition) > 100) + positionMouseDown = Interpolation.ValueAt(0.001f, positionMouseDown, e.MousePosition, 0, Clock.ElapsedFrameTime); + var position = e.MousePosition; float distance = Vector2Extensions.Distance(position, positionMouseDown); From 2ecab454aa4dbde8ca37f2d07a0f93be80e9dff0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 25 Jun 2022 19:43:39 +0900 Subject: [PATCH 166/211] Adjust animations and tolerances to make things feel snappier --- osu.Game/Graphics/Cursor/MenuCursor.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs index b387dbf9a8..10ed76ebdd 100644 --- a/osu.Game/Graphics/Cursor/MenuCursor.cs +++ b/osu.Game/Graphics/Cursor/MenuCursor.cs @@ -51,15 +51,16 @@ namespace osu.Game.Graphics.Cursor { if (dragRotationState != DragRotationState.NotDragging) { - if (Vector2.Distance(positionMouseDown, e.MousePosition) > 100) - positionMouseDown = Interpolation.ValueAt(0.001f, positionMouseDown, e.MousePosition, 0, Clock.ElapsedFrameTime); + // make the rotation centre point floating. + if (Vector2.Distance(positionMouseDown, e.MousePosition) > 60) + positionMouseDown = Interpolation.ValueAt(0.005f, positionMouseDown, e.MousePosition, 0, Clock.ElapsedFrameTime); var position = e.MousePosition; float distance = Vector2Extensions.Distance(position, positionMouseDown); // don't start rotating until we're moved a minimum distance away from the mouse down location, // else it can have an annoying effect. - if (dragRotationState == DragRotationState.DragStarted && distance > 30) + if (dragRotationState == DragRotationState.DragStarted && distance > 80) dragRotationState = DragRotationState.Rotating; // don't rotate when distance is zero to avoid NaN @@ -74,7 +75,7 @@ namespace osu.Game.Graphics.Cursor if (diff > 180) diff -= 360; degrees = activeCursor.Rotation + diff; - activeCursor.RotateTo(degrees, 600, Easing.OutQuint); + activeCursor.RotateTo(degrees, 120, Easing.OutQuint); } } @@ -114,7 +115,7 @@ namespace osu.Game.Graphics.Cursor if (dragRotationState != DragRotationState.NotDragging) { - activeCursor.RotateTo(0, 600 * (1 + Math.Abs(activeCursor.Rotation / 720)), Easing.OutElasticHalf); + activeCursor.RotateTo(0, 400 * (0.5f + Math.Abs(activeCursor.Rotation / 960)), Easing.OutElasticQuarter); dragRotationState = DragRotationState.NotDragging; } From 1a22377e19d45ee88dab9e9effba1260b7bacf47 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 26 Jun 2022 16:42:28 +0900 Subject: [PATCH 167/211] Fix test deadlock due to TPL threadpool saturation As found in aggressive CI runs: ```csharp 00007F6F527F32B0 00007f74f937c72d (MethodDesc 00007f74f5545a78 + 0x22d System.Threading.ManualResetEventSlim.Wait(Int32, System.Threading.CancellationToken)), calling (MethodDesc 00007f74f51c0838 + 0 System.Threading.Monitor.Wait(System.Object, Int32)) 00007F6F527F3330 00007f74f93861ca (MethodDesc 00007f74f5259100 + 0x10a System.Threading.Tasks.Task.SpinThenBlockingWait(Int32, System.Threading.CancellationToken)), calling (MethodDesc 00007f74f5545a78 + 0 System.Threading.ManualResetEventSlim.Wait(Int32, System.Threading.CancellationToken)) 00007F6F527F3390 00007f74f9385d11 (MethodDesc 00007f74f52590e8 + 0x81 System.Threading.Tasks.Task.InternalWaitCore(Int32, System.Threading.CancellationToken)), calling (MethodDesc 00007f74f5259100 + 0 System.Threading.Tasks.Task.SpinThenBlockingWait(Int32, System.Threading.CancellationToken)) 00007F6F527F33E0 00007f74fc3823af (MethodDesc 00007f74f5934c08 + 0x4f System.Threading.Tasks.Task`1[[System.Boolean, System.Private.CoreLib]].GetResultCore(Boolean)), calling (MethodDesc 00007f74f52590e8 + 0 System.Threading.Tasks.Task.InternalWaitCore(Int32, System.Threading.CancellationToken)) 00007F6F527F3400 00007f74fb0aad92 (MethodDesc 00007f74fb28b000 + 0x122 osu.Game.Tests.Visual.OnlinePlay.OnlinePlayTestScene+<>c__DisplayClass21_0.b__1(osu.Game.Online.API.APIRequest)), calling (MethodDesc 00007f74f5934be8 + 0 System.Threading.Tasks.Task`1[[System.Boolean, System.Private.CoreLib]].get_Result()) 00007F6F527F3470 00007f74fa9c6dd7 (MethodDesc 00007f74f921f6c8 + 0x77 osu.Game.Online.API.DummyAPIAccess.PerformAsync(osu.Game.Online.API.APIRequest)) 00007F6F527F34C0 00007f74fb13c718 (MethodDesc 00007f74fb4e0c50 + 0x538 osu.Game.Database.OnlineLookupCache`3+d__13[[System.Int32, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].MoveNext()) ``` Going with the simplest solution, as what we had was pretty ugly to start with and I don't want to overthink this, just push a fix and hope for the best. --- .../Visual/OnlinePlay/OnlinePlayTestScene.cs | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs index 282312c9c1..6577057c17 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs @@ -4,14 +4,14 @@ #nullable disable using System; -using System.Threading.Tasks; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Database; +using osu.Framework.Logging; using osu.Game.Beatmaps; +using osu.Game.Database; using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay; @@ -72,22 +72,18 @@ namespace osu.Game.Tests.Visual.OnlinePlay ((DummyAPIAccess)API).HandleRequest = request => { - TaskCompletionSource tcs = new TaskCompletionSource(); - - // Because some of the handlers use realm, we need to ensure the game is still alive when firing. - // If we don't, a stray `PerformAsync` could hit an `ObjectDisposedException` if running too late. - Scheduler.Add(() => + try { - bool result = handler.HandleRequest(request, API.LocalUser.Value, beatmapManager); - tcs.SetResult(result); - }, false); - -#pragma warning disable RS0030 - // We can't GetResultSafely() here (will fail with "Can't use GetResultSafely from inside an async operation."), but Wait is safe enough due to - // the task being a TaskCompletionSource. - // Importantly, this doesn't deadlock because of the scheduler call above running inline where feasible (see the `false` argument). - return tcs.Task.Result; -#pragma warning restore RS0030 + return handler.HandleRequest(request, API.LocalUser.Value, beatmapManager); + } + catch (ObjectDisposedException) + { + // These requests can be fired asynchronously, but potentially arrive after game components + // have been disposed (ie. realm in BeatmapManager). + // This only happens in tests and it's easiest to ignore them for now. + Logger.Log($"Handled {nameof(ObjectDisposedException)} in test request handling"); + return true; + } }; }); From cd9eaf215b9d3c9a10271d008a8a3baa25f0407c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 02:58:01 +0900 Subject: [PATCH 168/211] Attempt to fix flaky `PlaylistOverlay` test --- .../Visual/UserInterface/TestScenePlaylistOverlay.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs index 4c35ec40b5..ee5ef2f364 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs @@ -27,6 +27,8 @@ namespace osu.Game.Tests.Visual.UserInterface private Live first; + private const int item_count = 100; + [SetUp] public void Setup() => Schedule(() => { @@ -46,7 +48,7 @@ namespace osu.Game.Tests.Visual.UserInterface beatmapSets.Clear(); - for (int i = 0; i < 100; i++) + for (int i = 0; i < item_count; i++) { beatmapSets.Add(TestResources.CreateTestBeatmapSetInfo().ToLiveUnmanaged()); } @@ -59,6 +61,13 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestRearrangeItems() { + AddUntilStep("wait for load complete", () => + { + return this + .ChildrenOfType() + .Count(i => i.ChildrenOfType().First().DelayedLoadCompleted) > 6; + }); + AddUntilStep("wait for animations to complete", () => !playlistOverlay.Transforms.Any()); AddStep("hold 1st item handle", () => From b5a8889fb80e359d0afb17a7d1e76dc4b66df941 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 03:04:49 +0900 Subject: [PATCH 169/211] Attempt to fix flaky `EditorNavigation` test Conditionals taken from https://github.com/ppy/osu/blob/f8830c6850128456266c82de83273204f8b74ac0/osu.Game/Tests/Visual/EditorTestScene.cs#L61-L62 where it seemed to resolve other similar cases. --- osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs index 85b50a9b21..273e8abcd7 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs @@ -9,10 +9,12 @@ using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Database; +using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components.Timelines.Summary; +using osu.Game.Screens.Edit.Compose.Components.Timeline; using osu.Game.Screens.Edit.GameplayTest; using osu.Game.Screens.Select; using osu.Game.Tests.Resources; @@ -38,7 +40,10 @@ namespace osu.Game.Tests.Visual.Editing AddStep("switch ruleset", () => Game.Ruleset.Value = new ManiaRuleset().RulesetInfo); AddStep("open editor", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).Edit(beatmapSet.Beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == 0))); - AddUntilStep("wait for editor open", () => Game.ScreenStack.CurrentScreen is Editor editor && editor.IsLoaded); + AddUntilStep("wait for editor open", () => Game.ScreenStack.CurrentScreen is Editor editor + && editor.IsLoaded + && editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true + && editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); AddStep("test gameplay", () => { var testGameplayButton = this.ChildrenOfType().Single(); From da61d0547ffb39614a6c7b93610ac26c77e1fc67 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 15:24:25 +0900 Subject: [PATCH 170/211] Include archive name in import log output --- osu.Game/Database/RealmArchiveModelImporter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index a3349d9918..76f6db1384 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -296,7 +296,8 @@ namespace osu.Game.Database try { - LogForModel(item, @"Beginning import..."); + // Log output here will be missing a valid hash in non-batch imports. + LogForModel(item, $@"Beginning import from {archive?.Name ?? "unknown"}..."); // TODO: do we want to make the transaction this local? not 100% sure, will need further investigation. using (var transaction = realm.BeginWrite()) From 13c8d330094370093b33f724d84f4a914761e528 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 15:29:01 +0900 Subject: [PATCH 171/211] Fix second case of empty beatmaps being reported to sentry as errors --- osu.Game/Beatmaps/BeatmapImporter.cs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapImporter.cs b/osu.Game/Beatmaps/BeatmapImporter.cs index 237088036c..d89541844b 100644 --- a/osu.Game/Beatmaps/BeatmapImporter.cs +++ b/osu.Game/Beatmaps/BeatmapImporter.cs @@ -18,7 +18,6 @@ using osu.Game.Database; using osu.Game.Extensions; using osu.Game.IO; using osu.Game.IO.Archives; -using osu.Game.Models; using osu.Game.Rulesets; using osu.Game.Rulesets.Objects; using osu.Game.Skinning; @@ -49,7 +48,7 @@ namespace osu.Game.Beatmaps protected override void Populate(BeatmapSetInfo beatmapSet, ArchiveReader? archive, Realm realm, CancellationToken cancellationToken = default) { if (archive != null) - beatmapSet.Beatmaps.AddRange(createBeatmapDifficulties(beatmapSet.Files, realm)); + beatmapSet.Beatmaps.AddRange(createBeatmapDifficulties(beatmapSet, realm)); foreach (BeatmapInfo b in beatmapSet.Beatmaps) { @@ -200,23 +199,32 @@ namespace osu.Game.Beatmaps /// /// Create all required s for the provided archive. /// - private List createBeatmapDifficulties(IList files, Realm realm) + private List createBeatmapDifficulties(BeatmapSetInfo beatmapSet, Realm realm) { var beatmaps = new List(); - foreach (var file in files.Where(f => f.Filename.EndsWith(".osu", StringComparison.OrdinalIgnoreCase))) + foreach (var file in beatmapSet.Files.Where(f => f.Filename.EndsWith(".osu", StringComparison.OrdinalIgnoreCase))) { using (var memoryStream = new MemoryStream(Files.Store.Get(file.File.GetStoragePath()))) // we need a memory stream so we can seek { IBeatmap decoded; + using (var lineReader = new LineBufferedReader(memoryStream, true)) + { + if (lineReader.PeekLine() == null) + { + LogForModel(beatmapSet, $"No content found in beatmap file {file.Filename}."); + continue; + } + decoded = Decoder.GetDecoder(lineReader).Decode(lineReader); + } string hash = memoryStream.ComputeSHA2Hash(); if (beatmaps.Any(b => b.Hash == hash)) { - Logger.Log($"Skipping import of {file.Filename} due to duplicate file content.", LoggingTarget.Database); + LogForModel(beatmapSet, $"Skipping import of {file.Filename} due to duplicate file content."); continue; } @@ -227,7 +235,7 @@ namespace osu.Game.Beatmaps if (ruleset?.Available != true) { - Logger.Log($"Skipping import of {file.Filename} due to missing local ruleset {decodedInfo.Ruleset.OnlineID}.", LoggingTarget.Database); + LogForModel(beatmapSet, $"Skipping import of {file.Filename} due to missing local ruleset {decodedInfo.Ruleset.OnlineID}."); continue; } From 01487a11859af1cd36719fe250d34dff919c66cd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 15:52:45 +0900 Subject: [PATCH 172/211] Add assertion on realm re-fetch being not-null --- osu.Game/Database/ModelManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Database/ModelManager.cs b/osu.Game/Database/ModelManager.cs index 9603412178..4224c92f2c 100644 --- a/osu.Game/Database/ModelManager.cs +++ b/osu.Game/Database/ModelManager.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using osu.Framework.Platform; @@ -46,6 +47,7 @@ namespace osu.Game.Database Realm.Realm.Write(realm => { var managed = realm.Find(item.ID); + Debug.Assert(managed != null); operation(managed); item.Files.Clear(); From b70b365411ab9c820da30829b6dbcc5c42c3b15a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 15:53:05 +0900 Subject: [PATCH 173/211] Ensure files are cleaned up even on test step failure in `TestAddAudioTrack` --- .../Editing/TestSceneEditorBeatmapCreation.cs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index a204fc5686..fcbf63da79 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -95,18 +95,23 @@ namespace osu.Game.Tests.Visual.Editing string extractedFolder = $"{temp}_extracted"; Directory.CreateDirectory(extractedFolder); - using (var zip = ZipArchive.Open(temp)) - zip.WriteToDirectory(extractedFolder); + try + { + using (var zip = ZipArchive.Open(temp)) + zip.WriteToDirectory(extractedFolder); - bool success = setup.ChildrenOfType().First().ChangeAudioTrack(new FileInfo(Path.Combine(extractedFolder, "03. Renatus - Soleily 192kbps.mp3"))); + bool success = setup.ChildrenOfType().First().ChangeAudioTrack(new FileInfo(Path.Combine(extractedFolder, "03. Renatus - Soleily 192kbps.mp3"))); - File.Delete(temp); - Directory.Delete(extractedFolder, true); + // ensure audio file is copied to beatmap as "audio.mp3" rather than original filename. + Assert.That(Beatmap.Value.Metadata.AudioFile == "audio.mp3"); - // ensure audio file is copied to beatmap as "audio.mp3" rather than original filename. - Assert.That(Beatmap.Value.Metadata.AudioFile == "audio.mp3"); - - return success; + return success; + } + finally + { + File.Delete(temp); + Directory.Delete(extractedFolder, true); + } }); AddAssert("track length changed", () => Beatmap.Value.Track.Length > 60000); From 10d1bbb1316f427598d2cd714ebc7b645061e030 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 15:58:51 +0900 Subject: [PATCH 174/211] Log global working beatmap updates in `OsuGameBase` instead of `OsuGame` --- osu.Game/OsuGame.cs | 1 - osu.Game/OsuGameBase.cs | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index f51a18b36f..7724241d5a 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -612,7 +612,6 @@ namespace osu.Game { beatmap.OldValue?.CancelAsyncLoad(); beatmap.NewValue?.BeginAsyncLoad(); - Logger.Log($"Game-wide working beatmap updated to {beatmap.NewValue}"); } private void modsChanged(ValueChangedEvent> mods) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 7d39aad226..57369419d2 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -490,10 +490,12 @@ namespace osu.Game } } - private void onBeatmapChanged(ValueChangedEvent valueChangedEvent) + private void onBeatmapChanged(ValueChangedEvent beatmap) { if (IsLoaded && !ThreadSafety.IsUpdateThread) throw new InvalidOperationException("Global beatmap bindable must be changed from update thread."); + + Logger.Log($"Game-wide working beatmap updated to {beatmap.NewValue}"); } private void onRulesetChanged(ValueChangedEvent r) From f6a6538e9698f402ce612b8abecef67ec533aac5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 27 Jun 2022 15:01:53 +0900 Subject: [PATCH 175/211] Add more properties to IBeatmapOnlineInfo --- osu.Game/Beatmaps/IBeatmapOnlineInfo.cs | 33 ++++++++++++++++--- .../API/Requests/Responses/APIBeatmap.cs | 3 ++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/IBeatmapOnlineInfo.cs b/osu.Game/Beatmaps/IBeatmapOnlineInfo.cs index 160b7cf0ae..e1634e7d24 100644 --- a/osu.Game/Beatmaps/IBeatmapOnlineInfo.cs +++ b/osu.Game/Beatmaps/IBeatmapOnlineInfo.cs @@ -13,25 +13,50 @@ namespace osu.Game.Beatmaps /// int? MaxCombo { get; } + /// + /// The approach rate. + /// + float ApproachRate { get; } + + /// + /// The circle size. + /// + float CircleSize { get; } + + /// + /// The drain rate. + /// + float DrainRate { get; } + + /// + /// The overall difficulty. + /// + float OverallDifficulty { get; } + /// /// The amount of circles in this beatmap. /// - public int CircleCount { get; } + int CircleCount { get; } /// /// The amount of sliders in this beatmap. /// - public int SliderCount { get; } + int SliderCount { get; } + + /// + /// The amount of spinners in tihs beatmap. + /// + int SpinnerCount { get; } /// /// The amount of plays this beatmap has. /// - public int PlayCount { get; } + int PlayCount { get; } /// /// The amount of passes this beatmap has. /// - public int PassCount { get; } + int PassCount { get; } APIFailTimes? FailTimes { get; } } diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index 258708de2b..735fde333d 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -69,6 +69,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"count_sliders")] public int SliderCount { get; set; } + [JsonProperty(@"count_spinners")] + public int SpinnerCount { get; set; } + [JsonProperty(@"version")] public string DifficultyName { get; set; } = string.Empty; From 0579780bb8c38e25675755a4bc5cf045c2e1e7aa Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 27 Jun 2022 15:05:49 +0900 Subject: [PATCH 176/211] Add IBeatmapOnlineInfo parameter and use to extract more data --- .../Difficulty/CatchDifficultyAttributes.cs | 5 +++-- .../Difficulty/ManiaDifficultyAttributes.cs | 5 +++-- .../Difficulty/OsuDifficultyAttributes.cs | 10 ++++++++-- .../Difficulty/TaikoDifficultyAttributes.cs | 5 +++-- osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs | 4 +++- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs index 9951d736c3..c2f5aa3629 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Newtonsoft.Json; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; namespace osu.Game.Rulesets.Catch.Difficulty @@ -31,9 +32,9 @@ namespace osu.Game.Rulesets.Catch.Difficulty yield return (ATTRIB_ID_MAX_COMBO, MaxCombo); } - public override void FromDatabaseAttributes(IReadOnlyDictionary values) + public override void FromDatabaseAttributes(IReadOnlyDictionary values, IBeatmapOnlineInfo onlineInfo) { - base.FromDatabaseAttributes(values); + base.FromDatabaseAttributes(values, onlineInfo); StarRating = values[ATTRIB_ID_AIM]; ApproachRate = values[ATTRIB_ID_APPROACH_RATE]; diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs index 8a5161be79..023c45fbcf 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Newtonsoft.Json; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; namespace osu.Game.Rulesets.Mania.Difficulty @@ -37,9 +38,9 @@ namespace osu.Game.Rulesets.Mania.Difficulty yield return (ATTRIB_ID_SCORE_MULTIPLIER, ScoreMultiplier); } - public override void FromDatabaseAttributes(IReadOnlyDictionary values) + public override void FromDatabaseAttributes(IReadOnlyDictionary values, IBeatmapOnlineInfo onlineInfo) { - base.FromDatabaseAttributes(values); + base.FromDatabaseAttributes(values, onlineInfo); MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO]; StarRating = values[ATTRIB_ID_DIFFICULTY]; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 19217015c1..abab44b96a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using Newtonsoft.Json; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; @@ -96,9 +97,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty yield return (ATTRIB_ID_SLIDER_FACTOR, SliderFactor); } - public override void FromDatabaseAttributes(IReadOnlyDictionary values) + public override void FromDatabaseAttributes(IReadOnlyDictionary values, IBeatmapOnlineInfo onlineInfo) { - base.FromDatabaseAttributes(values); + base.FromDatabaseAttributes(values, onlineInfo); AimDifficulty = values[ATTRIB_ID_AIM]; SpeedDifficulty = values[ATTRIB_ID_SPEED]; @@ -108,6 +109,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty StarRating = values[ATTRIB_ID_DIFFICULTY]; FlashlightDifficulty = values.GetValueOrDefault(ATTRIB_ID_FLASHLIGHT); SliderFactor = values[ATTRIB_ID_SLIDER_FACTOR]; + + DrainRate = onlineInfo.DrainRate; + HitCircleCount = onlineInfo.CircleCount; + SliderCount = onlineInfo.SliderCount; + SpinnerCount = onlineInfo.SpinnerCount; } #region Newtonsoft.Json implicit ShouldSerialize() methods diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs index 6c617a22a4..eec59afc5b 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Newtonsoft.Json; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; namespace osu.Game.Rulesets.Taiko.Difficulty @@ -57,9 +58,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow); } - public override void FromDatabaseAttributes(IReadOnlyDictionary values) + public override void FromDatabaseAttributes(IReadOnlyDictionary values, IBeatmapOnlineInfo onlineInfo) { - base.FromDatabaseAttributes(values); + base.FromDatabaseAttributes(values, onlineInfo); MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO]; StarRating = values[ATTRIB_ID_DIFFICULTY]; diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index e0844a5c8a..1f08790408 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Difficulty @@ -74,7 +75,8 @@ namespace osu.Game.Rulesets.Difficulty /// Reads osu-web database attribute mappings into this object. /// /// The attribute mappings. - public virtual void FromDatabaseAttributes(IReadOnlyDictionary values) + /// The where more information about the beatmap may be extracted from (such as AR/CS/OD/etc). + public virtual void FromDatabaseAttributes(IReadOnlyDictionary values, IBeatmapOnlineInfo onlineInfo) { } } From 0fd2c010e5f8de3ec1ba777925d426dfcb63b55e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 27 Jun 2022 15:06:42 +0900 Subject: [PATCH 177/211] Remove NRT disables from attributes classes --- .../Difficulty/CatchDifficultyAttributes.cs | 2 -- .../Difficulty/ManiaDifficultyAttributes.cs | 2 -- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs | 2 -- .../Difficulty/TaikoDifficultyAttributes.cs | 2 -- osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs | 5 ++--- 5 files changed, 2 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs index c2f5aa3629..2d01153f98 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyAttributes.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Collections.Generic; using Newtonsoft.Json; using osu.Game.Beatmaps; diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs index 023c45fbcf..680732f26e 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Collections.Generic; using Newtonsoft.Json; using osu.Game.Beatmaps; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index abab44b96a..4b06502e32 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs index eec59afc5b..380ab4a4fc 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Collections.Generic; using Newtonsoft.Json; using osu.Game.Beatmaps; diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index 1f08790408..b0e83d6abe 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -1,8 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; @@ -31,7 +30,7 @@ namespace osu.Game.Rulesets.Difficulty /// /// The mods which were applied to the beatmap. /// - public Mod[] Mods { get; set; } + public Mod[] Mods { get; set; } = Array.Empty(); /// /// The combined star rating of all skills. From 5a7d339cc871aeacaf1f2623f289eb2b599e7253 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 16:19:31 +0900 Subject: [PATCH 178/211] Centralise and harden editor-ready-for-use check Not only does this combine the check into one location, but it also adds a check on the global `WorkingBeatmap` being updated, which is the only way I can see the following failure happening: ```csharp 05:19:07 osu.Game.Tests: osu.Game.Tests.Visual.Editing.TestSceneEditorBeatmapCreation.TestAddAudioTrack 05:19:07 Failed TestAddAudioTrack [161 ms] 05:19:07 Error Message: 05:19:07 TearDown : System.NullReferenceException : Object reference not set to an instance of an object. 05:19:07 Stack Trace: 05:19:07 --TearDown 05:19:07 at osu.Game.Database.ModelManager`1.<>c__DisplayClass7_0.b__0(TModel managed) in C:\BuildAgent\work\ecd860037212ac52\osu.Game\Database\ModelManager.cs:line 36 05:19:07 at osu.Game.Database.ModelManager`1.<>c__DisplayClass8_0.b__0(Realm realm) in C:\BuildAgent\work\ecd860037212ac52\osu.Game\Database\ModelManager.cs:line 49 05:19:07 at osu.Game.Database.RealmExtensions.Write(Realm realm, Action`1 function) in C:\BuildAgent\work\ecd860037212ac52\osu.Game\Database\RealmExtensions.cs:line 14 05:19:07 at osu.Game.Database.ModelManager`1.performFileOperation(TModel item, Action`1 operation) in C:\BuildAgent\work\ecd860037212ac52\osu.Game\Database\ModelManager.cs:line 46 05:19:07 at osu.Game.Database.ModelManager`1.AddFile(TModel item, Stream contents, String filename) in C:\BuildAgent\work\ecd860037212ac52\osu.Game\Database\ModelManager.cs:line 36 05:19:07 at osu.Game.Screens.Edit.Setup.ResourcesSection.ChangeAudioTrack(FileInfo source) in C:\BuildAgent\work\ecd860037212ac52\osu.Game\Screens\Edit\Setup\ResourcesSection.cs:line 115 05:19:07 at osu.Game.Tests.Visual.Editing.TestSceneEditorBeatmapCreation.b__13_0() in C:\BuildAgent\work\ecd860037212ac52\osu.Game.Tests\Visual\Editing\TestSceneEditorBeatmapCreation.cs:line 101 05:19:07 at osu.Framework.Testing.Drawables.Steps.AssertButton.checkAssert() 05:19:07 at osu.Framework.Testing.Drawables.Steps.StepButton.PerformStep(Boolean userTriggered) 05:19:07 at osu.Framework.Testing.TestScene.runNextStep(Action onCompletion, Action`1 onError, Func`2 stopCondition) ``` --- .../Editor/TestSceneSliderVelocityAdjust.cs | 9 ++---- .../Editing/TestSceneEditorBeatmapCreation.cs | 2 -- .../Editing/TestSceneEditorNavigation.cs | 7 +---- osu.Game/Screens/Edit/Editor.cs | 29 +++++++++++++++++++ osu.Game/Tests/Visual/EditorTestScene.cs | 8 ++--- 5 files changed, 34 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderVelocityAdjust.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderVelocityAdjust.cs index 3d9fe37e0f..ef9e332253 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderVelocityAdjust.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderVelocityAdjust.cs @@ -10,7 +10,6 @@ using osu.Framework.Input; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Beatmaps; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.UI; using osu.Game.Screens.Edit; @@ -41,10 +40,6 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false); - private bool editorComponentsReady => editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true - && editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true - && editor?.ChildrenOfType().FirstOrDefault()?.IsLoaded == true; - [TestCase(true)] [TestCase(false)] public void TestVelocityChangeSavesCorrectly(bool adjustVelocity) @@ -52,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor double? velocity = null; AddStep("enter editor", () => Game.ScreenStack.Push(new EditorLoader())); - AddUntilStep("wait for editor load", () => editorComponentsReady); + AddUntilStep("wait for editor load", () => editor?.ReadyForUse == true); AddStep("seek to first control point", () => editorClock.Seek(editorBeatmap.ControlPointInfo.TimingPoints.First().Time)); AddStep("enter slider placement mode", () => InputManager.Key(Key.Number3)); @@ -91,7 +86,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddStep("exit", () => InputManager.Key(Key.Escape)); AddStep("enter editor (again)", () => Game.ScreenStack.Push(new EditorLoader())); - AddUntilStep("wait for editor load", () => editorComponentsReady); + AddUntilStep("wait for editor load", () => editor?.ReadyForUse == true); AddStep("seek to slider", () => editorClock.Seek(slider.StartTime)); AddAssert("slider has correct velocity", () => slider.Velocity == velocity); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index fcbf63da79..b711d55e15 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -36,8 +36,6 @@ namespace osu.Game.Tests.Visual.Editing { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); - protected override bool EditorComponentsReady => Editor.ChildrenOfType().SingleOrDefault()?.IsLoaded == true; - protected override bool IsolateSavingFromDatabase => false; [Resolved] diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs index 273e8abcd7..62ca97d5e0 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs @@ -9,12 +9,10 @@ using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Database; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components.Timelines.Summary; -using osu.Game.Screens.Edit.Compose.Components.Timeline; using osu.Game.Screens.Edit.GameplayTest; using osu.Game.Screens.Select; using osu.Game.Tests.Resources; @@ -40,10 +38,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("switch ruleset", () => Game.Ruleset.Value = new ManiaRuleset().RulesetInfo); AddStep("open editor", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).Edit(beatmapSet.Beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == 0))); - AddUntilStep("wait for editor open", () => Game.ScreenStack.CurrentScreen is Editor editor - && editor.IsLoaded - && editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true - && editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); + AddUntilStep("wait for editor open", () => Game.ScreenStack.CurrentScreen is Editor editor && editor.ReadyForUse); AddStep("test gameplay", () => { var testGameplayButton = this.ChildrenOfType().Single(); diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 20bdf75b7d..9dbb5f4cfe 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -21,6 +21,7 @@ using osu.Framework.Input.Events; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Screens; +using osu.Framework.Testing; using osu.Framework.Timing; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -39,6 +40,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Screens.Edit.Components.Menus; using osu.Game.Screens.Edit.Compose; +using osu.Game.Screens.Edit.Compose.Components.Timeline; using osu.Game.Screens.Edit.Design; using osu.Game.Screens.Edit.GameplayTest; using osu.Game.Screens.Edit.Setup; @@ -97,6 +99,32 @@ namespace osu.Game.Screens.Edit public IBindable SamplePlaybackDisabled => samplePlaybackDisabled; + /// + /// Ensure all asynchronously loading pieces of the editor are in a good state. + /// This exists here for convenience for tests, not for actual use. + /// Eventually we'd probably want a better way to signal this. + /// + public bool ReadyForUse + { + get + { + if (!workingBeatmapUpdated) + return false; + + var loadedScreen = screenContainer?.Children.SingleOrDefault(s => s.IsLoaded); + + if (loadedScreen == null) + return false; + + if (loadedScreen is EditorScreenWithTimeline) + return loadedScreen.ChildrenOfType().FirstOrDefault()?.IsLoaded == true; + + return true; + } + } + + private bool workingBeatmapUpdated; + private readonly Bindable samplePlaybackDisabled = new Bindable(); private bool canSave; @@ -219,6 +247,7 @@ namespace osu.Game.Screens.Edit // this assumes that nothing during the rest of this load() method is accessing Beatmap.Value (loadableBeatmap should be preferred). // generally this is quite safe, as the actual load of editor content comes after menuBar.Mode.ValueChanged is fired in its own LoadComplete. Beatmap.Value = loadableBeatmap; + workingBeatmapUpdated = true; }); OsuMenuItem undoMenuItem; diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 3f5fee5768..31036247ab 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -17,9 +17,7 @@ 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; -using osu.Game.Screens.Edit.Compose.Components.Timeline; using osu.Game.Screens.Menu; using osu.Game.Skinning; @@ -58,15 +56,13 @@ namespace osu.Game.Tests.Visual Dependencies.CacheAs(testBeatmapManager = new TestBeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default)); } - protected virtual bool EditorComponentsReady => Editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true - && Editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true; - public override void SetUpSteps() { base.SetUpSteps(); AddStep("load editor", LoadEditor); - AddUntilStep("wait for editor to load", () => EditorComponentsReady); + AddUntilStep("wait for editor to load", () => Editor?.ReadyForUse == true); + AddUntilStep("wait for beatmap updated", () => !Beatmap.IsDefault); } protected virtual void LoadEditor() From 13dcaf82ada9d3e1a96322c49a194da0652b525d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 16:50:07 +0900 Subject: [PATCH 179/211] Fix chat tests failing 1/10000 runs https://github.com/ppy/osu/blob/31a447fda0532fcf15f8c8251ca890c533386492/osu.Game/Online/Chat/ChannelManager.cs#L412-L414 Sigh. --- osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs | 4 ++-- osu.Game/Online/API/DummyAPIAccess.cs | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 1fb0195368..73bad6e631 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -549,7 +549,7 @@ namespace osu.Game.Tests.Visual.Online private Channel createPrivateChannel() { - int id = RNG.Next(0, 10000); + int id = RNG.Next(0, DummyAPIAccess.DUMMY_USER_ID - 1); return new Channel(new APIUser { Id = id, @@ -559,7 +559,7 @@ namespace osu.Game.Tests.Visual.Online private Channel createAnnounceChannel() { - int id = RNG.Next(0, 10000); + int id = RNG.Next(0, DummyAPIAccess.DUMMY_USER_ID - 1); return new Channel { Name = $"Announce {id}", diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index 245760a00a..07d544260e 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -15,10 +15,12 @@ namespace osu.Game.Online.API { public class DummyAPIAccess : Component, IAPIProvider { + public const int DUMMY_USER_ID = 1001; + public Bindable LocalUser { get; } = new Bindable(new APIUser { Username = @"Dummy", - Id = 1001, + Id = DUMMY_USER_ID, }); public BindableList Friends { get; } = new BindableList(); From 8c3c1f095eaf966c3cc08691531e78582ae659ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 17:04:28 +0900 Subject: [PATCH 180/211] Update rollback test expectations I can't find a better way to do this. It's very hard to trigger an actual failure in the import process these days. For now I've just made this work with the new assumptions. May be worth removing the test in the future if this ever backfires. --- osu.Game.Tests/Database/BeatmapImporterTests.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index be11476c73..8c28f8cedd 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; using NUnit.Framework; @@ -607,6 +608,12 @@ namespace osu.Game.Tests.Database using (var outStream = File.Open(brokenTempFilename, FileMode.CreateNew)) using (var zip = ZipArchive.Open(brokenOsz)) { + foreach (var entry in zip.Entries.ToArray()) + { + if (entry.Key.EndsWith(".osu", StringComparison.InvariantCulture)) + zip.RemoveEntry(entry); + } + zip.AddEntry("broken.osu", brokenOsu, false); zip.SaveTo(outStream, CompressionType.Deflate); } @@ -627,7 +634,7 @@ namespace osu.Game.Tests.Database checkSingleReferencedFileCount(realm.Realm, 18); - Assert.AreEqual(1, loggedExceptionCount); + Assert.AreEqual(0, loggedExceptionCount); File.Delete(brokenTempFilename); }); From 401d9c1baed7bc9d60a88d286566a2e8537c1aff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 17:13:46 +0900 Subject: [PATCH 181/211] Fix `TestStoryboardSkipOutro` occasionally failing due to strict timings --- osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs index 002e35f742..0ba8583b56 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs @@ -52,10 +52,11 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestStoryboardSkipOutro() { + AddStep("set storyboard duration to long", () => currentStoryboardDuration = 200000); CreateTest(null); AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value); AddStep("skip outro", () => InputManager.Key(osuTK.Input.Key.Space)); - AddAssert("player is no longer current screen", () => !Player.IsCurrentScreen()); + AddUntilStep("player is no longer current screen", () => !Player.IsCurrentScreen()); AddUntilStep("wait for score shown", () => Player.IsScoreShown); } From f6a61472c413357bd46add03f2924d0662929dfb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 17:59:40 +0900 Subject: [PATCH 182/211] Fix occasional failure in realm test proceedings due to incorrect `Debug.Assert` After a `BlockAllOperations`, the restoration of the `updateRealm` instance is not instance. It is posted to a `SynchronizationContext`. The assertion which has been removed in this commit was assuming it would always be an immediate operation. To ensure this works as expected, I've tracked the initialised state via a new `bool`. ```csharp System.TimeoutException : Attempting to block for migration took too long. 1) Host threw exception System.AggregateException: One or more errors occurred. (: ) ---> NUnit.Framework.AssertionException: : at osu.Framework.Logging.ThrowingTraceListener.Fail(String message1, String message2) at System.Diagnostics.TraceInternal.Fail(String message, String detailMessage) at System.Diagnostics.TraceInternal.TraceProvider.Fail(String message, String detailMessage) at System.Diagnostics.Debug.Fail(String message, String detailMessage) at osu.Game.Database.RealmAccess.BlockAllOperations() in /opt/buildagent/work/ecd860037212ac52/osu.Game/Database/RealmAccess.cs:line 813 at osu.Game.OsuGameBase.<>c__DisplayClass108_1.b__0() in /opt/buildagent/work/ecd860037212ac52/osu.Game/OsuGameBase.cs:line 449 at osu.Framework.Threading.ScheduledDelegate.RunTaskInternal() at osu.Framework.Threading.Scheduler.Update() at osu.Framework.Graphics.Drawable.UpdateSubTree() at osu.Framework.Graphics.Containers.CompositeDrawable.UpdateSubTree() ``` https://teamcity.ppy.sh/buildConfiguration/Osu_Build/322?hideProblemsFromDependencies=false&hideTestsFromDependencies=false&expandBuildTestsSection=true --- osu.Game/Database/RealmAccess.cs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 3ea7a14826..089a783177 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -102,6 +102,12 @@ namespace osu.Game.Database private Realm? updateRealm; + /// + /// Tracks whether a realm was ever fetched from this instance. + /// After a fetch occurs, blocking operations will be guaranteed to restore any subscriptions. + /// + private bool hasInitialisedOnce; + private bool isSendingNotificationResetEvents; public Realm Realm => ensureUpdateRealm(); @@ -121,6 +127,7 @@ namespace osu.Game.Database if (updateRealm == null) { updateRealm = getRealmInstance(); + hasInitialisedOnce = true; Logger.Log(@$"Opened realm ""{updateRealm.Config.DatabasePath}"" at version {updateRealm.Config.SchemaVersion}"); @@ -806,13 +813,7 @@ namespace osu.Game.Database lock (realmLock) { - if (updateRealm == null) - { - // null realm means the update thread has not yet retrieved its instance. - // we don't need to worry about reviving the update instance in this case, so don't bother with the SynchronizationContext. - Debug.Assert(!ThreadSafety.IsUpdateThread); - } - else + if (hasInitialisedOnce) { if (!ThreadSafety.IsUpdateThread) throw new InvalidOperationException(@$"{nameof(BlockAllOperations)} must be called from the update thread."); @@ -827,12 +828,12 @@ namespace osu.Game.Database action.Value?.Dispose(); customSubscriptionsResetMap[action.Key] = null; } + + updateRealm?.Dispose(); + updateRealm = null; } Logger.Log(@"Blocking realm operations.", LoggingTarget.Database); - - updateRealm?.Dispose(); - updateRealm = null; } const int sleep_length = 200; From 5af1106fa5f0e9f49cadbbca052c3ee5d65d2df5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 18:04:52 +0900 Subject: [PATCH 183/211] Remove unused using statement --- osu.Game.Tests/Database/BeatmapImporterTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index 8c28f8cedd..6f5a79c9da 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using NUnit.Framework; From 0ba29b6fa64eac5a908903fbbfbe0270662879a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 18:28:00 +0900 Subject: [PATCH 184/211] Use `currentScreen` instead to make sure the screen we care about is loaded --- osu.Game/Screens/Edit/Editor.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 9dbb5f4cfe..81ae08aea1 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -111,13 +111,11 @@ namespace osu.Game.Screens.Edit if (!workingBeatmapUpdated) return false; - var loadedScreen = screenContainer?.Children.SingleOrDefault(s => s.IsLoaded); - - if (loadedScreen == null) + if (currentScreen?.IsLoaded != true) return false; - if (loadedScreen is EditorScreenWithTimeline) - return loadedScreen.ChildrenOfType().FirstOrDefault()?.IsLoaded == true; + if (currentScreen is EditorScreenWithTimeline) + return currentScreen.ChildrenOfType().FirstOrDefault()?.IsLoaded == true; return true; } From 50c1c066deff819c782f77e6bcd1814ed8b3b2a5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 18:41:27 +0900 Subject: [PATCH 185/211] Add various logging of global `WorkingBeatmap` state changes --- osu.Game/OsuGame.cs | 6 ++++++ osu.Game/Overlays/MusicController.cs | 3 +++ osu.Game/Screens/Menu/MainMenu.cs | 3 +++ osu.Game/Screens/Select/SongSelect.cs | 7 +++++-- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index f51a18b36f..1458af1ea1 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -486,6 +486,7 @@ namespace osu.Game /// public void PresentBeatmap(IBeatmapSetInfo beatmap, Predicate difficultyCriteria = null) { + Logger.Log($"Beginning {nameof(PresentBeatmap)} with beatmap {beatmap}"); Live databasedSet = null; if (beatmap.OnlineID > 0) @@ -522,6 +523,7 @@ namespace osu.Game } else { + Logger.Log($"Completing {nameof(PresentBeatmap)} with beatmap {beatmap} ruleset {selection.Ruleset}"); Ruleset.Value = selection.Ruleset; Beatmap.Value = BeatmapManager.GetWorkingBeatmap(selection); } @@ -534,6 +536,8 @@ namespace osu.Game /// public void PresentScore(IScoreInfo score, ScorePresentType presentType = ScorePresentType.Results) { + Logger.Log($"Beginning {nameof(PresentScore)} with score {score}"); + // The given ScoreInfo may have missing properties if it was retrieved from online data. Re-retrieve it from the database // to ensure all the required data for presenting a replay are present. ScoreInfo databasedScoreInfo = null; @@ -568,6 +572,8 @@ namespace osu.Game PerformFromScreen(screen => { + Logger.Log($"{nameof(PresentScore)} updating beatmap ({databasedBeatmap}) and ruleset ({databasedScore.ScoreInfo.Ruleset} to match score"); + Ruleset.Value = databasedScore.ScoreInfo.Ruleset; Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap); diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index bce7e9b797..1c2c9f2b48 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -14,6 +14,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Audio; using osu.Framework.Graphics.Containers; +using osu.Framework.Logging; using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Database; @@ -106,10 +107,12 @@ namespace osu.Game.Overlays if (beatmap.Disabled) return; + Logger.Log($"{nameof(MusicController)} skipping to next track to {nameof(EnsurePlayingSomething)}"); NextTrack(); } else if (!IsPlaying) { + Logger.Log($"{nameof(MusicController)} starting playback to {nameof(EnsurePlayingSomething)}"); Play(); } } diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 6a74a6bd6e..ba63902b46 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -10,6 +10,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Game.Beatmaps; @@ -302,6 +303,8 @@ namespace osu.Game.Screens.Menu public void PresentBeatmap(WorkingBeatmap beatmap, RulesetInfo ruleset) { + Logger.Log($"{nameof(MainMenu)} completing {nameof(PresentBeatmap)} with beatmap {beatmap} ruleset {ruleset}"); + Beatmap.Value = beatmap; Ruleset.Value = ruleset; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 41fb55a856..b89acfa570 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -494,7 +494,7 @@ namespace osu.Game.Screens.Select // clear pending task immediately to track any potential nested debounce operation. selectionChangedDebounce = null; - Logger.Log($"updating selection with beatmap:{beatmap?.ID.ToString() ?? "null"} ruleset:{ruleset?.ShortName ?? "null"}"); + Logger.Log($"Song select updating selection with beatmap:{beatmap?.ID.ToString() ?? "null"} ruleset:{ruleset?.ShortName ?? "null"}"); if (transferRulesetValue()) { @@ -519,7 +519,7 @@ namespace osu.Game.Screens.Select // In these cases, the other component has already loaded the beatmap, so we don't need to do so again. if (!EqualityComparer.Default.Equals(beatmap, Beatmap.Value.BeatmapInfo)) { - Logger.Log($"beatmap changed from \"{Beatmap.Value.BeatmapInfo}\" to \"{beatmap}\""); + Logger.Log($"Song select changing beatmap from \"{Beatmap.Value.BeatmapInfo}\" to \"{beatmap?.ToString() ?? "null"}\""); Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap); } @@ -737,7 +737,10 @@ namespace osu.Game.Screens.Select bool isNewTrack = !lastTrack.TryGetTarget(out var last) || last != track; if (!track.IsRunning && (music.UserPauseRequested != true || isNewTrack)) + { + Logger.Log($"Song select decided to {nameof(ensurePlayingSelected)}"); music.Play(true); + } lastTrack.SetTarget(track); } From aa7d54f8b6c31fd7e485721da2de000b4855414e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 27 Jun 2022 20:10:15 +0900 Subject: [PATCH 186/211] Add logging for various cases of `SongSelect.FinaliseSelection` being aborted --- .../OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs | 4 ++++ osu.Game/Screens/Select/SongSelect.cs | 3 +++ 2 files changed, 7 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 0f589a8b35..dbd679104e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; @@ -78,7 +79,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override bool SelectItem(PlaylistItem item) { if (operationInProgress.Value) + { + Logger.Log($"{nameof(SelectedItem)} aborted due to {nameof(operationInProgress)}"); return false; + } // If the client is already in a room, update via the client. // Otherwise, update the playlist directly in preparation for it to be submitted to the API on match creation. diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 41fb55a856..4e45abab3f 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -360,7 +360,10 @@ namespace osu.Game.Screens.Select { // This is very important as we have not yet bound to screen-level bindables before the carousel load is completed. if (!Carousel.BeatmapSetsLoaded) + { + Logger.Log($"{nameof(FinaliseSelection)} aborted as carousel beatmaps are not yet loaded"); return; + } if (ruleset != null) Ruleset.Value = ruleset; From 6c6de9ce533d5cd99b38390b396cabdc3ec34e9f Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 27 Jun 2022 20:40:02 +0900 Subject: [PATCH 187/211] Fix typo --- osu.Game/Overlays/MusicController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 1c2c9f2b48..4a10f30a7a 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -107,7 +107,7 @@ namespace osu.Game.Overlays if (beatmap.Disabled) return; - Logger.Log($"{nameof(MusicController)} skipping to next track to {nameof(EnsurePlayingSomething)}"); + Logger.Log($"{nameof(MusicController)} skipping next track to {nameof(EnsurePlayingSomething)}"); NextTrack(); } else if (!IsPlaying) From 3e3843dcf9a8a943f730a3e74ca2cd5f44dd20c8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Jun 2022 00:32:36 +0900 Subject: [PATCH 188/211] Fix potential crash on `CloseAllOverlays` due to collection mutation --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 7f4e4af455..01f0b09a3e 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -249,7 +249,7 @@ namespace osu.Game /// Whether the toolbar should also be hidden. public void CloseAllOverlays(bool hideToolbar = true) { - foreach (var overlay in focusedOverlays) + foreach (var overlay in focusedOverlays.ToArray()) overlay.Hide(); if (hideToolbar) Toolbar.Hide(); From b28cfc222b22a417f69f6449f36465c5a20cb385 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Jun 2022 01:19:20 +0900 Subject: [PATCH 189/211] Schedule unregister instead --- osu.Game/OsuGame.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 01f0b09a3e..ef42522f9d 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -231,7 +231,7 @@ namespace osu.Game /// /// Unregisters a blocking that was not created by itself. /// - private void unregisterBlockingOverlay(OverlayContainer overlayContainer) + private void unregisterBlockingOverlay(OverlayContainer overlayContainer) => Schedule(() => { externalOverlays.Remove(overlayContainer); @@ -239,7 +239,7 @@ namespace osu.Game focusedOverlays.Remove(focusedOverlayContainer); overlayContainer.Expire(); - } + }); #endregion @@ -249,7 +249,7 @@ namespace osu.Game /// Whether the toolbar should also be hidden. public void CloseAllOverlays(bool hideToolbar = true) { - foreach (var overlay in focusedOverlays.ToArray()) + foreach (var overlay in focusedOverlays) overlay.Hide(); if (hideToolbar) Toolbar.Hide(); From 569fde4b47976898cf1df4cd5965e54af7caa238 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Jun 2022 01:34:24 +0900 Subject: [PATCH 190/211] Add messages to all `InvalidOperationException`s Without this, they can be very non-descript and hard to track down --- osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs | 8 ++++---- osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs | 8 ++++---- .../Visual/SongSelect/TestSceneAdvancedStats.cs | 2 +- osu.Game/Online/API/Requests/Responses/APIScore.cs | 2 +- osu.Game/Online/Rooms/MultiplayerScore.cs | 2 +- .../Profile/Sections/Ranks/DrawableProfileScore.cs | 2 +- osu.Game/Screens/Edit/EditorBeatmap.cs | 2 +- osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs b/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs index a779fae510..14da07bc2d 100644 --- a/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs +++ b/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs @@ -83,14 +83,14 @@ namespace osu.Game.Tests.NonVisual public override event Action NewResult { - add => throw new InvalidOperationException(); - remove => throw new InvalidOperationException(); + add => throw new InvalidOperationException($"{nameof(NewResult)} operations not supported in test context"); + remove => throw new InvalidOperationException($"{nameof(NewResult)} operations not supported in test context"); } public override event Action RevertResult { - add => throw new InvalidOperationException(); - remove => throw new InvalidOperationException(); + add => throw new InvalidOperationException($"{nameof(RevertResult)} operations not supported in test context"); + remove => throw new InvalidOperationException($"{nameof(RevertResult)} operations not supported in test context"); } public override Playfield Playfield { get; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs index 70d7f6a28b..707f807e64 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs @@ -273,14 +273,14 @@ namespace osu.Game.Tests.Visual.Gameplay public override event Action NewResult { - add => throw new InvalidOperationException(); - remove => throw new InvalidOperationException(); + add => throw new InvalidOperationException($"{nameof(NewResult)} operations not supported in test context"); + remove => throw new InvalidOperationException($"{nameof(NewResult)} operations not supported in test context"); } public override event Action RevertResult { - add => throw new InvalidOperationException(); - remove => throw new InvalidOperationException(); + add => throw new InvalidOperationException($"{nameof(RevertResult)} operations not supported in test context"); + remove => throw new InvalidOperationException($"{nameof(RevertResult)} operations not supported in test context"); } public override Playfield Playfield { get; } diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs index 77670c38f3..4510fda11d 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs @@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual.SongSelect { AddStep("set beatmap", () => advancedStats.BeatmapInfo = new BeatmapInfo { - Ruleset = rulesets.GetRuleset(3) ?? throw new InvalidOperationException(), + Ruleset = rulesets.GetRuleset(3) ?? throw new InvalidOperationException("osu!mania ruleset not found"), Difficulty = new BeatmapDifficulty { CircleSize = 5, diff --git a/osu.Game/Online/API/Requests/Responses/APIScore.cs b/osu.Game/Online/API/Requests/Responses/APIScore.cs index 1b56362aec..f236607761 100644 --- a/osu.Game/Online/API/Requests/Responses/APIScore.cs +++ b/osu.Game/Online/API/Requests/Responses/APIScore.cs @@ -88,7 +88,7 @@ namespace osu.Game.Online.API.Requests.Responses /// public ScoreInfo CreateScoreInfo(RulesetStore rulesets, BeatmapInfo beatmap = null) { - var ruleset = rulesets.GetRuleset(RulesetID) ?? throw new InvalidOperationException(); + var ruleset = rulesets.GetRuleset(RulesetID) ?? throw new InvalidOperationException($"Ruleset with ID of {RulesetID} not found locally"); var rulesetInstance = ruleset.CreateInstance(); diff --git a/osu.Game/Online/Rooms/MultiplayerScore.cs b/osu.Game/Online/Rooms/MultiplayerScore.cs index 13f14bca5b..6f597e5b10 100644 --- a/osu.Game/Online/Rooms/MultiplayerScore.cs +++ b/osu.Game/Online/Rooms/MultiplayerScore.cs @@ -79,7 +79,7 @@ namespace osu.Game.Online.Rooms TotalScore = TotalScore, MaxCombo = MaxCombo, BeatmapInfo = beatmap, - Ruleset = rulesets.GetRuleset(playlistItem.RulesetID) ?? throw new InvalidOperationException(), + Ruleset = rulesets.GetRuleset(playlistItem.RulesetID) ?? throw new InvalidOperationException($"Ruleset with ID of {playlistItem.RulesetID} not found locally"), Statistics = Statistics, User = User, Accuracy = Accuracy, diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs index 54a262f6a6..90a357a281 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs @@ -136,7 +136,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks Spacing = new Vector2(2), Children = Score.Mods.Select(mod => { - var ruleset = rulesets.GetRuleset(Score.RulesetID) ?? throw new InvalidOperationException(); + var ruleset = rulesets.GetRuleset(Score.RulesetID) ?? throw new InvalidOperationException($"Ruleset with ID of {Score.RulesetID} not found locally"); return new ModIcon(ruleset.CreateInstance().CreateModFromAcronym(mod.Acronym)) { diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 0a6f9974b0..96425e8bc8 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -122,7 +122,7 @@ namespace osu.Game.Screens.Edit public BeatmapInfo BeatmapInfo { get => beatmapInfo; - set => throw new InvalidOperationException(); + set => throw new InvalidOperationException($"Can't set {nameof(BeatmapInfo)} on {nameof(EditorBeatmap)}"); } public BeatmapMetadata Metadata => beatmapInfo.Metadata; diff --git a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs index fc29c5aac5..db1d94aee2 100644 --- a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs +++ b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs @@ -134,7 +134,7 @@ namespace osu.Game.Tests.Visual.Spectator FrameSendAttempts++; if (ShouldFailSendingFrames) - return Task.FromException(new InvalidOperationException()); + return Task.FromException(new InvalidOperationException($"Intentional fail via {ShouldFailSendingFrames}")); return ((ISpectatorClient)this).UserSentFrames(api.LocalUser.Value.Id, bundle); } From 54fe6b7df3ae62e0dc7a61f28ef0e3ff85aee06e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Jun 2022 01:43:09 +0900 Subject: [PATCH 191/211] Fix incorrect string interpolation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs index db1d94aee2..2531f3c485 100644 --- a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs +++ b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs @@ -134,7 +134,7 @@ namespace osu.Game.Tests.Visual.Spectator FrameSendAttempts++; if (ShouldFailSendingFrames) - return Task.FromException(new InvalidOperationException($"Intentional fail via {ShouldFailSendingFrames}")); + return Task.FromException(new InvalidOperationException($"Intentional fail via {nameof(ShouldFailSendingFrames)}")); return ((ISpectatorClient)this).UserSentFrames(api.LocalUser.Value.Id, bundle); } From 1a0228415d526599dbba42ba8cc08ba767142367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 27 Jun 2022 22:26:00 +0200 Subject: [PATCH 192/211] Wait for and dismiss notification in editor navigation test --- osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs index 62ca97d5e0..a21ef6f897 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs @@ -9,6 +9,7 @@ using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Database; +using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Edit; @@ -35,6 +36,8 @@ namespace osu.Game.Tests.Visual.Editing () => Game.Beatmap.Value.BeatmapSetInfo.Equals(beatmapSet) && Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect && songSelect.IsLoaded); + AddUntilStep("wait for completion notification", () => Game.Notifications.ChildrenOfType().Count() == 1); + AddStep("dismiss notifications", () => Game.Notifications.Hide()); AddStep("switch ruleset", () => Game.Ruleset.Value = new ManiaRuleset().RulesetInfo); AddStep("open editor", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).Edit(beatmapSet.Beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == 0))); From c1075d113fb13b586a216444946057f936c8d86a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Jun 2022 13:58:35 +0900 Subject: [PATCH 193/211] Add logging around current channel changes and join requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tracking down a flaky test (https://teamcity.ppy.sh/buildConfiguration/Osu_Build/553?hideProblemsFromDependencies=false&expandBuildTestsSection=true&hideTestsFromDependencies=false): ```csharp TearDown : System.TimeoutException : "PM Channel 1 displayed" timed out --TearDown at osu.Framework.Testing.Drawables.Steps.UntilStepButton.<>c__DisplayClass11_0.<.ctor>b__0() at osu.Framework.Testing.Drawables.Steps.StepButton.PerformStep(Boolean userTriggered) at osu.Framework.Testing.TestScene.runNextStep(Action onCompletion, Action`1 onError, Func`2 stopCondition) --- End of stack trace from previous location --- at osu.Framework.Testing.TestSceneTestRunner.TestRunner.RunTestBlocking(TestScene test) at osu.Game.Tests.Visual.OsuTestScene.OsuTestSceneTestRunner.RunTestBlocking(TestScene test) in /opt/buildagent/work/ecd860037212ac52/osu.Game/Tests/Visual/OsuTestScene.cs:line 503 at osu.Framework.Testing.TestScene.RunTestsFromNUnit() ------- Stdout: ------- [runtime] 2022-06-27 23:18:55 [verbose]: 💨 Class: TestSceneChatOverlay [runtime] 2022-06-27 23:18:55 [verbose]: 🔶 Test: TestKeyboardNextChannel [runtime] 2022-06-27 23:18:55 [verbose]: Chat is now polling every 60000 ms [runtime] 2022-06-27 23:18:55 [verbose]: 🔸 Step #1 Setup request handler [runtime] 2022-06-27 23:18:55 [verbose]: 🔸 Step #2 Add test channels [runtime] 2022-06-27 23:18:55 [verbose]: 🔸 Step #3 Show overlay with channels [runtime] 2022-06-27 23:18:55 [verbose]: Unhandled Request Type: osu.Game.Online.API.Requests.CreateChannelRequest [network] 2022-06-27 23:18:55 [verbose]: Failing request osu.Game.Online.API.Requests.CreateChannelRequest (System.InvalidOperationException: DummyAPIAccess cannot process this request.) [runtime] 2022-06-27 23:18:55 [verbose]: Unhandled Request Type: osu.Game.Online.API.Requests.CreateChannelRequest [network] 2022-06-27 23:18:55 [verbose]: Failing request osu.Game.Online.API.Requests.CreateChannelRequest (System.InvalidOperationException: DummyAPIAccess cannot process this request.) [runtime] 2022-06-27 23:18:55 [verbose]: 🔸 Step #4 Select channel 1 [runtime] 2022-06-27 23:18:55 [verbose]: 🔸 Step #5 Channel 1 is visible [runtime] 2022-06-27 23:18:55 [verbose]: 🔸 Step #6 Press document next keys [runtime] 2022-06-27 23:18:55 [verbose]: 🔸 Step #7 Channel 2 is visible [runtime] 2022-06-27 23:18:55 [verbose]: 🔸 Step #8 Press document next keys [runtime] 2022-06-27 23:18:55 [verbose]: 🔸 Step #9 PM Channel 1 displayed [network] 2022-06-27 23:18:55 [verbose]: Request to https://a.ppy.sh/587 failed with System.Net.WebException: NotFound. [network] 2022-06-27 23:18:55 [verbose]: Request to https://a.ppy.sh/503 failed with System.Net.WebException: NotFound. [runtime] 2022-06-27 23:19:05 [verbose]: 💥 Failed (on attempt 5,550) [runtime] 2022-06-27 23:19:05 [verbose]: ⏳ Currently loading components (0) [runtime] 2022-06-27 23:19:05 [verbose]: 🧵 Task schedulers [runtime] 2022-06-27 23:19:05 [verbose]: LoadComponentsAsync (standard) concurrency:4 running:0 pending:0 [runtime] 2022-06-27 23:19:05 [verbose]: LoadComponentsAsync (long load) concurrency:4 running:0 pending:0 [runtime] 2022-06-27 23:19:05 [verbose]: 🎱 Thread pool [runtime] 2022-06-27 23:19:05 [verbose]: worker: min 1 max 32,767 available 32,766 [runtime] 2022-06-27 23:19:05 [verbose]: completion: min 1 max 1,000 available 1,000 [runtime] 2022-06-27 23:19:05 [debug]: Focus on "ChatTextBox" no longer valid as a result of unfocusIfNoLongerValid. [runtime] 2022-06-27 23:19:05 [debug]: Focus changed from ChatTextBox to nothing. ``` This kind of logging should be helpful: ```csharp [runtime] 2022-06-28 04:59:57 [verbose]: 🔸 Step #5 Channel 1 is visible [runtime] 2022-06-28 04:59:57 [verbose]: 🔸 Step #6 Press document next keys [runtime] 2022-06-28 04:59:57 [verbose]: Current channel changed to #channel-2 [runtime] 2022-06-28 04:59:57 [debug]: Pressed (DocumentNext) handled by TestSceneChatOverlay+TestChatOverlay. [runtime] 2022-06-28 04:59:57 [debug]: KeyDownEvent(PageDown, False) handled by ManualInputManager+LocalPlatformActionContainer. [runtime] 2022-06-28 04:59:57 [verbose]: 🔸 Step #7 Channel 2 is visible [runtime] 2022-06-28 04:59:57 [verbose]: 🔸 Step #8 Press document next keys [runtime] 2022-06-28 04:59:57 [verbose]: Current channel changed to test user 685 [runtime] 2022-06-28 04:59:57 [debug]: Pressed (DocumentNext) handled by TestSceneChatOverlay+TestChatOverlay. [runtime] 2022-06-28 04:59:57 [debug]: KeyDownEvent(PageDown, False) handled by ManualInputManager+LocalPlatformActionContainer. [runtime] 2022-06-28 04:59:57 [verbose]: 🔸 Step #9 PM Channel 1 displayed [runtime] 2022-06-28 04:59:57 [verbose]: 🔸 Step #10 Press document next keys [runtime] 2022-06-28 04:59:57 [verbose]: Current channel changed to test user 218 ``` --- .../Visual/Online/TestSceneChatOverlay.cs | 2 +- osu.Game/Online/Chat/ChannelManager.cs | 30 +++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 73bad6e631..ff2817c439 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -472,8 +472,8 @@ namespace osu.Game.Tests.Visual.Online }); AddStep("Select channel 1", () => clickDrawable(getChannelListItem(testChannel1))); - waitForChannel1Visible(); + AddStep("Press document next keys", () => InputManager.Keys(PlatformAction.DocumentNext)); waitForChannel2Visible(); diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 48dfaadfa5..ec84b0643d 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -133,12 +133,14 @@ namespace osu.Game.Online.Chat ?? JoinChannel(new Channel(user)); } - private void currentChannelChanged(ValueChangedEvent e) + private void currentChannelChanged(ValueChangedEvent channel) { - bool isSelectorChannel = e.NewValue is ChannelListing.ChannelListingChannel; + bool isSelectorChannel = channel.NewValue is ChannelListing.ChannelListingChannel; if (!isSelectorChannel) - JoinChannel(e.NewValue); + JoinChannel(channel.NewValue); + + Logger.Log($"Current channel changed to {channel.NewValue}"); } /// @@ -447,9 +449,17 @@ namespace osu.Game.Online.Chat return channel; case ChannelType.PM: + Logger.Log($"Attempting to join PM channel {channel}"); + var createRequest = new CreateChannelRequest(channel); + createRequest.Failure += e => + { + Logger.Log($"Failed to join PM channel {channel} ({e.Message})"); + }; createRequest.Success += resChannel => { + Logger.Log($"Joined PM channel {channel} ({resChannel.ChannelID})"); + if (resChannel.ChannelID.HasValue) { channel.Id = resChannel.ChannelID.Value; @@ -463,9 +473,19 @@ namespace osu.Game.Online.Chat break; default: + Logger.Log($"Attempting to join public channel {channel}"); + var req = new JoinChannelRequest(channel); - req.Success += () => joinChannel(channel, fetchInitialMessages); - req.Failure += _ => LeaveChannel(channel); + req.Success += () => + { + Logger.Log($"Joined public channel {channel}"); + joinChannel(channel, fetchInitialMessages); + }; + req.Failure += e => + { + Logger.Log($"Failed to join public channel {channel} ({e.Message})"); + LeaveChannel(channel); + }; api.Queue(req); return channel; } From a2701a32055c752fb2ce6c8a937623b69da583b6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Jun 2022 14:58:33 +0900 Subject: [PATCH 194/211] Increase leaniences on `TestSceneSpectatorPlayback.TestWithSendFailure` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not really sure how to improve this further, but should help with cases like this: ```csharp [runtime] 2022-06-28 05:32:06 [verbose]: 💨 Class: TestSceneSpectatorPlayback [runtime] 2022-06-28 05:32:06 [verbose]: 🔶 Test: TestWithSendFailure [runtime] 2022-06-28 05:32:06 [verbose]: 🔸 Step #1 Setup containers [runtime] 2022-06-28 05:32:06 [verbose]: Received 1 new frames (total 1 of 2) [runtime] 2022-06-28 05:32:06 [verbose]: 🔸 Step #2 received frames [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 7 of 8) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 13 of 19) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 19 of 29) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 25 of 44) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 31 of 45) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 37 of 59) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 43 of 67) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 49 of 125) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 55 of 126) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 61 of 127) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 67 of 128) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 73 of 129) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 79 of 130) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 85 of 131) [runtime] 2022-06-28 05:32:06 [verbose]: ✔️ 22 repetitions [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 91 of 132) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 97 of 133) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 103 of 134) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 109 of 135) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 115 of 136) [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 121 of 137) [runtime] 2022-06-28 05:32:06 [verbose]: 🔸 Step #3 start failing sends [runtime] 2022-06-28 05:32:06 [verbose]: Received 6 new frames (total 127 of 138) [runtime] 2022-06-28 05:32:06 [verbose]: 🔸 Step #4 wait for send attempts [runtime] 2022-06-28 05:32:06 [verbose]: 🔸 Step #5 frames did not increase [runtime] 2022-06-28 05:32:06 [verbose]: 💥 Failed [runtime] 2022-06-28 05:32:06 [verbose]: ⏳ Currently loading components (0) [runtime] 2022-06-28 05:32:06 [verbose]: 🧵 Task schedulers [runtime] 2022-06-28 05:32:06 [verbose]: LoadComponentsAsync (standard) concurrency:4 running:0 pending:0 [runtime] 2022-06-28 05:32:06 [verbose]: LoadComponentsAsync (long load) concurrency:4 running:0 pending:0 [runtime] 2022-06-28 05:32:06 [verbose]: 🎱 Thread pool [runtime] 2022-06-28 05:32:06 [verbose]: worker: min 1 max 32,767 available 32,766 [runtime] 2022-06-28 05:32:06 [verbose]: completion: min 1 max 1,000 available 1,000 [runtime] 2022-06-28 05:32:06 [verbose]: Host execution state changed to Stopping ``` https://teamcity.ppy.sh/buildConfiguration/Osu_Build/811?hideProblemsFromDependencies=false&hideTestsFromDependencies=false&expandBuildTestsSection=true --- .../Visual/Gameplay/TestSceneSpectatorPlayback.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs index 1e517efef2..5fad661e9b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs @@ -167,11 +167,16 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("start failing sends", () => { spectatorClient.ShouldFailSendingFrames = true; - framesReceivedSoFar = replay.Frames.Count; frameSendAttemptsSoFar = spectatorClient.FrameSendAttempts; }); - AddUntilStep("wait for send attempts", () => spectatorClient.FrameSendAttempts > frameSendAttemptsSoFar + 5); + AddUntilStep("wait for next send attempt", () => + { + framesReceivedSoFar = replay.Frames.Count; + return spectatorClient.FrameSendAttempts > frameSendAttemptsSoFar + 1; + }); + + AddUntilStep("wait for more send attempts", () => spectatorClient.FrameSendAttempts > frameSendAttemptsSoFar + 10); AddAssert("frames did not increase", () => framesReceivedSoFar == replay.Frames.Count); AddStep("stop failing sends", () => spectatorClient.ShouldFailSendingFrames = false); From 22b254e5c5ce9aee62f21f0863394f26e1212a2c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Jun 2022 15:09:28 +0900 Subject: [PATCH 195/211] Handle task exception outside of schedule to avoid unobserved exceptions --- osu.Game/Online/Spectator/SpectatorClient.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game/Online/Spectator/SpectatorClient.cs b/osu.Game/Online/Spectator/SpectatorClient.cs index 4a43aa6c66..08e1e78d86 100644 --- a/osu.Game/Online/Spectator/SpectatorClient.cs +++ b/osu.Game/Online/Spectator/SpectatorClient.cs @@ -294,17 +294,21 @@ namespace osu.Game.Online.Spectator lastSend = tcs.Task; - SendFramesInternal(bundle).ContinueWith(t => Schedule(() => + SendFramesInternal(bundle).ContinueWith(t => { + // Handle exception outside of `Schedule` to ensure it doesn't go unovserved. bool wasSuccessful = t.Exception == null; - // If the last bundle send wasn't successful, try again without dequeuing. - if (wasSuccessful) - pendingFrameBundles.Dequeue(); + return Schedule(() => + { + // If the last bundle send wasn't successful, try again without dequeuing. + if (wasSuccessful) + pendingFrameBundles.Dequeue(); - tcs.SetResult(wasSuccessful); - sendNextBundleIfRequired(); - })); + tcs.SetResult(wasSuccessful); + sendNextBundleIfRequired(); + }); + }); } } } From 35745c83b7fa468468c5b032bda97d5120c59f27 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Jun 2022 15:19:02 +0900 Subject: [PATCH 196/211] Replace dodgy `SetUpSteps` overriding with usage of `HasCustomSteps` --- .../TestSceneCatchPlayerLegacySkin.cs | 2 +- .../TestSceneSliderSnaking.cs | 29 ++++++------------- .../TestSceneStoryboardSamplePlayback.cs | 2 +- .../Gameplay/TestSceneStoryboardWithOutro.cs | 12 ++++---- osu.Game/Tests/Visual/PlayerTestScene.cs | 4 +-- 5 files changed, 19 insertions(+), 30 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs index 731cb4e135..8dd6f82c57 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.Tests AddStep("change component scale", () => Player.ChildrenOfType().First().Scale = new Vector2(2f)); AddStep("update target", () => Player.ChildrenOfType().ForEach(LegacySkin.UpdateDrawableTarget)); AddStep("exit player", () => Player.Exit()); - CreateTest(null); + CreateTest(); } AddAssert("legacy HUD combo counter hidden", () => diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs index 5706955fc5..366793058d 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs @@ -66,10 +66,7 @@ namespace osu.Game.Rulesets.Osu.Tests drawableSlider = null; }); - [SetUpSteps] - public override void SetUpSteps() - { - } + protected override bool HasCustomSteps => true; [TestCase(0)] [TestCase(1)] @@ -77,7 +74,7 @@ namespace osu.Game.Rulesets.Osu.Tests public void TestSnakingEnabled(int sliderIndex) { AddStep("enable autoplay", () => autoplay = true); - base.SetUpSteps(); + CreateTest(); AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning); retrieveSlider(sliderIndex); @@ -101,7 +98,7 @@ namespace osu.Game.Rulesets.Osu.Tests public void TestSnakingDisabled(int sliderIndex) { AddStep("have autoplay", () => autoplay = true); - base.SetUpSteps(); + CreateTest(); AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning); retrieveSlider(sliderIndex); @@ -121,8 +118,7 @@ namespace osu.Game.Rulesets.Osu.Tests { AddStep("enable autoplay", () => autoplay = true); setSnaking(true); - base.SetUpSteps(); - + CreateTest(); // repeat might have a chance to update its position depending on where in the frame its hit, // so some leniency is allowed here instead of checking strict equality addCheckPositionChangeSteps(() => 16600, getSliderRepeat, positionAlmostSame); @@ -133,15 +129,14 @@ namespace osu.Game.Rulesets.Osu.Tests { AddStep("disable autoplay", () => autoplay = false); setSnaking(true); - base.SetUpSteps(); - + CreateTest(); addCheckPositionChangeSteps(() => 16600, getSliderRepeat, positionDecreased); } private void retrieveSlider(int index) { AddStep("retrieve slider at index", () => slider = (Slider)beatmap.HitObjects[index]); - addSeekStep(() => slider); + addSeekStep(() => slider.StartTime); AddUntilStep("retrieve drawable slider", () => (drawableSlider = (DrawableSlider)Player.DrawableRuleset.Playfield.AllHitObjects.SingleOrDefault(d => d.HitObject == slider)) != null); } @@ -205,16 +200,10 @@ namespace osu.Game.Rulesets.Osu.Tests }); } - private void addSeekStep(Func slider) + private void addSeekStep(Func getTime) { - AddStep("seek to slider", () => Player.GameplayClockContainer.Seek(slider().StartTime)); - AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(slider().StartTime, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100)); - } - - private void addSeekStep(Func time) - { - AddStep("seek to time", () => Player.GameplayClockContainer.Seek(time())); - AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time(), Player.DrawableRuleset.FrameStableClock.CurrentTime, 100)); + AddStep("seek to time", () => Player.GameplayClockContainer.Seek(getTime())); + AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(getTime(), Player.DrawableRuleset.FrameStableClock.CurrentTime, 100)); } protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap { HitObjects = createHitObjects() }; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardSamplePlayback.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardSamplePlayback.cs index 079d459beb..f0e184d727 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardSamplePlayback.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardSamplePlayback.cs @@ -121,7 +121,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void createPlayerTest() { - CreateTest(null); + CreateTest(); AddAssert("storyboard loaded", () => Player.Beatmap.Value.Storyboard != null); waitUntilStoryboardSamplesPlay(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs index 0ba8583b56..e2b2ad85a3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs @@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestStoryboardSkipOutro() { AddStep("set storyboard duration to long", () => currentStoryboardDuration = 200000); - CreateTest(null); + CreateTest(); AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value); AddStep("skip outro", () => InputManager.Key(osuTK.Input.Key.Space)); AddUntilStep("player is no longer current screen", () => !Player.IsCurrentScreen()); @@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestStoryboardNoSkipOutro() { - CreateTest(null); + CreateTest(); AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= currentStoryboardDuration); AddUntilStep("wait for score shown", () => Player.IsScoreShown); } @@ -71,7 +71,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestStoryboardExitDuringOutroStillExits() { - CreateTest(null); + CreateTest(); AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value); AddStep("exit via pause", () => Player.ExitViaPause()); AddAssert("player exited", () => !Player.IsCurrentScreen() && Player.GetChildScreen() == null); @@ -81,7 +81,7 @@ namespace osu.Game.Tests.Visual.Gameplay [TestCase(true)] public void TestStoryboardToggle(bool enabledAtBeginning) { - CreateTest(null); + CreateTest(); AddStep($"{(enabledAtBeginning ? "enable" : "disable")} storyboard", () => LocalConfig.SetValue(OsuSetting.ShowStoryboard, enabledAtBeginning)); AddStep("toggle storyboard", () => LocalConfig.SetValue(OsuSetting.ShowStoryboard, !enabledAtBeginning)); AddUntilStep("wait for score shown", () => Player.IsScoreShown); @@ -130,7 +130,7 @@ namespace osu.Game.Tests.Visual.Gameplay { SkipOverlay.FadeContainer fadeContainer() => Player.ChildrenOfType().First(); - CreateTest(null); + CreateTest(); AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value); AddUntilStep("skip overlay content becomes visible", () => fadeContainer().State == Visibility.Visible); @@ -144,7 +144,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestPerformExitNoOutro() { - CreateTest(null); + CreateTest(); AddStep("disable storyboard", () => LocalConfig.SetValue(OsuSetting.ShowStoryboard, false)); AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value); AddStep("exit via pause", () => Player.ExitViaPause()); diff --git a/osu.Game/Tests/Visual/PlayerTestScene.cs b/osu.Game/Tests/Visual/PlayerTestScene.cs index 521fd8f21a..e1714299b6 100644 --- a/osu.Game/Tests/Visual/PlayerTestScene.cs +++ b/osu.Game/Tests/Visual/PlayerTestScene.cs @@ -39,10 +39,10 @@ namespace osu.Game.Tests.Visual base.SetUpSteps(); if (!HasCustomSteps) - CreateTest(null); + CreateTest(); } - protected void CreateTest(Action action) + protected void CreateTest([CanBeNull] Action action = null) { if (action != null && !HasCustomSteps) throw new InvalidOperationException($"Cannot add custom test steps without {nameof(HasCustomSteps)} being set."); From 6bfd351dec8e4a1a38a8ab60e36580534b3fa6ad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Jun 2022 15:23:29 +0900 Subject: [PATCH 197/211] Add logging of `GameplayClockContainer` seeks --- osu.Game/Screens/Play/GameplayClockContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 6403943a53..9396b3311f 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Logging; using osu.Framework.Timing; namespace osu.Game.Screens.Play @@ -101,6 +102,8 @@ namespace osu.Game.Screens.Play /// The destination time to seek to. public virtual void Seek(double time) { + Logger.Log($"{nameof(GameplayClockContainer)} seeking to {time}"); + AdjustableSource.Seek(time); // Manually process to make sure the gameplay clock is correctly updated after a seek. From 21d31ee218ab60d886c20155e9b817f5dc44257e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Jun 2022 18:04:08 +0900 Subject: [PATCH 198/211] Ensure joined channels are actually joined to avoid unexpected tab order --- .../Visual/Online/TestSceneChatOverlay.cs | 71 +++++++++++-------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index ff2817c439..c57606d44b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -40,7 +40,6 @@ namespace osu.Game.Tests.Visual.Online private ChannelManager channelManager; private APIUser testUser; - private Channel testPMChannel; private Channel[] testChannels; private Channel testChannel1 => testChannels[0]; @@ -53,7 +52,6 @@ namespace osu.Game.Tests.Visual.Online public void SetUp() => Schedule(() => { testUser = new APIUser { Username = "test user", Id = 5071479 }; - testPMChannel = new Channel(testUser); testChannels = Enumerable.Range(1, 10).Select(createPublicChannel).ToArray(); Child = new DependencyProvidingContainer @@ -181,7 +179,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("Show overlay", () => chatOverlay.Show()); AddAssert("Listing is visible", () => listingIsVisible); - AddStep("Join channel 1", () => channelManager.JoinChannel(testChannel1)); + joinTestChannel(0); AddStep("Select channel 1", () => clickDrawable(getChannelListItem(testChannel1))); waitForChannel1Visible(); } @@ -203,12 +201,11 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestChannelCloseButton() { + var testPMChannel = new Channel(testUser); + AddStep("Show overlay", () => chatOverlay.Show()); - AddStep("Join PM and public channels", () => - { - channelManager.JoinChannel(testChannel1); - channelManager.JoinChannel(testPMChannel); - }); + joinTestChannel(0); + joinChannel(testPMChannel); AddStep("Select PM channel", () => clickDrawable(getChannelListItem(testPMChannel))); AddStep("Click close button", () => { @@ -229,7 +226,7 @@ namespace osu.Game.Tests.Visual.Online public void TestChatCommand() { AddStep("Show overlay", () => chatOverlay.Show()); - AddStep("Join channel 1", () => channelManager.JoinChannel(testChannel1)); + joinTestChannel(0); AddStep("Select channel 1", () => clickDrawable(getChannelListItem(testChannel1))); AddStep("Open chat with user", () => channelManager.PostCommand($"chat {testUser.Username}")); AddAssert("PM channel is selected", () => @@ -248,14 +245,16 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestMultiplayerChannelIsNotShown() { - Channel multiplayerChannel = null; + Channel multiplayerChannel; AddStep("Show overlay", () => chatOverlay.Show()); - AddStep("Join multiplayer channel", () => channelManager.JoinChannel(multiplayerChannel = new Channel(new APIUser()) + + joinChannel(multiplayerChannel = new Channel(new APIUser()) { Name = "#mp_1", Type = ChannelType.Multiplayer, - })); + }); + AddAssert("Channel is joined", () => channelManager.JoinedChannels.Contains(multiplayerChannel)); AddUntilStep("Channel not present in listing", () => !chatOverlay.ChildrenOfType() .Where(item => item.IsPresent) @@ -269,7 +268,7 @@ namespace osu.Game.Tests.Visual.Online Message message = null; AddStep("Show overlay", () => chatOverlay.Show()); - AddStep("Join channel 1", () => channelManager.JoinChannel(testChannel1)); + joinTestChannel(0); AddStep("Select channel 1", () => clickDrawable(getChannelListItem(testChannel1))); AddStep("Send message in channel 1", () => { @@ -291,8 +290,8 @@ namespace osu.Game.Tests.Visual.Online Message message = null; AddStep("Show overlay", () => chatOverlay.Show()); - AddStep("Join channel 1", () => channelManager.JoinChannel(testChannel1)); - AddStep("Join channel 2", () => channelManager.JoinChannel(testChannel2)); + joinTestChannel(0); + joinTestChannel(1); AddStep("Select channel 1", () => clickDrawable(getChannelListItem(testChannel1))); AddStep("Send message in channel 2", () => { @@ -314,8 +313,8 @@ namespace osu.Game.Tests.Visual.Online Message message = null; AddStep("Show overlay", () => chatOverlay.Show()); - AddStep("Join channel 1", () => channelManager.JoinChannel(testChannel1)); - AddStep("Join channel 2", () => channelManager.JoinChannel(testChannel2)); + joinTestChannel(0); + joinTestChannel(1); AddStep("Select channel 1", () => clickDrawable(getChannelListItem(testChannel1))); AddStep("Send message in channel 2", () => { @@ -337,7 +336,7 @@ namespace osu.Game.Tests.Visual.Online { Message message = null; - AddStep("Join channel 1", () => channelManager.JoinChannel(testChannel1)); + joinTestChannel(0); AddStep("Send message in channel 1", () => { testChannel1.AddNewMessages(message = new Message @@ -357,7 +356,7 @@ namespace osu.Game.Tests.Visual.Online { Message message = null; - AddStep("Join channel 1", () => channelManager.JoinChannel(testChannel1)); + joinTestChannel(0); AddStep("Send message in channel 1", () => { testChannel1.AddNewMessages(message = new Message @@ -378,7 +377,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("Show overlay", () => chatOverlay.Show()); AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox); - AddStep("Join channel 1", () => channelManager.JoinChannel(testChannel1)); + joinTestChannel(0); AddStep("Select channel 1", () => clickDrawable(getChannelListItem(testChannel1))); waitForChannel1Visible(); AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox); @@ -404,11 +403,11 @@ namespace osu.Game.Tests.Visual.Online chatOverlay.Show(); chatOverlay.SlowLoading = true; }); - AddStep("Join channel 1", () => channelManager.JoinChannel(testChannel1)); + joinTestChannel(0); AddStep("Select channel 1", () => clickDrawable(getChannelListItem(testChannel1))); AddUntilStep("Channel 1 loading", () => !channelIsVisible && chatOverlay.GetSlowLoadingChannel(testChannel1).LoadState == LoadState.Loading); - AddStep("Join channel 2", () => channelManager.JoinChannel(testChannel2)); + joinTestChannel(1); AddStep("Select channel 2", () => clickDrawable(getChannelListItem(testChannel2))); AddUntilStep("Channel 2 loading", () => !channelIsVisible && chatOverlay.GetSlowLoadingChannel(testChannel2).LoadState == LoadState.Loading); @@ -461,15 +460,13 @@ namespace osu.Game.Tests.Visual.Online Channel pmChannel1 = createPrivateChannel(); Channel pmChannel2 = createPrivateChannel(); - AddStep("Show overlay with channels", () => - { - channelManager.JoinChannel(testChannel1); - channelManager.JoinChannel(testChannel2); - channelManager.JoinChannel(pmChannel1); - channelManager.JoinChannel(pmChannel2); - channelManager.JoinChannel(announceChannel); - chatOverlay.Show(); - }); + joinTestChannel(0); + joinTestChannel(1); + joinChannel(pmChannel1); + joinChannel(pmChannel2); + joinChannel(announceChannel); + + AddStep("Show overlay", () => chatOverlay.Show()); AddStep("Select channel 1", () => clickDrawable(getChannelListItem(testChannel1))); waitForChannel1Visible(); @@ -490,6 +487,18 @@ namespace osu.Game.Tests.Visual.Online waitForChannel1Visible(); } + private void joinTestChannel(int i) + { + AddStep($"Join test channel {i}", () => channelManager.JoinChannel(testChannels[i])); + AddUntilStep("wait for join completed", () => testChannels[i].Joined.Value); + } + + private void joinChannel(Channel channel) + { + AddStep($"Join channel {channel}", () => channelManager.JoinChannel(channel)); + AddUntilStep("wait for join completed", () => channel.Joined.Value); + } + private void waitForChannel1Visible() => AddUntilStep("Channel 1 is visible", () => channelIsVisible && currentDrawableChannel?.Channel == testChannel1); From ed1b809f54b22116ee6f04738f85d11a22ff8457 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Jun 2022 18:11:30 +0900 Subject: [PATCH 199/211] Add missing request handling to actually join PM channels --- osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index c57606d44b..d2d9b9a9e5 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -78,6 +78,14 @@ namespace osu.Game.Tests.Visual.Online { switch (req) { + case CreateChannelRequest createRequest: + createRequest.TriggerSuccess(new APIChatChannel + { + ChannelID = ((int)createRequest.Channel.Id), + RecentMessages = new List() + }); + return true; + case GetUpdatesRequest getUpdates: getUpdates.TriggerFailure(new WebException()); return true; From 975ba83838a63f97e7942f3958ad9d3dd50d80d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Jun 2022 18:19:43 +0900 Subject: [PATCH 200/211] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 8f4a102cce..f884ce0eff 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b9033f1bb9..dbfdf0fde8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index a1e4cf3ba0..11c177dbae 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From c282e193169431e8c7bbe1bf26ad77b6c197396b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Jun 2022 16:29:19 +0900 Subject: [PATCH 201/211] Update language initialisation in line with framework `LocalisationManager` changes --- osu.Game/OsuGame.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index ef42522f9d..bd0a2680ae 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -24,6 +24,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Framework.Screens; using osu.Framework.Threading; @@ -686,27 +687,29 @@ namespace osu.Game { base.LoadComplete(); - foreach (var language in Enum.GetValues(typeof(Language)).OfType()) + var languages = Enum.GetValues(typeof(Language)).OfType(); + + var mappings = languages.Select(language => { #if DEBUG if (language == Language.debug) - { - Localisation.AddLanguage(Language.debug.ToString(), new DebugLocalisationStore()); - continue; - } + return new LocaleMapping("debug", new DebugLocalisationStore()); #endif string cultureCode = language.ToCultureCode(); try { - Localisation.AddLanguage(cultureCode, new ResourceManagerLocalisationStore(cultureCode)); + return new LocaleMapping(new ResourceManagerLocalisationStore(cultureCode)); } catch (Exception ex) { Logger.Error(ex, $"Could not load localisations for language \"{cultureCode}\""); + return null; } - } + }).Where(m => m != null); + + Localisation.AddLocaleMappings(mappings); // The next time this is updated is in UpdateAfterChildren, which occurs too late and results // in the cursor being shown for a few frames during the intro. From 7c9c499e19d033ef0b352df7930668c67ddd3017 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 28 Jun 2022 19:21:41 +0900 Subject: [PATCH 202/211] Update resources (translation updates) --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index f884ce0eff..2ef3bb2dd1 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index dbfdf0fde8..ab690b22a6 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 11c177dbae..a84fc40a45 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + From 2269f1046ed34d4dad8542013a322290ebda5458 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Tue, 28 Jun 2022 20:59:03 +0800 Subject: [PATCH 203/211] Remove the nullable disable annotations. --- osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs | 2 -- osu.Game/Migrations/20171019041408_InitialCreate.cs | 2 -- .../Migrations/20171025071459_AddMissingIndexRules.Designer.cs | 2 -- osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs | 2 -- ...0171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs | 2 -- .../20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs | 2 -- .../20171209034410_AddRulesetInfoShortName.Designer.cs | 2 -- osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.cs | 2 -- osu.Game/Migrations/20180125143340_Settings.Designer.cs | 2 -- osu.Game/Migrations/20180125143340_Settings.cs | 2 -- osu.Game/Migrations/20180131154205_AddMuteBinding.cs | 2 -- osu.Game/Migrations/20180219060912_AddSkins.Designer.cs | 2 -- osu.Game/Migrations/20180219060912_AddSkins.cs | 2 -- .../20180529055154_RemoveUniqueHashConstraints.Designer.cs | 2 -- .../Migrations/20180529055154_RemoveUniqueHashConstraints.cs | 2 -- .../20180621044111_UpdateTaikoDefaultBindings.Designer.cs | 2 -- .../Migrations/20180621044111_UpdateTaikoDefaultBindings.cs | 2 -- .../Migrations/20180628011956_RemoveNegativeSetIDs.Designer.cs | 2 -- osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.cs | 2 -- osu.Game/Migrations/20180913080842_AddRankStatus.Designer.cs | 2 -- osu.Game/Migrations/20180913080842_AddRankStatus.cs | 2 -- osu.Game/Migrations/20181007180454_StandardizePaths.Designer.cs | 2 -- osu.Game/Migrations/20181007180454_StandardizePaths.cs | 2 -- osu.Game/Migrations/20181128100659_AddSkinInfoHash.Designer.cs | 2 -- osu.Game/Migrations/20181128100659_AddSkinInfoHash.cs | 2 -- .../Migrations/20181130113755_AddScoreInfoTables.Designer.cs | 2 -- osu.Game/Migrations/20181130113755_AddScoreInfoTables.cs | 2 -- osu.Game/Migrations/20190225062029_AddUserIDColumn.Designer.cs | 2 -- osu.Game/Migrations/20190225062029_AddUserIDColumn.cs | 2 -- osu.Game/Migrations/20190525060824_SkinSettings.Designer.cs | 2 -- osu.Game/Migrations/20190525060824_SkinSettings.cs | 2 -- .../20190605091246_AddDateAddedColumnToBeatmapSet.Designer.cs | 2 -- .../Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.cs | 2 -- .../20190708070844_AddBPMAndLengthColumns.Designer.cs | 2 -- osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.cs | 2 -- osu.Game/Migrations/20190913104727_AddBeatmapVideo.Designer.cs | 2 -- osu.Game/Migrations/20190913104727_AddBeatmapVideo.cs | 2 -- .../Migrations/20200302094919_RefreshVolumeBindings.Designer.cs | 2 -- osu.Game/Migrations/20200302094919_RefreshVolumeBindings.cs | 2 -- .../Migrations/20201019224408_AddEpilepsyWarning.Designer.cs | 2 -- osu.Game/Migrations/20201019224408_AddEpilepsyWarning.cs | 2 -- .../20210412045700_RefreshVolumeBindingsAgain.Designer.cs | 2 -- .../Migrations/20210412045700_RefreshVolumeBindingsAgain.cs | 2 -- .../20210511060743_AddSkinInstantiationInfo.Designer.cs | 2 -- osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.cs | 2 -- .../20210514062639_AddAuthorIdToBeatmapMetadata.Designer.cs | 2 -- .../Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.cs | 2 -- .../Migrations/20210824185035_AddCountdownSettings.Designer.cs | 2 -- osu.Game/Migrations/20210824185035_AddCountdownSettings.cs | 2 -- .../20210912144011_AddSamplesMatchPlaybackRate.Designer.cs | 2 -- .../Migrations/20210912144011_AddSamplesMatchPlaybackRate.cs | 2 -- osu.Game/Migrations/20211020081609_ResetSkinHashes.cs | 2 -- osu.Game/Migrations/OsuDbContextModelSnapshot.cs | 2 -- 53 files changed, 106 deletions(-) diff --git a/osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs b/osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs index 7104245d9e..c751530bf4 100644 --- a/osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs +++ b/osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs @@ -1,7 +1,5 @@ // using Microsoft.EntityFrameworkCore; - -#nullable disable using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20171019041408_InitialCreate.cs b/osu.Game/Migrations/20171019041408_InitialCreate.cs index f1c7c94638..08ab64fd08 100644 --- a/osu.Game/Migrations/20171019041408_InitialCreate.cs +++ b/osu.Game/Migrations/20171019041408_InitialCreate.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20171025071459_AddMissingIndexRules.Designer.cs b/osu.Game/Migrations/20171025071459_AddMissingIndexRules.Designer.cs index b464c15ce2..4cd234f2ef 100644 --- a/osu.Game/Migrations/20171025071459_AddMissingIndexRules.Designer.cs +++ b/osu.Game/Migrations/20171025071459_AddMissingIndexRules.Designer.cs @@ -1,7 +1,5 @@ // using Microsoft.EntityFrameworkCore; - -#nullable disable using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs b/osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs index 1d0164a1d9..4ec3952941 100644 --- a/osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs +++ b/osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs b/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs index 53e8b887d8..006acf12cd 100644 --- a/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs +++ b/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs @@ -1,7 +1,5 @@ // using Microsoft.EntityFrameworkCore; - -#nullable disable using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs b/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs index 765a6a5b58..6aba12f86f 100644 --- a/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs +++ b/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.Designer.cs b/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.Designer.cs index 4da20141bc..fc2496bc24 100644 --- a/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.Designer.cs +++ b/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.Designer.cs @@ -1,7 +1,5 @@ // using Microsoft.EntityFrameworkCore; - -#nullable disable using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.cs b/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.cs index 3379efa68e..5688455f79 100644 --- a/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.cs +++ b/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20180125143340_Settings.Designer.cs b/osu.Game/Migrations/20180125143340_Settings.Designer.cs index 68054d6404..4bb599eec1 100644 --- a/osu.Game/Migrations/20180125143340_Settings.Designer.cs +++ b/osu.Game/Migrations/20180125143340_Settings.Designer.cs @@ -1,7 +1,5 @@ // using Microsoft.EntityFrameworkCore; - -#nullable disable using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20180125143340_Settings.cs b/osu.Game/Migrations/20180125143340_Settings.cs index 8f7d0a6ed3..1feb37531f 100644 --- a/osu.Game/Migrations/20180125143340_Settings.cs +++ b/osu.Game/Migrations/20180125143340_Settings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20180131154205_AddMuteBinding.cs b/osu.Game/Migrations/20180131154205_AddMuteBinding.cs index 3e97e78e61..8646d1d76b 100644 --- a/osu.Game/Migrations/20180131154205_AddMuteBinding.cs +++ b/osu.Game/Migrations/20180131154205_AddMuteBinding.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Infrastructure; using osu.Game.Database; diff --git a/osu.Game/Migrations/20180219060912_AddSkins.Designer.cs b/osu.Game/Migrations/20180219060912_AddSkins.Designer.cs index 7d95a702b8..cdc4ef2e66 100644 --- a/osu.Game/Migrations/20180219060912_AddSkins.Designer.cs +++ b/osu.Game/Migrations/20180219060912_AddSkins.Designer.cs @@ -1,7 +1,5 @@ // using Microsoft.EntityFrameworkCore; - -#nullable disable using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20180219060912_AddSkins.cs b/osu.Game/Migrations/20180219060912_AddSkins.cs index df9d267a14..319748bed6 100644 --- a/osu.Game/Migrations/20180219060912_AddSkins.cs +++ b/osu.Game/Migrations/20180219060912_AddSkins.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.Designer.cs b/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.Designer.cs index 7e490c7833..f28408bfb3 100644 --- a/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.Designer.cs +++ b/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.Designer.cs @@ -1,7 +1,5 @@ // using Microsoft.EntityFrameworkCore; - -#nullable disable using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.cs b/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.cs index 62c341b0c6..91eabe8868 100644 --- a/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.cs +++ b/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.Designer.cs b/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.Designer.cs index a103cdad20..aaa11e88b6 100644 --- a/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.Designer.cs +++ b/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.cs b/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.cs index b08fa7a899..d888ccd5a2 100644 --- a/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.cs +++ b/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.Designer.cs b/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.Designer.cs index 5b1734554a..7eeacd56d7 100644 --- a/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.Designer.cs +++ b/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.cs b/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.cs index 4ba0a4d0e6..fdea636ac6 100644 --- a/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.cs +++ b/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20180913080842_AddRankStatus.Designer.cs b/osu.Game/Migrations/20180913080842_AddRankStatus.Designer.cs index ceef5b6948..5ab43da046 100644 --- a/osu.Game/Migrations/20180913080842_AddRankStatus.Designer.cs +++ b/osu.Game/Migrations/20180913080842_AddRankStatus.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20180913080842_AddRankStatus.cs b/osu.Game/Migrations/20180913080842_AddRankStatus.cs index ec82925b03..bb147dff84 100644 --- a/osu.Game/Migrations/20180913080842_AddRankStatus.cs +++ b/osu.Game/Migrations/20180913080842_AddRankStatus.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20181007180454_StandardizePaths.Designer.cs b/osu.Game/Migrations/20181007180454_StandardizePaths.Designer.cs index d1185ef186..b387a45ecf 100644 --- a/osu.Game/Migrations/20181007180454_StandardizePaths.Designer.cs +++ b/osu.Game/Migrations/20181007180454_StandardizePaths.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20181007180454_StandardizePaths.cs b/osu.Game/Migrations/20181007180454_StandardizePaths.cs index f9323c0b9b..30f27043a0 100644 --- a/osu.Game/Migrations/20181007180454_StandardizePaths.cs +++ b/osu.Game/Migrations/20181007180454_StandardizePaths.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20181128100659_AddSkinInfoHash.Designer.cs b/osu.Game/Migrations/20181128100659_AddSkinInfoHash.Designer.cs index 0797090c7b..120674671a 100644 --- a/osu.Game/Migrations/20181128100659_AddSkinInfoHash.Designer.cs +++ b/osu.Game/Migrations/20181128100659_AddSkinInfoHash.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20181128100659_AddSkinInfoHash.cs b/osu.Game/Migrations/20181128100659_AddSkinInfoHash.cs index 43689f2a3c..ee825a1e9c 100644 --- a/osu.Game/Migrations/20181128100659_AddSkinInfoHash.cs +++ b/osu.Game/Migrations/20181128100659_AddSkinInfoHash.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20181130113755_AddScoreInfoTables.Designer.cs b/osu.Game/Migrations/20181130113755_AddScoreInfoTables.Designer.cs index 3b70ad8d45..eee53182ce 100644 --- a/osu.Game/Migrations/20181130113755_AddScoreInfoTables.Designer.cs +++ b/osu.Game/Migrations/20181130113755_AddScoreInfoTables.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20181130113755_AddScoreInfoTables.cs b/osu.Game/Migrations/20181130113755_AddScoreInfoTables.cs index f52edacc7f..58980132f3 100644 --- a/osu.Game/Migrations/20181130113755_AddScoreInfoTables.cs +++ b/osu.Game/Migrations/20181130113755_AddScoreInfoTables.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20190225062029_AddUserIDColumn.Designer.cs b/osu.Game/Migrations/20190225062029_AddUserIDColumn.Designer.cs index 51b63bd9eb..8e1e3a59f3 100644 --- a/osu.Game/Migrations/20190225062029_AddUserIDColumn.Designer.cs +++ b/osu.Game/Migrations/20190225062029_AddUserIDColumn.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20190225062029_AddUserIDColumn.cs b/osu.Game/Migrations/20190225062029_AddUserIDColumn.cs index 00d807d5c4..f2eef600dc 100644 --- a/osu.Game/Migrations/20190225062029_AddUserIDColumn.cs +++ b/osu.Game/Migrations/20190225062029_AddUserIDColumn.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20190525060824_SkinSettings.Designer.cs b/osu.Game/Migrations/20190525060824_SkinSettings.Designer.cs index 9d6515e5c6..348c42adb9 100644 --- a/osu.Game/Migrations/20190525060824_SkinSettings.Designer.cs +++ b/osu.Game/Migrations/20190525060824_SkinSettings.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20190525060824_SkinSettings.cs b/osu.Game/Migrations/20190525060824_SkinSettings.cs index 463d4fe1ad..7779b55bb7 100644 --- a/osu.Game/Migrations/20190525060824_SkinSettings.cs +++ b/osu.Game/Migrations/20190525060824_SkinSettings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.Designer.cs b/osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.Designer.cs index 1bc2e76ae5..9477369aa0 100644 --- a/osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.Designer.cs +++ b/osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.cs b/osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.cs index 61925a4cb4..0620a0624f 100644 --- a/osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.cs +++ b/osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.Designer.cs b/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.Designer.cs index c51b8739bc..c5fcc16f84 100644 --- a/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.Designer.cs +++ b/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.cs b/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.cs index 19a2464157..f8ce354aa1 100644 --- a/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.cs +++ b/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20190913104727_AddBeatmapVideo.Designer.cs b/osu.Game/Migrations/20190913104727_AddBeatmapVideo.Designer.cs index 95583e7587..826233a2b0 100644 --- a/osu.Game/Migrations/20190913104727_AddBeatmapVideo.Designer.cs +++ b/osu.Game/Migrations/20190913104727_AddBeatmapVideo.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20190913104727_AddBeatmapVideo.cs b/osu.Game/Migrations/20190913104727_AddBeatmapVideo.cs index c1208e0bf1..af82b4db20 100644 --- a/osu.Game/Migrations/20190913104727_AddBeatmapVideo.cs +++ b/osu.Game/Migrations/20190913104727_AddBeatmapVideo.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.Designer.cs b/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.Designer.cs index 3c7de0602b..22316b0380 100644 --- a/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.Designer.cs +++ b/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.cs b/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.cs index 73cfb1725b..3d2ddbf6fc 100644 --- a/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.cs +++ b/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20201019224408_AddEpilepsyWarning.Designer.cs b/osu.Game/Migrations/20201019224408_AddEpilepsyWarning.Designer.cs index 24acc3195f..1c05de832e 100644 --- a/osu.Game/Migrations/20201019224408_AddEpilepsyWarning.Designer.cs +++ b/osu.Game/Migrations/20201019224408_AddEpilepsyWarning.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20201019224408_AddEpilepsyWarning.cs b/osu.Game/Migrations/20201019224408_AddEpilepsyWarning.cs index eaca8785f9..58a35a7bf3 100644 --- a/osu.Game/Migrations/20201019224408_AddEpilepsyWarning.cs +++ b/osu.Game/Migrations/20201019224408_AddEpilepsyWarning.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.Designer.cs b/osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.Designer.cs index 704af354c9..2c100d39b9 100644 --- a/osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.Designer.cs +++ b/osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.cs b/osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.cs index 7772c0e86b..4d3941dd20 100644 --- a/osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.cs +++ b/osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.Designer.cs b/osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.Designer.cs index 097bd6a244..b808c648da 100644 --- a/osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.Designer.cs +++ b/osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.cs b/osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.cs index 1cc9ab6120..887635fa85 100644 --- a/osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.cs +++ b/osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.Designer.cs b/osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.Designer.cs index ca9502422b..89bab3a0fa 100644 --- a/osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.Designer.cs +++ b/osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.cs b/osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.cs index 82c5b27769..7b579e27b9 100644 --- a/osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.cs +++ b/osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20210824185035_AddCountdownSettings.Designer.cs b/osu.Game/Migrations/20210824185035_AddCountdownSettings.Designer.cs index 2a4e370649..afeb42130d 100644 --- a/osu.Game/Migrations/20210824185035_AddCountdownSettings.Designer.cs +++ b/osu.Game/Migrations/20210824185035_AddCountdownSettings.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20210824185035_AddCountdownSettings.cs b/osu.Game/Migrations/20210824185035_AddCountdownSettings.cs index dd6fa23387..d1b09e2c1d 100644 --- a/osu.Game/Migrations/20210824185035_AddCountdownSettings.cs +++ b/osu.Game/Migrations/20210824185035_AddCountdownSettings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.Designer.cs b/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.Designer.cs index 9e09f2c69e..6e53d7fae0 100644 --- a/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.Designer.cs +++ b/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.Designer.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; diff --git a/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.cs b/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.cs index 0598a41f09..f6fc1f4420 100644 --- a/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.cs +++ b/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Migrations; namespace osu.Game.Migrations diff --git a/osu.Game/Migrations/20211020081609_ResetSkinHashes.cs b/osu.Game/Migrations/20211020081609_ResetSkinHashes.cs index 0f7a2a5702..6d53c019ec 100644 --- a/osu.Game/Migrations/20211020081609_ResetSkinHashes.cs +++ b/osu.Game/Migrations/20211020081609_ResetSkinHashes.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using osu.Game.Database; diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index 7e38889fa6..036c26cb0a 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -1,7 +1,5 @@ // using System; - -#nullable disable using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; From de7f2a0bba6953b486689427198b0b1fd2804a30 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Tue, 28 Jun 2022 20:56:02 +0800 Subject: [PATCH 204/211] Remove the nullable disable annotation in the localisation. --- osu.Game/Localisation/AudioSettingsStrings.cs | 2 -- osu.Game/Localisation/BeatmapOffsetControlStrings.cs | 2 -- osu.Game/Localisation/BindingSettingsStrings.cs | 2 -- osu.Game/Localisation/ButtonSystemStrings.cs | 2 -- osu.Game/Localisation/ChatStrings.cs | 2 -- osu.Game/Localisation/CommonStrings.cs | 2 -- osu.Game/Localisation/DebugLocalisationStore.cs | 2 -- osu.Game/Localisation/DebugSettingsStrings.cs | 2 -- osu.Game/Localisation/DifficultyMultiplierDisplayStrings.cs | 2 -- .../FirstRunOverlayImportFromStableScreenStrings.cs | 2 -- osu.Game/Localisation/FirstRunSetupBeatmapScreenStrings.cs | 2 -- osu.Game/Localisation/FirstRunSetupOverlayStrings.cs | 2 -- osu.Game/Localisation/GameplaySettingsStrings.cs | 2 -- osu.Game/Localisation/GeneralSettingsStrings.cs | 2 -- osu.Game/Localisation/GlobalActionKeyBindingStrings.cs | 2 -- osu.Game/Localisation/GraphicsSettingsStrings.cs | 2 -- osu.Game/Localisation/InputSettingsStrings.cs | 2 -- osu.Game/Localisation/JoystickSettingsStrings.cs | 2 -- osu.Game/Localisation/Language.cs | 2 -- osu.Game/Localisation/LayoutSettingsStrings.cs | 2 -- osu.Game/Localisation/LeaderboardStrings.cs | 2 -- osu.Game/Localisation/MaintenanceSettingsStrings.cs | 2 -- osu.Game/Localisation/ModSelectOverlayStrings.cs | 2 -- osu.Game/Localisation/MouseSettingsStrings.cs | 2 -- osu.Game/Localisation/MultiplayerTeamResultsScreenStrings.cs | 2 -- osu.Game/Localisation/NamedOverlayComponentStrings.cs | 2 -- osu.Game/Localisation/NotificationsStrings.cs | 2 -- osu.Game/Localisation/NowPlayingStrings.cs | 2 -- osu.Game/Localisation/OnlineSettingsStrings.cs | 2 -- osu.Game/Localisation/RulesetSettingsStrings.cs | 2 -- osu.Game/Localisation/SettingsStrings.cs | 2 -- osu.Game/Localisation/SkinSettingsStrings.cs | 2 -- osu.Game/Localisation/TabletSettingsStrings.cs | 2 -- osu.Game/Localisation/ToastStrings.cs | 2 -- osu.Game/Localisation/UserInterfaceStrings.cs | 2 -- 35 files changed, 70 deletions(-) diff --git a/osu.Game/Localisation/AudioSettingsStrings.cs b/osu.Game/Localisation/AudioSettingsStrings.cs index 0dc95da2f4..0f0f560df9 100644 --- a/osu.Game/Localisation/AudioSettingsStrings.cs +++ b/osu.Game/Localisation/AudioSettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/BeatmapOffsetControlStrings.cs b/osu.Game/Localisation/BeatmapOffsetControlStrings.cs index 417cf335e0..632a1ad0ea 100644 --- a/osu.Game/Localisation/BeatmapOffsetControlStrings.cs +++ b/osu.Game/Localisation/BeatmapOffsetControlStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/BindingSettingsStrings.cs b/osu.Game/Localisation/BindingSettingsStrings.cs index 39b5ac0d21..ad4a650a1f 100644 --- a/osu.Game/Localisation/BindingSettingsStrings.cs +++ b/osu.Game/Localisation/BindingSettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/ButtonSystemStrings.cs b/osu.Game/Localisation/ButtonSystemStrings.cs index c71a99711b..ba4abf63a6 100644 --- a/osu.Game/Localisation/ButtonSystemStrings.cs +++ b/osu.Game/Localisation/ButtonSystemStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/ChatStrings.cs b/osu.Game/Localisation/ChatStrings.cs index b07ed18f7b..7bd284a94e 100644 --- a/osu.Game/Localisation/ChatStrings.cs +++ b/osu.Game/Localisation/ChatStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 39dc7cf518..1ee562e122 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/DebugLocalisationStore.cs b/osu.Game/Localisation/DebugLocalisationStore.cs index 83ae4581a8..2b114b1bd8 100644 --- a/osu.Game/Localisation/DebugLocalisationStore.cs +++ b/osu.Game/Localisation/DebugLocalisationStore.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; using System.Globalization; diff --git a/osu.Game/Localisation/DebugSettingsStrings.cs b/osu.Game/Localisation/DebugSettingsStrings.cs index e6de4ddee9..74b2c8d892 100644 --- a/osu.Game/Localisation/DebugSettingsStrings.cs +++ b/osu.Game/Localisation/DebugSettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/DifficultyMultiplierDisplayStrings.cs b/osu.Game/Localisation/DifficultyMultiplierDisplayStrings.cs index 4bcbdcff7b..952ca22678 100644 --- a/osu.Game/Localisation/DifficultyMultiplierDisplayStrings.cs +++ b/osu.Game/Localisation/DifficultyMultiplierDisplayStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/FirstRunOverlayImportFromStableScreenStrings.cs b/osu.Game/Localisation/FirstRunOverlayImportFromStableScreenStrings.cs index 38f5860cc5..deac7d8628 100644 --- a/osu.Game/Localisation/FirstRunOverlayImportFromStableScreenStrings.cs +++ b/osu.Game/Localisation/FirstRunOverlayImportFromStableScreenStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/FirstRunSetupBeatmapScreenStrings.cs b/osu.Game/Localisation/FirstRunSetupBeatmapScreenStrings.cs index 331a8c6764..3a7fe4bb12 100644 --- a/osu.Game/Localisation/FirstRunSetupBeatmapScreenStrings.cs +++ b/osu.Game/Localisation/FirstRunSetupBeatmapScreenStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs b/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs index 0c73d7a85b..91b427e2ca 100644 --- a/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs +++ b/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/GameplaySettingsStrings.cs b/osu.Game/Localisation/GameplaySettingsStrings.cs index 1719b7d6e8..8a0f773551 100644 --- a/osu.Game/Localisation/GameplaySettingsStrings.cs +++ b/osu.Game/Localisation/GameplaySettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/GeneralSettingsStrings.cs b/osu.Game/Localisation/GeneralSettingsStrings.cs index 8cf26a930d..2aa91f5245 100644 --- a/osu.Game/Localisation/GeneralSettingsStrings.cs +++ b/osu.Game/Localisation/GeneralSettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index d45fba6f17..82d03dbb5b 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/GraphicsSettingsStrings.cs b/osu.Game/Localisation/GraphicsSettingsStrings.cs index a73d67067e..38355d9041 100644 --- a/osu.Game/Localisation/GraphicsSettingsStrings.cs +++ b/osu.Game/Localisation/GraphicsSettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/InputSettingsStrings.cs b/osu.Game/Localisation/InputSettingsStrings.cs index a16dcd998a..e46b4cecf3 100644 --- a/osu.Game/Localisation/InputSettingsStrings.cs +++ b/osu.Game/Localisation/InputSettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/JoystickSettingsStrings.cs b/osu.Game/Localisation/JoystickSettingsStrings.cs index efda1afd48..976ec1adde 100644 --- a/osu.Game/Localisation/JoystickSettingsStrings.cs +++ b/osu.Game/Localisation/JoystickSettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/Language.cs b/osu.Game/Localisation/Language.cs index f9094b9540..c13a1a10cb 100644 --- a/osu.Game/Localisation/Language.cs +++ b/osu.Game/Localisation/Language.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.ComponentModel; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/LayoutSettingsStrings.cs b/osu.Game/Localisation/LayoutSettingsStrings.cs index 1a0b015050..b4326b8e39 100644 --- a/osu.Game/Localisation/LayoutSettingsStrings.cs +++ b/osu.Game/Localisation/LayoutSettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/LeaderboardStrings.cs b/osu.Game/Localisation/LeaderboardStrings.cs index 14bc5b7af4..8e53f8e88c 100644 --- a/osu.Game/Localisation/LeaderboardStrings.cs +++ b/osu.Game/Localisation/LeaderboardStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/MaintenanceSettingsStrings.cs b/osu.Game/Localisation/MaintenanceSettingsStrings.cs index 4cb514feb0..7a04bcd1ca 100644 --- a/osu.Game/Localisation/MaintenanceSettingsStrings.cs +++ b/osu.Game/Localisation/MaintenanceSettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/ModSelectOverlayStrings.cs b/osu.Game/Localisation/ModSelectOverlayStrings.cs index 3d99075922..e9af7147e3 100644 --- a/osu.Game/Localisation/ModSelectOverlayStrings.cs +++ b/osu.Game/Localisation/ModSelectOverlayStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/MouseSettingsStrings.cs b/osu.Game/Localisation/MouseSettingsStrings.cs index 563d6f7637..fd7225ad2e 100644 --- a/osu.Game/Localisation/MouseSettingsStrings.cs +++ b/osu.Game/Localisation/MouseSettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/MultiplayerTeamResultsScreenStrings.cs b/osu.Game/Localisation/MultiplayerTeamResultsScreenStrings.cs index 956d5195e7..92cedce3e0 100644 --- a/osu.Game/Localisation/MultiplayerTeamResultsScreenStrings.cs +++ b/osu.Game/Localisation/MultiplayerTeamResultsScreenStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/NamedOverlayComponentStrings.cs b/osu.Game/Localisation/NamedOverlayComponentStrings.cs index f6a50460dc..475bea2a4a 100644 --- a/osu.Game/Localisation/NamedOverlayComponentStrings.cs +++ b/osu.Game/Localisation/NamedOverlayComponentStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index c60e5d3415..382e0d81f4 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/NowPlayingStrings.cs b/osu.Game/Localisation/NowPlayingStrings.cs index 75d9b28ea6..f334637338 100644 --- a/osu.Game/Localisation/NowPlayingStrings.cs +++ b/osu.Game/Localisation/NowPlayingStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/OnlineSettingsStrings.cs b/osu.Game/Localisation/OnlineSettingsStrings.cs index ebb21afeb7..6862f4ac2c 100644 --- a/osu.Game/Localisation/OnlineSettingsStrings.cs +++ b/osu.Game/Localisation/OnlineSettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/RulesetSettingsStrings.cs b/osu.Game/Localisation/RulesetSettingsStrings.cs index 08901a641e..a356c9e20b 100644 --- a/osu.Game/Localisation/RulesetSettingsStrings.cs +++ b/osu.Game/Localisation/RulesetSettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/SettingsStrings.cs b/osu.Game/Localisation/SettingsStrings.cs index 5dcab39e10..aa2e2740eb 100644 --- a/osu.Game/Localisation/SettingsStrings.cs +++ b/osu.Game/Localisation/SettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/SkinSettingsStrings.cs b/osu.Game/Localisation/SkinSettingsStrings.cs index 42b72fdbb8..81035c5a5e 100644 --- a/osu.Game/Localisation/SkinSettingsStrings.cs +++ b/osu.Game/Localisation/SkinSettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/TabletSettingsStrings.cs b/osu.Game/Localisation/TabletSettingsStrings.cs index 8d2bc21652..d62d348df9 100644 --- a/osu.Game/Localisation/TabletSettingsStrings.cs +++ b/osu.Game/Localisation/TabletSettingsStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/ToastStrings.cs b/osu.Game/Localisation/ToastStrings.cs index 00a0031293..52e75425bf 100644 --- a/osu.Game/Localisation/ToastStrings.cs +++ b/osu.Game/Localisation/ToastStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index a007f760d8..a090b8c14c 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Localisation; namespace osu.Game.Localisation From aacded0ecf2aaecaac5ea48e7fff00a9052064ca Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 28 Jun 2022 07:33:05 -0700 Subject: [PATCH 205/211] Fix difficulty adjust settings having more padding on sliders --- osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs index a42d4a049a..599e81f2b8 100644 --- a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs +++ b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Settings; namespace osu.Game.Rulesets.Mods @@ -103,9 +104,9 @@ namespace osu.Game.Rulesets.Mods { InternalChildren = new Drawable[] { - new SettingsSlider + new OsuSliderBar { - ShowsDefaultIndicator = false, + RelativeSizeAxes = Axes.X, Current = currentNumber, KeyboardStep = 0.1f, } From f07107aba9e3812e8ae94a09fac8a00374da5e42 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 28 Jun 2022 08:38:15 -0700 Subject: [PATCH 206/211] Fix failing diff adjust slider tests --- .../UserInterface/TestSceneModDifficultyAdjustSettings.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs index 72e503dc33..9641e6b1bf 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; @@ -246,7 +247,7 @@ namespace osu.Game.Tests.Visual.UserInterface { AddStep($"Set {name} slider to {value}", () => this.ChildrenOfType().First(c => c.LabelText == name) - .ChildrenOfType>().First().Current.Value = value); + .ChildrenOfType>().First().Current.Value = value); } private void checkBindableAtValue(string name, float? expectedValue) @@ -260,7 +261,7 @@ namespace osu.Game.Tests.Visual.UserInterface { AddAssert($"Slider {name} at {expectedValue}", () => this.ChildrenOfType().First(c => c.LabelText == name) - .ChildrenOfType>().First().Current.Value == expectedValue); + .ChildrenOfType>().First().Current.Value == expectedValue); } private void setBeatmapWithDifficultyParameters(float value) From d07c2a64b934303314fec10956ec437a464cc6a2 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 28 Jun 2022 08:39:09 -0700 Subject: [PATCH 207/211] Remove unused using --- .../Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs index 9641e6b1bf..181f46a996 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs @@ -14,7 +14,6 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; -using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; using osuTK; From 978a80dd6f2b6bbc615ca520eac176da6e58ae88 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Jun 2022 01:52:50 +0900 Subject: [PATCH 208/211] Change closure elimination to hint Pretty noisy as a suggestion, and can fire incorrectly quite a lot (aka `Schedule()`). --- osu.sln.DotSettings | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index a55b3b5074..0794095854 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -98,6 +98,7 @@ WARNING HINT DO_NOT_SHOW + HINT HINT HINT ERROR From 36e71d39f2bbdd119148659e5682683f3bf07943 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 28 Jun 2022 09:54:18 -0700 Subject: [PATCH 209/211] Fix one more mod settings test --- .../Visual/UserInterface/TestSceneModSelectOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 006707d064..4de70f6f9e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -230,7 +230,7 @@ namespace osu.Game.Tests.Visual.UserInterface createScreen(); AddStep("select diff adjust", () => SelectedMods.Value = new Mod[] { new OsuModDifficultyAdjust() }); - AddStep("set setting", () => modSelectOverlay.ChildrenOfType>().First().Current.Value = 8); + AddStep("set setting", () => modSelectOverlay.ChildrenOfType>().First().Current.Value = 8); AddAssert("ensure setting is propagated", () => SelectedMods.Value.OfType().Single().CircleSize.Value == 8); From ecdb30d215f57df0cbb608acafe676b25b5b25a4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Jun 2022 02:28:21 +0900 Subject: [PATCH 210/211] Fix one more case of collection modification during enumeration https://sentry.ppy.sh/share/issue/a61c27b2a63a4a6aa80e75873f9d87ca/ --- osu.Game/Database/RealmAccess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 089a783177..cb34a92702 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -132,7 +132,7 @@ namespace osu.Game.Database Logger.Log(@$"Opened realm ""{updateRealm.Config.DatabasePath}"" at version {updateRealm.Config.SchemaVersion}"); // Resubscribe any subscriptions - foreach (var action in customSubscriptionsResetMap.Keys) + foreach (var action in customSubscriptionsResetMap.Keys.ToArray()) registerSubscription(action); } From 3a00131606d11382b1ca264be4803cc7fb300ae3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 29 Jun 2022 13:51:48 +0900 Subject: [PATCH 211/211] Bump fastlane --- Gemfile.lock | 60 ++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ddab497657..cae682ec2b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,20 +8,20 @@ GEM artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.2.0) - aws-partitions (1.570.0) - aws-sdk-core (3.130.0) + aws-partitions (1.601.0) + aws-sdk-core (3.131.2) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.525.0) aws-sigv4 (~> 1.1) - jmespath (~> 1.0) - aws-sdk-kms (1.55.0) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.57.0) aws-sdk-core (~> 3, >= 3.127.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.113.0) + aws-sdk-s3 (1.114.0) aws-sdk-core (~> 3, >= 3.127.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.4) - aws-sigv4 (1.4.0) + aws-sigv4 (1.5.0) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) claide (1.1.0) @@ -36,7 +36,7 @@ GEM unf (>= 0.0.5, < 1.0.0) dotenv (2.7.6) emoji_regex (3.2.3) - excon (0.92.1) + excon (0.92.3) faraday (1.10.0) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -56,8 +56,8 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.0.3) - multipart-post (>= 1.2, < 3) + faraday-multipart (1.0.4) + multipart-post (~> 2) faraday-net_http (1.0.1) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) @@ -66,7 +66,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.2.6) - fastlane (2.205.1) + fastlane (2.206.2) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -110,9 +110,9 @@ GEM souyuz (= 0.11.1) fastlane-plugin-xamarin (0.6.3) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.16.0) - google-apis-core (>= 0.4, < 2.a) - google-apis-core (0.4.2) + google-apis-androidpublisher_v3 (0.23.0) + google-apis-core (>= 0.6, < 2.a) + google-apis-core (0.6.0) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -121,19 +121,19 @@ GEM retriable (>= 2.0, < 4.a) rexml webrick - google-apis-iamcredentials_v1 (0.10.0) - google-apis-core (>= 0.4, < 2.a) - google-apis-playcustomapp_v1 (0.7.0) - google-apis-core (>= 0.4, < 2.a) - google-apis-storage_v1 (0.11.0) - google-apis-core (>= 0.4, < 2.a) + google-apis-iamcredentials_v1 (0.12.0) + google-apis-core (>= 0.6, < 2.a) + google-apis-playcustomapp_v1 (0.9.0) + google-apis-core (>= 0.6, < 2.a) + google-apis-storage_v1 (0.16.0) + google-apis-core (>= 0.6, < 2.a) google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) google-cloud-errors (1.2.0) - google-cloud-storage (1.36.1) + google-cloud-storage (1.36.2) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) @@ -141,7 +141,7 @@ GEM google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.1.2) + googleauth (1.2.0) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) memoist (~> 0.16) @@ -149,12 +149,12 @@ GEM os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) highline (2.0.3) - http-cookie (1.0.4) + http-cookie (1.0.5) domain_name (~> 0.5) httpclient (2.8.3) jmespath (1.6.1) - json (2.6.1) - jwt (2.3.0) + json (2.6.2) + jwt (2.4.1) memoist (0.16.2) mini_magick (4.11.0) mini_mime (1.1.2) @@ -169,10 +169,10 @@ GEM optparse (0.1.1) os (1.1.4) plist (3.6.0) - public_suffix (4.0.6) + public_suffix (4.0.7) racc (1.6.0) rake (13.0.6) - representable (3.1.1) + representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) @@ -182,9 +182,9 @@ GEM ruby2_keywords (0.0.5) rubyzip (2.3.2) security (0.1.3) - signet (0.16.1) + signet (0.17.0) addressable (~> 2.8) - faraday (>= 0.17.5, < 3.0) + faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) simctl (1.6.8) @@ -205,11 +205,11 @@ GEM uber (0.1.0) unf (0.1.4) unf_ext - unf_ext (0.0.8.1) + unf_ext (0.0.8.2) unicode-display_width (1.8.0) webrick (1.7.0) word_wrap (1.0.0) - xcodeproj (1.21.0) + xcodeproj (1.22.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0)