diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ccfc888032..e7e7ba5fe7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,12 +126,6 @@ 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 iOS framework project for now. diff --git a/SampleGame.Android/SampleGameActivity.cs b/SampleGame.Android/SampleGameActivity.cs index 25b3c0c134..bdb800d5da 100644 --- a/SampleGame.Android/SampleGameActivity.cs +++ b/SampleGame.Android/SampleGameActivity.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 Android.App; using osu.Framework; using osu.Framework.Android; diff --git a/osu-framework.sln.DotSettings b/osu-framework.sln.DotSettings index 6c41a91352..7071a978cb 100644 --- a/osu-framework.sln.DotSettings +++ b/osu-framework.sln.DotSettings @@ -801,6 +801,16 @@ See the LICENCE file in the repository root for full licence text. <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + True + True + True + True + True + True + True + True + True + True True True True diff --git a/osu.Framework.Android/AndroidGameActivity.cs b/osu.Framework.Android/AndroidGameActivity.cs index 2b82ce55ad..774ad6f1b5 100644 --- a/osu.Framework.Android/AndroidGameActivity.cs +++ b/osu.Framework.Android/AndroidGameActivity.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 Android.App; using Android.Content; using Android.Content.PM; @@ -11,7 +9,7 @@ using Android.Views; using ManagedBass; using osu.Framework.Bindables; -using Debug = System.Diagnostics.Debug; +using osu.Framework.Extensions.ObjectExtensions; namespace osu.Framework.Android { @@ -43,22 +41,17 @@ public abstract class AndroidGameActivity : Activity /// public SystemUiFlags UIVisibilityFlags { - get - { - Debug.Assert(Window != null); - return (SystemUiFlags)Window.DecorView.SystemUiVisibility; - } + get => (SystemUiFlags)Window.AsNonNull().DecorView.SystemUiVisibility; set { - Debug.Assert(Window != null); systemUiFlags = value; - Window.DecorView.SystemUiVisibility = (StatusBarVisibility)value; + Window.AsNonNull().DecorView.SystemUiVisibility = (StatusBarVisibility)value; } } private SystemUiFlags systemUiFlags; - private AndroidGameView gameView; + private AndroidGameView gameView = null!; public override void OnTrimMemory([GeneratedEnum] TrimMemory level) { @@ -66,7 +59,7 @@ public override void OnTrimMemory([GeneratedEnum] TrimMemory level) gameView.Host?.Collect(); } - protected override void OnCreate(Bundle savedInstanceState) + protected override void OnCreate(Bundle? savedInstanceState) { // The default current directory on android is '/'. // On some devices '/' maps to the app data directory. On others it maps to the root of the internal storage. @@ -79,11 +72,9 @@ protected override void OnCreate(Bundle savedInstanceState) UIVisibilityFlags = SystemUiFlags.LayoutFlags | SystemUiFlags.ImmersiveSticky | SystemUiFlags.HideNavigation | SystemUiFlags.Fullscreen; - Debug.Assert(Window != null); - // Firing up the on-screen keyboard (eg: interacting with textboxes) may cause the UI visibility flags to be altered thus showing the navigation bar and potentially the status bar // This sets back the UI flags to hidden once the interaction with the on-screen keyboard has finished. - Window.DecorView.SystemUiVisibilityChange += (_, e) => + Window.AsNonNull().DecorView.SystemUiVisibilityChange += (_, e) => { if ((SystemUiFlags)e.Visibility != systemUiFlags) { @@ -93,8 +84,7 @@ protected override void OnCreate(Bundle savedInstanceState) if (Build.VERSION.SdkInt >= BuildVersionCodes.P) { - Debug.Assert(Window.Attributes != null); - Window.Attributes.LayoutInDisplayCutoutMode = LayoutInDisplayCutoutMode.ShortEdges; + Window.AsNonNull().Attributes.AsNonNull().LayoutInDisplayCutoutMode = LayoutInDisplayCutoutMode.ShortEdges; } gameView.HostStarted += host => @@ -104,9 +94,9 @@ protected override void OnCreate(Bundle savedInstanceState) RunOnUiThread(() => { if (!allow.NewValue) - Window.AddFlags(WindowManagerFlags.KeepScreenOn); + Window?.AddFlags(WindowManagerFlags.KeepScreenOn); else - Window.ClearFlags(WindowManagerFlags.KeepScreenOn); + Window?.ClearFlags(WindowManagerFlags.KeepScreenOn); }); }, true); }; @@ -141,17 +131,17 @@ public override void OnBackPressed() // On some devices and keyboard combinations the OnKeyDown event does not propagate the key event to the view. // Here it is done manually to ensure that the keys actually land in the view. - public override bool OnKeyDown([GeneratedEnum] Keycode keyCode, KeyEvent e) + public override bool OnKeyDown([GeneratedEnum] Keycode keyCode, KeyEvent? e) { return gameView.OnKeyDown(keyCode, e); } - public override bool OnKeyUp([GeneratedEnum] Keycode keyCode, KeyEvent e) + public override bool OnKeyUp([GeneratedEnum] Keycode keyCode, KeyEvent? e) { return gameView.OnKeyUp(keyCode, e); } - public override bool OnKeyLongPress([GeneratedEnum] Keycode keyCode, KeyEvent e) + public override bool OnKeyLongPress([GeneratedEnum] Keycode keyCode, KeyEvent? e) { return gameView.OnKeyLongPress(keyCode, e); } diff --git a/osu.Framework.Android/AndroidGameHost.cs b/osu.Framework.Android/AndroidGameHost.cs index 5b92e12ccc..d69ee62775 100644 --- a/osu.Framework.Android/AndroidGameHost.cs +++ b/osu.Framework.Android/AndroidGameHost.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.IO; using Android.App; @@ -11,6 +9,7 @@ using osu.Framework.Android.Graphics.Video; using osu.Framework.Android.Input; using osu.Framework.Configuration; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Video; using osu.Framework.Input; @@ -65,7 +64,7 @@ protected override IEnumerable CreateAvailableInputHandlers() => public override IEnumerable UserStoragePaths => new[] { // not null as internal "external storage" is always available. - Application.Context.GetExternalFilesDir(string.Empty)!.ToString(), + Application.Context.GetExternalFilesDir(string.Empty).AsNonNull().ToString(), }; public override bool OpenFileExternally(string filename) => false; diff --git a/osu.Framework.Android/AndroidGameView.cs b/osu.Framework.Android/AndroidGameView.cs index c0b1967732..15886a19e2 100644 --- a/osu.Framework.Android/AndroidGameView.cs +++ b/osu.Framework.Android/AndroidGameView.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 Android.Content; using Android.Graphics; @@ -15,19 +13,19 @@ using osu.Framework.Android.Input; using osu.Framework.Logging; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; using osu.Framework.Platform; using osuTK.Graphics; -using Debug = System.Diagnostics.Debug; namespace osu.Framework.Android { public class AndroidGameView : osuTK.Android.AndroidGameView { - public AndroidGameHost Host { get; private set; } + public AndroidGameHost? Host { get; private set; } - public AndroidGameActivity Activity { get; } + public AndroidGameActivity Activity { get; } = null!; public BindableSafeArea SafeAreaPadding { get; } = new BindableSafeArea(); @@ -62,9 +60,9 @@ public bool PointerCapture } } - private readonly Game game; + private readonly Game game = null!; - private InputMethodManager inputMethodManager; + private InputMethodManager? inputMethodManager; /// /// Whether is active. @@ -128,8 +126,10 @@ public bool OnCommitText(string text) return false; } - public override bool OnKeyDown([GeneratedEnum] Keycode keyCode, KeyEvent e) + public override bool OnKeyDown([GeneratedEnum] Keycode keyCode, KeyEvent? e) { + if (e == null) return base.OnKeyDown(keyCode, e); + switch (keyCode) { // Do not consume Volume keys, so the system can handle them @@ -151,14 +151,18 @@ public override bool OnKeyDown([GeneratedEnum] Keycode keyCode, KeyEvent e) } } - public override bool OnKeyLongPress([GeneratedEnum] Keycode keyCode, KeyEvent e) + public override bool OnKeyLongPress([GeneratedEnum] Keycode keyCode, KeyEvent? e) { + if (e == null) return base.OnKeyLongPress(keyCode, e); + KeyLongPress?.Invoke(keyCode, e); return true; } - public override bool OnKeyUp([GeneratedEnum] Keycode keyCode, KeyEvent e) + public override bool OnKeyUp([GeneratedEnum] Keycode keyCode, KeyEvent? e) { + if (e == null) return base.OnKeyUp(keyCode, e); + KeyUp?.Invoke(keyCode, e); return true; } @@ -206,12 +210,10 @@ private bool handleException(Exception ex) /// private void updateSafeArea() { - Debug.Assert(Display != null); - // compute the usable screen area. var screenSize = new Point(); - Display.GetRealSize(screenSize); + Display.AsNonNull().GetRealSize(screenSize); var screenArea = new RectangleI(0, 0, screenSize.X, screenSize.Y); var usableScreenArea = screenArea; @@ -257,8 +259,10 @@ private void updateSafeArea() public override bool OnCheckIsTextEditor() => textInputActive; /// null to disable input methods - public override IInputConnection OnCreateInputConnection(EditorInfo outAttrs) + public override IInputConnection? OnCreateInputConnection(EditorInfo? outAttrs) { + if (outAttrs == null) throw new ArgumentNullException(nameof(outAttrs)); + // Properly disable native input methods so that the software keyboard doesn't unexpectedly open. // Eg. when pressing keys on a hardware keyboard. if (!textInputActive) @@ -274,7 +278,7 @@ internal void StartTextInput() textInputActive = true; Activity.RunOnUiThread(() => { - inputMethodManager.RestartInput(this); // this syncs the Android input method state with `OnCreateInputConnection()`. + inputMethodManager?.RestartInput(this); // this syncs the Android input method state with `OnCreateInputConnection()`. RequestFocus(); inputMethodManager?.ShowSoftInput(this, 0); }); @@ -285,7 +289,7 @@ internal void StopTextInput() textInputActive = false; Activity.RunOnUiThread(() => { - inputMethodManager.RestartInput(this); + inputMethodManager?.RestartInput(this); inputMethodManager?.HideSoftInputFromWindow(WindowToken, HideSoftInputFlags.None); ClearFocus(); }); @@ -316,27 +320,27 @@ public override void SwapBuffers() /// /// Invoked on a key down event. /// - public new event Action KeyDown; + public new event Action? KeyDown; /// /// Invoked on a key up event. /// - public new event Action KeyUp; + public new event Action? KeyUp; /// /// Invoked on a key long press event. /// - public event Action KeyLongPress; + public event Action? KeyLongPress; /// /// Invoked when text is committed by an . /// - public event Action CommitText; + public event Action? CommitText; /// /// Invoked when the has been started on the . /// - public event Action HostStarted; + public event Action? HostStarted; #endregion } diff --git a/osu.Framework.Android/AndroidGameWindow.cs b/osu.Framework.Android/AndroidGameWindow.cs index 9232c01acc..8a80387045 100644 --- a/osu.Framework.Android/AndroidGameWindow.cs +++ b/osu.Framework.Android/AndroidGameWindow.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.Bindables; @@ -29,7 +27,7 @@ public override Platform.WindowState WindowState set { } } - public event Action CursorStateChanged; + public event Action? CursorStateChanged; public override CursorState CursorState { diff --git a/osu.Framework.Android/AndroidStorage.cs b/osu.Framework.Android/AndroidStorage.cs index ff8db9559e..6b88be723b 100644 --- a/osu.Framework.Android/AndroidStorage.cs +++ b/osu.Framework.Android/AndroidStorage.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.Platform; namespace osu.Framework.Android diff --git a/osu.Framework.Android/Graphics/Textures/AndroidTextureLoaderStore.cs b/osu.Framework.Android/Graphics/Textures/AndroidTextureLoaderStore.cs index 2a2211c982..1f1730db4c 100644 --- a/osu.Framework.Android/Graphics/Textures/AndroidTextureLoaderStore.cs +++ b/osu.Framework.Android/Graphics/Textures/AndroidTextureLoaderStore.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.IO; using Android.Graphics; diff --git a/osu.Framework.Android/Graphics/Video/AndroidVideoDecoder.cs b/osu.Framework.Android/Graphics/Video/AndroidVideoDecoder.cs index c3011bd12f..1fb151b2e5 100644 --- a/osu.Framework.Android/Graphics/Video/AndroidVideoDecoder.cs +++ b/osu.Framework.Android/Graphics/Video/AndroidVideoDecoder.cs @@ -1,17 +1,15 @@ // 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.IO; using System.Reflection; using System.Runtime.InteropServices; using Android.Runtime; using FFmpeg.AutoGen; using osu.Framework.Extensions.EnumExtensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.Video; using osu.Framework.Logging; @@ -151,11 +149,9 @@ public AndroidVideoDecoder(Stream videoStream) const string java_vm_field_name = "java_vm"; var jvmPtrInfo = typeof(JNIEnv).GetField(java_vm_field_name, BindingFlags.NonPublic | BindingFlags.Static); - object jvmPtrObj = jvmPtrInfo?.GetValue(null); - - Debug.Assert(jvmPtrObj != null); + object? jvmPtrObj = jvmPtrInfo?.GetValue(null); - int result = av_jni_set_java_vm((void*)(IntPtr)jvmPtrObj, null); + int result = av_jni_set_java_vm((void*)(IntPtr)jvmPtrObj.AsNonNull(), null); if (result < 0) throw new InvalidOperationException($"Couldn't pass Java VM handle to FFmpeg: ${result}"); } diff --git a/osu.Framework.Android/Input/AndroidInputConnection.cs b/osu.Framework.Android/Input/AndroidInputConnection.cs index 3c20157993..1bcdee1fb9 100644 --- a/osu.Framework.Android/Input/AndroidInputConnection.cs +++ b/osu.Framework.Android/Input/AndroidInputConnection.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 Android.Views; using Android.Views.InputMethods; using Java.Lang; @@ -11,40 +9,43 @@ namespace osu.Framework.Android.Input { internal class AndroidInputConnection : BaseInputConnection { - public AndroidGameView TargetView { get; set; } + private readonly AndroidGameView targetView; public AndroidInputConnection(AndroidGameView targetView, bool fullEditor) : base(targetView, fullEditor) { - TargetView = targetView; + this.targetView = targetView; } - public override bool CommitText(ICharSequence text, int newCursorPosition) + public override bool CommitText(ICharSequence? text, int newCursorPosition) { - if (text.Length() != 0) + if (text?.Length() > 0) { - TargetView.OnCommitText(text.ToString()); + targetView.OnCommitText(text.ToString()); return true; } return base.CommitText(text, newCursorPosition); } - public override bool SendKeyEvent(KeyEvent e) + public override bool SendKeyEvent(KeyEvent? e) { + if (e == null) + return base.SendKeyEvent(e); + switch (e.Action) { case KeyEventActions.Down: - TargetView?.OnKeyDown(e.KeyCode, e); + targetView.OnKeyDown(e.KeyCode, e); return true; case KeyEventActions.Up: - TargetView?.OnKeyUp(e.KeyCode, e); + targetView.OnKeyUp(e.KeyCode, e); return true; case KeyEventActions.Multiple: - TargetView?.OnKeyDown(e.KeyCode, e); - TargetView?.OnKeyUp(e.KeyCode, e); + targetView.OnKeyDown(e.KeyCode, e); + targetView.OnKeyUp(e.KeyCode, e); return true; } diff --git a/osu.Framework.Android/Input/AndroidInputExtensions.cs b/osu.Framework.Android/Input/AndroidInputExtensions.cs index 550e5008bc..dd3860029f 100644 --- a/osu.Framework.Android/Input/AndroidInputExtensions.cs +++ b/osu.Framework.Android/Input/AndroidInputExtensions.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 Android.Views; diff --git a/osu.Framework.Android/Properties/AssemblyInfo.cs b/osu.Framework.Android/Properties/AssemblyInfo.cs index 587c7bb43e..16db49e197 100644 --- a/osu.Framework.Android/Properties/AssemblyInfo.cs +++ b/osu.Framework.Android/Properties/AssemblyInfo.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.Runtime.CompilerServices; using Android; using Android.App; diff --git a/osu.Framework.Benchmarks/BenchmarkAggregateBindable.cs b/osu.Framework.Benchmarks/BenchmarkAggregateBindable.cs index 0fb3de4e28..3e01b96c66 100644 --- a/osu.Framework.Benchmarks/BenchmarkAggregateBindable.cs +++ b/osu.Framework.Benchmarks/BenchmarkAggregateBindable.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 BenchmarkDotNet.Attributes; using osu.Framework.Bindables; diff --git a/osu.Framework.Benchmarks/BenchmarkBeginAbsoluteSequence.cs b/osu.Framework.Benchmarks/BenchmarkBeginAbsoluteSequence.cs index 26d73f880c..dfdfc81582 100644 --- a/osu.Framework.Benchmarks/BenchmarkBeginAbsoluteSequence.cs +++ b/osu.Framework.Benchmarks/BenchmarkBeginAbsoluteSequence.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 BenchmarkDotNet.Attributes; using NUnit.Framework; using osu.Framework.Graphics; @@ -16,7 +14,7 @@ namespace osu.Framework.Benchmarks [MemoryDiagnoser] public class BenchmarkBeginAbsoluteSequence : GameBenchmark { - private TestGame game; + private TestGame game = null!; [Test] [Benchmark] @@ -106,9 +104,9 @@ public void VeryNestedRecursive() private class TestGame : Game { - public Container Flat; - public Container VeryNested; - public Container SlightlyNested; + public Container Flat = null!; + public Container VeryNested = null!; + public Container SlightlyNested = null!; protected override void LoadComplete() { diff --git a/osu.Framework.Benchmarks/BenchmarkBindableInstantiation.cs b/osu.Framework.Benchmarks/BenchmarkBindableInstantiation.cs index aa165f4fc2..be5c1cd988 100644 --- a/osu.Framework.Benchmarks/BenchmarkBindableInstantiation.cs +++ b/osu.Framework.Benchmarks/BenchmarkBindableInstantiation.cs @@ -1,11 +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; using BenchmarkDotNet.Attributes; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; namespace osu.Framework.Benchmarks { @@ -21,14 +20,14 @@ public class BenchmarkBindableInstantiation [Benchmark(Baseline = true)] public Bindable GetBoundCopyOld() => new BindableOld().GetBoundCopy(); - private class BindableOld : Bindable + private class BindableOld : Bindable where T : notnull { - public BindableOld(T defaultValue = default) + public BindableOld(T defaultValue = default!) : base(defaultValue) { } - protected override Bindable CreateInstance() => (BindableOld)Activator.CreateInstance(GetType(), Value); + protected override Bindable CreateInstance() => (BindableOld)Activator.CreateInstance(GetType(), Value).AsNonNull(); } } } diff --git a/osu.Framework.Benchmarks/BenchmarkBindableList.cs b/osu.Framework.Benchmarks/BenchmarkBindableList.cs index 1b8646ee0d..6154505ffa 100644 --- a/osu.Framework.Benchmarks/BenchmarkBindableList.cs +++ b/osu.Framework.Benchmarks/BenchmarkBindableList.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 BenchmarkDotNet.Attributes; using osu.Framework.Bindables; diff --git a/osu.Framework.Benchmarks/BenchmarkButtonInput.cs b/osu.Framework.Benchmarks/BenchmarkButtonInput.cs index 73d7012aa9..e101a85442 100644 --- a/osu.Framework.Benchmarks/BenchmarkButtonInput.cs +++ b/osu.Framework.Benchmarks/BenchmarkButtonInput.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 BenchmarkDotNet.Attributes; using osu.Framework.Input.StateChanges; diff --git a/osu.Framework.Benchmarks/BenchmarkButtonStates.cs b/osu.Framework.Benchmarks/BenchmarkButtonStates.cs index cf85a9f368..7e29887be9 100644 --- a/osu.Framework.Benchmarks/BenchmarkButtonStates.cs +++ b/osu.Framework.Benchmarks/BenchmarkButtonStates.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 BenchmarkDotNet.Attributes; using osu.Framework.Input.States; using osuTK.Input; diff --git a/osu.Framework.Benchmarks/BenchmarkCompositeDrawableAllocations.cs b/osu.Framework.Benchmarks/BenchmarkCompositeDrawableAllocations.cs index 7f14d3e91c..0513c02066 100644 --- a/osu.Framework.Benchmarks/BenchmarkCompositeDrawableAllocations.cs +++ b/osu.Framework.Benchmarks/BenchmarkCompositeDrawableAllocations.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 BenchmarkDotNet.Attributes; using NUnit.Framework; using osu.Framework.Graphics; @@ -13,7 +11,7 @@ namespace osu.Framework.Benchmarks { public class BenchmarkCompositeDrawableAllocations : GameBenchmark { - private TestGame game; + private TestGame game = null!; [Test] [Benchmark] @@ -65,7 +63,7 @@ protected override void Update() { base.Update(); - Drawable drawable = null; + Drawable? drawable = null; switch (Mode) { diff --git a/osu.Framework.Benchmarks/BenchmarkDependencyContainer.cs b/osu.Framework.Benchmarks/BenchmarkDependencyContainer.cs index 96cf5b37c8..5cab656f7b 100644 --- a/osu.Framework.Benchmarks/BenchmarkDependencyContainer.cs +++ b/osu.Framework.Benchmarks/BenchmarkDependencyContainer.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.Threading; using BenchmarkDotNet.Attributes; using JetBrains.Annotations; @@ -20,9 +18,9 @@ namespace osu.Framework.Benchmarks { public class BenchmarkDependencyContainer : GameBenchmark { - private Game game; - private TestBdlReceiver bdlReceiver; - private TestCachedReceiver cachedReceiver; + private Game game = null!; + private TestBdlReceiver bdlReceiver = null!; + private TestCachedReceiver cachedReceiver = null!; public override void SetUp() { @@ -65,13 +63,13 @@ private void load(Game game, TextureStore textures, AudioManager audio) private class TestCachedReceiver : Drawable { [Resolved] - private GameHost host { get; set; } + private GameHost host { get; set; } = null!; [Resolved] - private FrameworkConfigManager frameworkConfigManager { get; set; } + private FrameworkConfigManager frameworkConfigManager { get; set; } = null!; [Resolved] - private FrameworkDebugConfigManager frameworkDebugConfigManager { get; set; } + private FrameworkDebugConfigManager frameworkDebugConfigManager { get; set; } = null!; } private class TestGame : Game diff --git a/osu.Framework.Benchmarks/BenchmarkDrawableAudioWrapper.cs b/osu.Framework.Benchmarks/BenchmarkDrawableAudioWrapper.cs index 896a4624e3..bd71549745 100644 --- a/osu.Framework.Benchmarks/BenchmarkDrawableAudioWrapper.cs +++ b/osu.Framework.Benchmarks/BenchmarkDrawableAudioWrapper.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 BenchmarkDotNet.Attributes; using NUnit.Framework; using osu.Framework.Graphics; @@ -39,7 +37,7 @@ private class TestGame : Game public bool TransferBetween { get; set; } - private AudioContainer lastContainer; + private AudioContainer? lastContainer; protected override void LoadComplete() { diff --git a/osu.Framework.Benchmarks/BenchmarkDrawableLoad.cs b/osu.Framework.Benchmarks/BenchmarkDrawableLoad.cs index b016dd1c4a..441dbebd88 100644 --- a/osu.Framework.Benchmarks/BenchmarkDrawableLoad.cs +++ b/osu.Framework.Benchmarks/BenchmarkDrawableLoad.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 BenchmarkDotNet.Attributes; using NUnit.Framework; using osu.Framework.Graphics; @@ -16,7 +14,7 @@ namespace osu.Framework.Benchmarks [MemoryDiagnoser] public class BenchmarkDrawableLoad : GameBenchmark { - private TestGame game; + private TestGame game = null!; private const int nesting_level = 100; diff --git a/osu.Framework.Benchmarks/BenchmarkEnum.cs b/osu.Framework.Benchmarks/BenchmarkEnum.cs index 5089c162ab..530bc6b07b 100644 --- a/osu.Framework.Benchmarks/BenchmarkEnum.cs +++ b/osu.Framework.Benchmarks/BenchmarkEnum.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 BenchmarkDotNet.Attributes; using osu.Framework.Extensions.EnumExtensions; diff --git a/osu.Framework.Benchmarks/BenchmarkFillFlowContainerAllocations.cs b/osu.Framework.Benchmarks/BenchmarkFillFlowContainerAllocations.cs index abba9cf137..28ce812b67 100644 --- a/osu.Framework.Benchmarks/BenchmarkFillFlowContainerAllocations.cs +++ b/osu.Framework.Benchmarks/BenchmarkFillFlowContainerAllocations.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 BenchmarkDotNet.Attributes; using osu.Framework.Graphics; @@ -14,7 +12,7 @@ namespace osu.Framework.Benchmarks { public class BenchmarkFillFlowContainerAllocations : GameBenchmark { - private TestGame game; + private TestGame game = null!; [Benchmark] public void MultipleComputeLayoutPositions() diff --git a/osu.Framework.Benchmarks/BenchmarkFontLoading.cs b/osu.Framework.Benchmarks/BenchmarkFontLoading.cs index b044a5d3e8..a98a26fbb4 100644 --- a/osu.Framework.Benchmarks/BenchmarkFontLoading.cs +++ b/osu.Framework.Benchmarks/BenchmarkFontLoading.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.Diagnostics; using System.Reflection; @@ -18,8 +16,8 @@ namespace osu.Framework.Benchmarks { public class BenchmarkFontLoading : BenchmarkTest { - private NamespacedResourceStore baseResources; - private TemporaryNativeStorage sharedTemp; + private NamespacedResourceStore baseResources = null!; + private TemporaryNativeStorage sharedTemp = null!; public override void SetUp() { @@ -32,7 +30,7 @@ public override void SetUp() [OneTimeTearDown] public void TearDown() { - sharedTemp?.Dispose(); + sharedTemp.Dispose(); } [Params(1, 10, 100, 1000, 10000)] @@ -93,7 +91,7 @@ private void runFor(GlyphStore store) { foreach (var p in props) { - object propValue = p.GetValue(null); + object? propValue = p.GetValue(null); Debug.Assert(propValue != null); var icon = (IconUsage)propValue; diff --git a/osu.Framework.Benchmarks/BenchmarkHashing.cs b/osu.Framework.Benchmarks/BenchmarkHashing.cs index bd4d99d0bc..5bff2e9be0 100644 --- a/osu.Framework.Benchmarks/BenchmarkHashing.cs +++ b/osu.Framework.Benchmarks/BenchmarkHashing.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.IO; using BenchmarkDotNet.Attributes; @@ -14,7 +12,7 @@ namespace osu.Framework.Benchmarks public class BenchmarkHashing { private const string test_string = @"A string with reasonable length"; - private MemoryStream memoryStream; + private MemoryStream memoryStream = null!; [Benchmark] public string StringMD5() => test_string.ComputeMD5Hash(); diff --git a/osu.Framework.Benchmarks/BenchmarkInterpolation.cs b/osu.Framework.Benchmarks/BenchmarkInterpolation.cs index 2cdf9e7a24..962a6f23bc 100644 --- a/osu.Framework.Benchmarks/BenchmarkInterpolation.cs +++ b/osu.Framework.Benchmarks/BenchmarkInterpolation.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 BenchmarkDotNet.Attributes; using osu.Framework.Graphics; using osu.Framework.Utils; diff --git a/osu.Framework.Benchmarks/BenchmarkInvalidationWithManyNotAlive.cs b/osu.Framework.Benchmarks/BenchmarkInvalidationWithManyNotAlive.cs index fe2249954f..6a65844709 100644 --- a/osu.Framework.Benchmarks/BenchmarkInvalidationWithManyNotAlive.cs +++ b/osu.Framework.Benchmarks/BenchmarkInvalidationWithManyNotAlive.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 BenchmarkDotNet.Attributes; using NUnit.Framework; using osu.Framework.Graphics; diff --git a/osu.Framework.Benchmarks/BenchmarkLocalisableDescription.cs b/osu.Framework.Benchmarks/BenchmarkLocalisableDescription.cs index e66f177536..db694e29c2 100644 --- a/osu.Framework.Benchmarks/BenchmarkLocalisableDescription.cs +++ b/osu.Framework.Benchmarks/BenchmarkLocalisableDescription.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 BenchmarkDotNet.Attributes; using osu.Framework.Extensions; using osu.Framework.Localisation; @@ -11,7 +9,7 @@ namespace osu.Framework.Benchmarks { public class BenchmarkLocalisableDescription { - private LocalisableString[] descriptions; + private LocalisableString[] descriptions = null!; [Params(1, 10, 100, 1000)] public int Times { get; set; } diff --git a/osu.Framework.Benchmarks/BenchmarkLocalisableString.cs b/osu.Framework.Benchmarks/BenchmarkLocalisableString.cs index 61f20cd73d..d04220cc87 100644 --- a/osu.Framework.Benchmarks/BenchmarkLocalisableString.cs +++ b/osu.Framework.Benchmarks/BenchmarkLocalisableString.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 BenchmarkDotNet.Attributes; using osu.Framework.Localisation; @@ -12,8 +10,8 @@ namespace osu.Framework.Benchmarks [MemoryDiagnoser] public class BenchmarkLocalisableString { - private string string1; - private string string2; + private string string1 = null!; + private string string2 = null!; private LocalisableString localisableString1; private LocalisableString localisableString2; private LocalisableString romanisableString1; diff --git a/osu.Framework.Benchmarks/BenchmarkLocalisedBindableString.cs b/osu.Framework.Benchmarks/BenchmarkLocalisedBindableString.cs index f30d696e05..5d5813704e 100644 --- a/osu.Framework.Benchmarks/BenchmarkLocalisedBindableString.cs +++ b/osu.Framework.Benchmarks/BenchmarkLocalisedBindableString.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 BenchmarkDotNet.Attributes; using osu.Framework.Configuration; @@ -14,8 +12,8 @@ namespace osu.Framework.Benchmarks [MemoryDiagnoser] public class BenchmarkLocalisedBindableString { - private LocalisationManager manager; - private TemporaryNativeStorage storage; + private LocalisationManager manager = null!; + private TemporaryNativeStorage storage = null!; [GlobalSetup] public void GlobalSetup() diff --git a/osu.Framework.Benchmarks/BenchmarkLogger.cs b/osu.Framework.Benchmarks/BenchmarkLogger.cs index 995ce3e5ba..1b9c7fa1fe 100644 --- a/osu.Framework.Benchmarks/BenchmarkLogger.cs +++ b/osu.Framework.Benchmarks/BenchmarkLogger.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 BenchmarkDotNet.Attributes; using osu.Framework.Logging; diff --git a/osu.Framework.Benchmarks/BenchmarkMakeChildAlive.cs b/osu.Framework.Benchmarks/BenchmarkMakeChildAlive.cs index c3de3a815c..15ecd14833 100644 --- a/osu.Framework.Benchmarks/BenchmarkMakeChildAlive.cs +++ b/osu.Framework.Benchmarks/BenchmarkMakeChildAlive.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 BenchmarkDotNet.Attributes; using NUnit.Framework; using osu.Framework.Graphics; diff --git a/osu.Framework.Benchmarks/BenchmarkManySpinningBoxes.cs b/osu.Framework.Benchmarks/BenchmarkManySpinningBoxes.cs index ac93ee34eb..12e6be556d 100644 --- a/osu.Framework.Benchmarks/BenchmarkManySpinningBoxes.cs +++ b/osu.Framework.Benchmarks/BenchmarkManySpinningBoxes.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 BenchmarkDotNet.Attributes; using NUnit.Framework; using osu.Framework.Graphics; @@ -15,7 +13,7 @@ namespace osu.Framework.Benchmarks { public class BenchmarkManySpinningBoxes : GameBenchmark { - private TestGame game; + private TestGame game = null!; [Test] [Benchmark] @@ -49,7 +47,7 @@ public void RunFrameWithAutoSizeDuration() private class TestGame : Game { - public Container MainContent; + public Container MainContent = null!; protected override void LoadComplete() { diff --git a/osu.Framework.Benchmarks/BenchmarkScheduler.cs b/osu.Framework.Benchmarks/BenchmarkScheduler.cs new file mode 100644 index 0000000000..4ac44dc3cc --- /dev/null +++ b/osu.Framework.Benchmarks/BenchmarkScheduler.cs @@ -0,0 +1,60 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using BenchmarkDotNet.Attributes; +using osu.Framework.Threading; + +namespace osu.Framework.Benchmarks +{ + public class BenchmarkScheduler : BenchmarkTest + { + private Scheduler scheduler = null!; + private Scheduler schedulerWithEveryUpdate = null!; + private Scheduler schedulerWithManyDelayed = null!; + + public override void SetUp() + { + base.SetUp(); + + scheduler = new Scheduler(); + + schedulerWithEveryUpdate = new Scheduler(); + schedulerWithEveryUpdate.AddDelayed(() => { }, 0, true); + + schedulerWithManyDelayed = new Scheduler(); + for (int i = 0; i < 1000; i++) + schedulerWithManyDelayed.AddDelayed(() => { }, int.MaxValue); + } + + [Benchmark] + public void UpdateEmptyScheduler() + { + for (int i = 0; i < 1000; i++) + scheduler.Update(); + } + + [Benchmark] + public void UpdateSchedulerWithManyDelayed() + { + for (int i = 0; i < 1000; i++) + schedulerWithManyDelayed.Update(); + } + + [Benchmark] + public void UpdateSchedulerWithEveryUpdate() + { + for (int i = 0; i < 1000; i++) + schedulerWithEveryUpdate.Update(); + } + + [Benchmark] + public void UpdateSchedulerWithManyAdded() + { + for (int i = 0; i < 1000; i++) + { + scheduler.Add(() => { }); + scheduler.Update(); + } + } + } +} diff --git a/osu.Framework.Benchmarks/BenchmarkScreenExtensions.cs b/osu.Framework.Benchmarks/BenchmarkScreenExtensions.cs index 684ca8a838..f9553e7d6e 100644 --- a/osu.Framework.Benchmarks/BenchmarkScreenExtensions.cs +++ b/osu.Framework.Benchmarks/BenchmarkScreenExtensions.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 BenchmarkDotNet.Attributes; using NUnit.Framework; using osu.Framework.Screens; @@ -11,7 +9,7 @@ namespace osu.Framework.Benchmarks { public class BenchmarkScreenExtensions : GameBenchmark { - private Screen testScreen; + private Screen testScreen = null!; [Test] [Benchmark] diff --git a/osu.Framework.Benchmarks/BenchmarkSlimReadOnlyCollection.cs b/osu.Framework.Benchmarks/BenchmarkSlimReadOnlyCollection.cs index 339f985484..db94774d36 100644 --- a/osu.Framework.Benchmarks/BenchmarkSlimReadOnlyCollection.cs +++ b/osu.Framework.Benchmarks/BenchmarkSlimReadOnlyCollection.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 BenchmarkDotNet.Attributes; using osu.Framework.Extensions.ListExtensions; diff --git a/osu.Framework.Benchmarks/BenchmarkSpinningParentWithManyAlive.cs b/osu.Framework.Benchmarks/BenchmarkSpinningParentWithManyAlive.cs index 8827a829e1..681ed781f7 100644 --- a/osu.Framework.Benchmarks/BenchmarkSpinningParentWithManyAlive.cs +++ b/osu.Framework.Benchmarks/BenchmarkSpinningParentWithManyAlive.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 BenchmarkDotNet.Attributes; using NUnit.Framework; using osu.Framework.Graphics; diff --git a/osu.Framework.Benchmarks/BenchmarkStreamExtensions.cs b/osu.Framework.Benchmarks/BenchmarkStreamExtensions.cs index b292a8f713..575109e5be 100644 --- a/osu.Framework.Benchmarks/BenchmarkStreamExtensions.cs +++ b/osu.Framework.Benchmarks/BenchmarkStreamExtensions.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.IO; using BenchmarkDotNet.Attributes; @@ -13,7 +11,7 @@ namespace osu.Framework.Benchmarks [MemoryDiagnoser] public class BenchmarkStreamExtensions { - private MemoryStream memoryStream; + private MemoryStream memoryStream = null!; [Params(100, 10000, 1000000)] public int Length { get; set; } diff --git a/osu.Framework.Benchmarks/BenchmarkTabletDriver.cs b/osu.Framework.Benchmarks/BenchmarkTabletDriver.cs index 03598936f2..68218d22fd 100644 --- a/osu.Framework.Benchmarks/BenchmarkTabletDriver.cs +++ b/osu.Framework.Benchmarks/BenchmarkTabletDriver.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 - #if NET6_0 using BenchmarkDotNet.Attributes; using osu.Framework.Input.Handlers.Tablet; @@ -11,7 +9,7 @@ namespace osu.Framework.Benchmarks { public class BenchmarkTabletDriver : BenchmarkTest { - private TabletDriver driver; + private TabletDriver driver = null!; public override void SetUp() { diff --git a/osu.Framework.Benchmarks/BenchmarkTest.cs b/osu.Framework.Benchmarks/BenchmarkTest.cs index a80ce57576..f2b65a4e22 100644 --- a/osu.Framework.Benchmarks/BenchmarkTest.cs +++ b/osu.Framework.Benchmarks/BenchmarkTest.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 BenchmarkDotNet.Attributes; using BenchmarkDotNet.Running; using NUnit.Framework; diff --git a/osu.Framework.Benchmarks/BenchmarkTextBuilder.cs b/osu.Framework.Benchmarks/BenchmarkTextBuilder.cs index e6f85cf0d2..4a40634bd4 100644 --- a/osu.Framework.Benchmarks/BenchmarkTextBuilder.cs +++ b/osu.Framework.Benchmarks/BenchmarkTextBuilder.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.Threading.Tasks; using BenchmarkDotNet.Attributes; using osu.Framework.Graphics.Sprites; @@ -15,7 +13,7 @@ public class BenchmarkTextBuilder { private readonly ITexturedGlyphLookupStore store = new TestStore(); - private TextBuilder textBuilder; + private TextBuilder textBuilder = null!; [Benchmark] public void AddCharacters() => initialiseBuilder(false); diff --git a/osu.Framework.Benchmarks/BenchmarkTransform.cs b/osu.Framework.Benchmarks/BenchmarkTransform.cs index dfc4bbda0a..e6a62ae8da 100644 --- a/osu.Framework.Benchmarks/BenchmarkTransform.cs +++ b/osu.Framework.Benchmarks/BenchmarkTransform.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 BenchmarkDotNet.Attributes; using osu.Framework.Graphics; @@ -15,7 +13,7 @@ namespace osu.Framework.Benchmarks { public class BenchmarkTransform : BenchmarkTest { - private Drawable target; + private Drawable target = null!; public override void SetUp() { diff --git a/osu.Framework.Benchmarks/BenchmarkTransformUpdate.cs b/osu.Framework.Benchmarks/BenchmarkTransformUpdate.cs index 6bebf443a6..90e0d34bdd 100644 --- a/osu.Framework.Benchmarks/BenchmarkTransformUpdate.cs +++ b/osu.Framework.Benchmarks/BenchmarkTransformUpdate.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 BenchmarkDotNet.Attributes; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; @@ -13,7 +11,8 @@ namespace osu.Framework.Benchmarks { public class BenchmarkTransformUpdate : BenchmarkTest { - private TestBox target; + private TestBox target = null!; + private TestBox targetNoTransforms = null!; public override void SetUp() { @@ -23,7 +22,8 @@ public override void SetUp() ManualClock clock; - target = new TestBox { Clock = new FramedClock(clock = new ManualClock()) }; + targetNoTransforms = new TestBox { Clock = new FramedClock(clock = new ManualClock()) }; + target = new TestBox { Clock = new FramedClock(clock) }; // transform one target member over a long period target.RotateTo(360, transforms_count * 2); @@ -36,6 +36,13 @@ public override void SetUp() target.Clock.ProcessFrame(); } + [Benchmark] + public void UpdateTransformsWithNonePresent() + { + for (int i = 0; i < 10000; i++) + targetNoTransforms.UpdateTransforms(); + } + [Benchmark] public void UpdateTransformsWithManyPresent() { diff --git a/osu.Framework.Benchmarks/BenchmarkWeakList.cs b/osu.Framework.Benchmarks/BenchmarkWeakList.cs index 7afdc6bbae..54ab24df70 100644 --- a/osu.Framework.Benchmarks/BenchmarkWeakList.cs +++ b/osu.Framework.Benchmarks/BenchmarkWeakList.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.Linq; using BenchmarkDotNet.Attributes; @@ -16,7 +14,7 @@ public class BenchmarkWeakList : BenchmarkTest public int ItemCount { get; set; } private readonly object[] objects = new object[1000]; - private WeakList weakList; + private WeakList weakList = null!; public override void SetUp() { diff --git a/osu.Framework.Benchmarks/GameBenchmark.cs b/osu.Framework.Benchmarks/GameBenchmark.cs index f4d4655b02..3c90cbfe62 100644 --- a/osu.Framework.Benchmarks/GameBenchmark.cs +++ b/osu.Framework.Benchmarks/GameBenchmark.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.Threading; using System.Threading.Tasks; @@ -17,9 +15,9 @@ namespace osu.Framework.Benchmarks [MemoryDiagnoser] public abstract class GameBenchmark { - private ManualGameHost gameHost; + private ManualGameHost gameHost = null!; - protected Game Game { get; private set; } + protected Game Game { get; private set; } = null!; [GlobalSetup] [OneTimeSetUp] @@ -32,8 +30,8 @@ public virtual void SetUp() [OneTimeTearDown] public virtual void TearDown() { - gameHost?.Exit(); - gameHost?.Dispose(); + gameHost.Exit(); + gameHost.Dispose(); } /// diff --git a/osu.Framework.Benchmarks/Program.cs b/osu.Framework.Benchmarks/Program.cs index 5faa5c4aef..0fb9705a83 100644 --- a/osu.Framework.Benchmarks/Program.cs +++ b/osu.Framework.Benchmarks/Program.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 BenchmarkDotNet.Configs; using BenchmarkDotNet.Running; diff --git a/osu.Framework.Tests.Android/TestGameActivity.cs b/osu.Framework.Tests.Android/TestGameActivity.cs index f352afb2d8..19851817fd 100644 --- a/osu.Framework.Tests.Android/TestGameActivity.cs +++ b/osu.Framework.Tests.Android/TestGameActivity.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 Android.App; using osu.Framework.Android; diff --git a/osu.Framework.Tests/Visual/Sprites/TestSceneTextures.cs b/osu.Framework.Tests/Visual/Sprites/TestSceneTextures.cs index 4cb229ff9c..40bd5e8ab0 100644 --- a/osu.Framework.Tests/Visual/Sprites/TestSceneTextures.cs +++ b/osu.Framework.Tests/Visual/Sprites/TestSceneTextures.cs @@ -229,7 +229,7 @@ private T getWithBlocking(string name, Func getFunc) } TotalCompletedLookups++; - return getFunc("sample-texture"); + return getFunc("sample-texture.png"); } public void Reset() diff --git a/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs b/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs index 5aa4e7828f..108436f689 100644 --- a/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs +++ b/osu.Framework.Tests/Visual/UserInterface/TestSceneSliderBar.cs @@ -4,11 +4,14 @@ #nullable disable using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; using osu.Framework.Testing; using osu.Framework.Utils; using osuTK; @@ -24,6 +27,7 @@ public class TestSceneSliderBar : ManualInputManagerTestScene private readonly SpriteText sliderBarText; private readonly TestSliderBar sliderBar; private readonly SliderBar transferOnCommitSliderBar; + private readonly TestSliderBarWithNub sliderBarWithNub; public TestSceneSliderBar() { @@ -84,6 +88,18 @@ public TestSceneSliderBar() KeyboardStep = 1, Current = sliderBarValue }, + new SpriteText + { + Text = "w/ Nub:", + }, + sliderBarWithNub = new TestSliderBarWithNub + { + Size = new Vector2(200, 10), + BackgroundColour = Color4.White, + SelectionColour = Color4.Pink, + KeyboardStep = 1, + Current = sliderBarValue + }, } }); } @@ -202,6 +218,43 @@ public void TestTransferValueOnCommit(bool disabled) checkValue(-5, disabled); } + [Test] + public void TestAbsoluteDrag() + { + checkValue(0, false); + AddStep("Move Cursor", + () => { InputManager.MoveMouseTo(sliderBarWithNub.ToScreenSpace(sliderBarWithNub.DrawSize * new Vector2(0.1f, 0.5f))); }); + AddStep("Click", () => { InputManager.PressButton(MouseButton.Left); }); + AddStep("Drag", + () => { InputManager.MoveMouseTo(sliderBarWithNub.ToScreenSpace(sliderBarWithNub.DrawSize * new Vector2(0.4f, 1f))); }); + AddStep("Release Click", () => { InputManager.ReleaseButton(MouseButton.Left); }); + checkValue(-2, false); + } + + [Test] + public void TestRelativeDrag() + { + checkValue(0, false); + AddStep("Move Cursor", + () => { InputManager.MoveMouseTo(sliderBarWithNub.ToScreenSpace(sliderBarWithNub.DrawSize * new Vector2(0.6f, 0.5f))); }); + AddStep("Click", () => { InputManager.PressButton(MouseButton.Left); }); + AddStep("Drag", + () => { InputManager.MoveMouseTo(sliderBarWithNub.ToScreenSpace(sliderBarWithNub.DrawSize * new Vector2(0.75f, 1f))); }); + AddStep("Release Click", () => { InputManager.ReleaseButton(MouseButton.Left); }); + checkValue(3, false); + } + + [Test] + public void TestRelativeClick() + { + checkValue(0, false); + AddStep("Move Cursor", + () => { InputManager.MoveMouseTo(sliderBarWithNub.ToScreenSpace(sliderBarWithNub.DrawSize * new Vector2(0.6f, 0.5f))); }); + AddStep("Click", () => { InputManager.PressButton(MouseButton.Left); }); + AddStep("Release Click", () => { InputManager.ReleaseButton(MouseButton.Left); }); + checkValue(0, false); + } + private void checkValue(int expected, bool disabled) { if (disabled) @@ -218,5 +271,32 @@ private void sliderBarValueChanged(ValueChangedEvent args) public class TestSliderBar : BasicSliderBar { } + + public class TestSliderBarWithNub : BasicSliderBar + { + private Box nub; + + [BackgroundDependencyLoader] + private void load() + { + Add(nub = new Box + { + Colour = Color4.Blue, + Origin = Anchor.Centre, + Anchor = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Y, + RelativePositionAxes = Axes.X, + Width = 80, + }); + } + + protected override bool ShouldHandleAsRelativeDrag(MouseDownEvent e) => nub.ReceivePositionalInputAt(e.ScreenSpaceMouseDownPosition); + + protected override void UpdateValue(float value) + { + base.UpdateValue(value); + nub.X = value; + } + } } } diff --git a/osu.Framework/Audio/Track/Track.cs b/osu.Framework/Audio/Track/Track.cs index 9611ced1a2..304b305aff 100644 --- a/osu.Framework/Audio/Track/Track.cs +++ b/osu.Framework/Audio/Track/Track.cs @@ -5,6 +5,7 @@ using System; using System.Threading.Tasks; using osu.Framework.Audio.Mixing; +using osu.Framework.Extensions; namespace osu.Framework.Audio.Track { @@ -13,8 +14,8 @@ public abstract class Track : AdjustableAudioComponent, ITrack, IAudioChannel public event Action? Completed; public event Action? Failed; - protected virtual void RaiseCompleted() => Completed?.Invoke(); - protected virtual void RaiseFailed() => Failed?.Invoke(); + protected void RaiseCompleted() => Completed?.Invoke(); + protected void RaiseFailed() => Failed?.Invoke(); public virtual bool IsDummyDevice => true; @@ -38,12 +39,14 @@ public virtual void Reset() /// /// Restarts this track from the while retaining adjustments. /// - public virtual void Restart() + public void Restart() => RestartAsync().WaitSafely(); + + public Task RestartAsync() => EnqueueAction(() => { Stop(); Seek(RestartPoint); Start(); - } + }); public virtual void ResetSpeedAdjustments() { @@ -82,15 +85,15 @@ public double Length /// Whether the seek was successful. public abstract bool Seek(double seek); - public virtual void Start() - { - if (IsDisposed) - throw new ObjectDisposedException(ToString(), "Can not start disposed tracks."); - } + public abstract Task SeekAsync(double seek); - public virtual void Stop() - { - } + public abstract Task StartAsync(); + + public abstract void Start(); + + public abstract Task StopAsync(); + + public abstract void Stop(); public abstract bool IsRunning { get; } diff --git a/osu.Framework/Audio/Track/TrackBass.cs b/osu.Framework/Audio/Track/TrackBass.cs index 5f1d63231b..6300889a33 100644 --- a/osu.Framework/Audio/Track/TrackBass.cs +++ b/osu.Framework/Audio/Track/TrackBass.cs @@ -220,18 +220,16 @@ protected override void UpdateState() public override bool IsDummyDevice => false; - public override void Stop() - { - base.Stop(); - - StopAsync().WaitSafely(); - } + public override void Stop() => StopAsync().WaitSafely(); - public Task StopAsync() => EnqueueAction(() => + public override Task StopAsync() { - stopInternal(); - isRunning = isPlayed = false; - }); + return EnqueueAction(() => + { + stopInternal(); + isRunning = isPlayed = false; + }); + } private void stopInternal() { @@ -251,12 +249,13 @@ private void setDirection(bool reverse) public override void Start() { - base.Start(); + if (IsDisposed) + throw new ObjectDisposedException(ToString(), "Can not start disposed tracks."); StartAsync().WaitSafely(); } - public Task StartAsync() => EnqueueAction(() => + public override Task StartAsync() => EnqueueAction(() => { if (startInternal()) isRunning = isPlayed = true; @@ -291,7 +290,7 @@ public override bool Looping public override bool Seek(double seek) => SeekAsync(seek).GetResultSafely(); - public async Task SeekAsync(double seek) + public override async Task SeekAsync(double seek) { // At this point the track may not yet be loaded which is indicated by a 0 length. // In that case we still want to return true, hence the conservative length. diff --git a/osu.Framework/Audio/Track/TrackVirtual.cs b/osu.Framework/Audio/Track/TrackVirtual.cs index f042512e6c..a03b47bd6a 100644 --- a/osu.Framework/Audio/Track/TrackVirtual.cs +++ b/osu.Framework/Audio/Track/TrackVirtual.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Threading.Tasks; using osu.Framework.Timing; namespace osu.Framework.Audio.Track @@ -34,6 +35,23 @@ public override bool Seek(double seek) return seekOffset == seek; } + public override Task SeekAsync(double seek) + { + return Task.FromResult(Seek(seek)); + } + + public override Task StartAsync() + { + Start(); + return Task.CompletedTask; + } + + public override Task StopAsync() + { + Stop(); + return Task.CompletedTask; + } + public override void Start() { if (Length == 0) diff --git a/osu.Framework/Extensions/ObjectExtensions/ObjectExtensions.cs b/osu.Framework/Extensions/ObjectExtensions/ObjectExtensions.cs index 2e819146b1..3bf2f21cfa 100644 --- a/osu.Framework/Extensions/ObjectExtensions/ObjectExtensions.cs +++ b/osu.Framework/Extensions/ObjectExtensions/ObjectExtensions.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.Diagnostics; using System.Diagnostics.CodeAnalysis; namespace osu.Framework.Extensions.ObjectExtensions @@ -20,12 +19,8 @@ public static class ObjectExtensions /// The nullable object. /// The type of the object. /// The non-nullable object corresponding to . - public static T AsNonNull(this T? obj) - where T : class - { - Debug.Assert(obj != null); - return obj; - } + [return: NotNullIfNotNull("obj")] + public static T AsNonNull(this T? obj) => obj!; /// /// If the given object is null. diff --git a/osu.Framework/Graphics/Audio/DrawableTrack.cs b/osu.Framework/Graphics/Audio/DrawableTrack.cs index 37fc052e3c..19b5f0c3d8 100644 --- a/osu.Framework/Graphics/Audio/DrawableTrack.cs +++ b/osu.Framework/Graphics/Audio/DrawableTrack.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Threading.Tasks; using osu.Framework.Audio; using osu.Framework.Audio.Mixing; using osu.Framework.Audio.Track; @@ -93,6 +94,14 @@ public void ResetSpeedAdjustments() RemoveAllAdjustments(AdjustableProperty.Tempo); } + public Task RestartAsync() => track.RestartAsync(); + + public Task SeekAsync(double seek) => track.SeekAsync(seek); + + public Task StartAsync() => track.StartAsync(); + + public Task StopAsync() => track.StopAsync(); + public bool Seek(double seek) => track.Seek(seek); public void Start() => track.Start(); diff --git a/osu.Framework/Graphics/Textures/TextureLoaderStore.cs b/osu.Framework/Graphics/Textures/TextureLoaderStore.cs index 991b578ee7..d719402d5b 100644 --- a/osu.Framework/Graphics/Textures/TextureLoaderStore.cs +++ b/osu.Framework/Graphics/Textures/TextureLoaderStore.cs @@ -19,13 +19,13 @@ namespace osu.Framework.Graphics.Textures /// public class TextureLoaderStore : IResourceStore { - private IResourceStore store { get; } + private readonly ResourceStore store; public TextureLoaderStore(IResourceStore store) { - this.store = store; - (store as ResourceStore)?.AddExtension(@"png"); - (store as ResourceStore)?.AddExtension(@"jpg"); + this.store = new ResourceStore(store); + this.store.AddExtension(@"png"); + this.store.AddExtension(@"jpg"); } public Task GetAsync(string name, CancellationToken cancellationToken = default) => diff --git a/osu.Framework/Graphics/Transforms/Transformable.cs b/osu.Framework/Graphics/Transforms/Transformable.cs index ca697b0217..ca62a1f8c0 100644 --- a/osu.Framework/Graphics/Transforms/Transformable.cs +++ b/osu.Framework/Graphics/Transforms/Transformable.cs @@ -42,7 +42,7 @@ public abstract class Transformable : ITransformable /// /// A lazily-initialized list of s applied to this object. /// - public IEnumerable Transforms => targetGroupingTrackers.SelectMany(t => t.Transforms); + public IEnumerable Transforms => targetGroupingTrackers?.SelectMany(t => t.Transforms) ?? Array.Empty(); /// /// Retrieves the s for a given target member. @@ -63,13 +63,16 @@ public double LatestTransformEndTime //expiry should happen either at the end of the last transform or using the current sequence delay (whichever is highest). double max = TransformStartTime; - foreach (var tracker in targetGroupingTrackers) + if (targetGroupingTrackers != null) { - for (int i = 0; i < tracker.Transforms.Count; i++) + foreach (var tracker in targetGroupingTrackers) { - var t = tracker.Transforms[i]; - if (t.EndTime > max) - max = t.EndTime + 1; //adding 1ms here ensures we can expire on the current frame without issue. + for (int i = 0; i < tracker.Transforms.Count; i++) + { + var t = tracker.Transforms[i]; + if (t.EndTime > max) + max = t.EndTime + 1; //adding 1ms here ensures we can expire on the current frame without issue. + } } } @@ -88,19 +91,26 @@ public double LatestTransformEndTime protected void UpdateTransforms() { TransformDelay = 0; + + if (targetGroupingTrackers == null) + return; + updateTransforms(Time.Current); } private double lastUpdateTransformsTime; - private readonly List targetGroupingTrackers = new List(); + private List targetGroupingTrackers; private TargetGroupingTransformTracker getTrackerFor(string targetMember) { - foreach (var t in targetGroupingTrackers) + if (targetGroupingTrackers != null) { - if (t.TargetMembers.Contains(targetMember)) - return t; + foreach (var t in targetGroupingTrackers) + { + if (t.TargetMembers.Contains(targetMember)) + return t; + } } return null; @@ -108,17 +118,23 @@ private TargetGroupingTransformTracker getTrackerFor(string targetMember) private TargetGroupingTransformTracker getTrackerForGrouping(string targetGrouping, bool createIfNotExisting) { - foreach (var t in targetGroupingTrackers) + if (targetGroupingTrackers != null) { - if (t.TargetGrouping == targetGrouping) - return t; + foreach (var t in targetGroupingTrackers) + { + if (t.TargetGrouping == targetGrouping) + return t; + } } if (!createIfNotExisting) return null; var tracker = new TargetGroupingTransformTracker(this, targetGrouping); + + targetGroupingTrackers ??= new List(); targetGroupingTrackers.Add(tracker); + return tracker; } @@ -130,6 +146,9 @@ private TargetGroupingTransformTracker getTrackerForGrouping(string targetGroupi /// Whether prior transforms should be reprocessed even if a rewind was not detected. private void updateTransforms(double time, bool forceRewindReprocess = false) { + if (targetGroupingTrackers == null) + return; + bool rewinding = lastUpdateTransformsTime > time || forceRewindReprocess; lastUpdateTransformsTime = time; @@ -177,6 +196,9 @@ public virtual void ClearTransforms(bool propagateChildren = false, string targe /// public virtual void ClearTransformsAfter(double time, bool propagateChildren = false, string targetMember = null) { + if (targetGroupingTrackers == null) + return; + EnsureTransformMutationAllowed(); if (targetMember != null) @@ -218,6 +240,9 @@ public virtual void ApplyTransformsAt(double time, bool propagateChildren = fals /// public virtual void FinishTransforms(bool propagateChildren = false, string targetMember = null) { + if (targetGroupingTrackers == null) + return; + EnsureTransformMutationAllowed(); if (targetMember != null) diff --git a/osu.Framework/Graphics/UserInterface/BasicDirectorySelector.cs b/osu.Framework/Graphics/UserInterface/BasicDirectorySelector.cs index da90af9a67..8df34c0055 100644 --- a/osu.Framework/Graphics/UserInterface/BasicDirectorySelector.cs +++ b/osu.Framework/Graphics/UserInterface/BasicDirectorySelector.cs @@ -5,6 +5,7 @@ using System.IO; using osu.Framework.Graphics.Containers; +using osuTK; namespace osu.Framework.Graphics.UserInterface { @@ -12,6 +13,13 @@ public class BasicDirectorySelector : DirectorySelector { protected override DirectorySelectorBreadcrumbDisplay CreateBreadcrumb() => new BasicDirectorySelectorBreadcrumbDisplay(); + protected override Drawable CreateHiddenToggleButton() => new BasicButton + { + Size = new Vector2(200, 25), + Text = "Toggle hidden items", + Action = ShowHiddenItems.Toggle, + }; + protected override DirectorySelectorDirectory CreateDirectoryItem(DirectoryInfo directory, string displayName = null) => new BasicDirectorySelectorDirectory(directory, displayName); protected override DirectorySelectorDirectory CreateParentDirectoryItem(DirectoryInfo directory) => new BasicDirectorySelectorParentDirectory(directory); diff --git a/osu.Framework/Graphics/UserInterface/BasicDirectorySelectorBreadcrumbDisplay.cs b/osu.Framework/Graphics/UserInterface/BasicDirectorySelectorBreadcrumbDisplay.cs index 0ee0a5abcf..e4abb0f8b0 100644 --- a/osu.Framework/Graphics/UserInterface/BasicDirectorySelectorBreadcrumbDisplay.cs +++ b/osu.Framework/Graphics/UserInterface/BasicDirectorySelectorBreadcrumbDisplay.cs @@ -49,6 +49,11 @@ public BreadcrumbDisplayDirectory(DirectoryInfo directory, string displayName = { } + // this method is suppressed to ensure the breadcrumbs of hidden directories are presented the same way as non-hidden directories + protected sealed override void ApplyHiddenState() + { + } + [BackgroundDependencyLoader] private void load() { diff --git a/osu.Framework/Graphics/UserInterface/BasicDirectorySelectorParentDirectory.cs b/osu.Framework/Graphics/UserInterface/BasicDirectorySelectorParentDirectory.cs index 276069fef8..6a8f743c41 100644 --- a/osu.Framework/Graphics/UserInterface/BasicDirectorySelectorParentDirectory.cs +++ b/osu.Framework/Graphics/UserInterface/BasicDirectorySelectorParentDirectory.cs @@ -16,5 +16,10 @@ public BasicDirectorySelectorParentDirectory(DirectoryInfo directory) : base(directory, "..") { } + + // this method is suppressed to ensure that parent directories that are also hidden directories are presented the same way as non-hidden parent directories + protected sealed override void ApplyHiddenState() + { + } } } diff --git a/osu.Framework/Graphics/UserInterface/BasicFileSelector.cs b/osu.Framework/Graphics/UserInterface/BasicFileSelector.cs index 468dfb47fb..d11727b384 100644 --- a/osu.Framework/Graphics/UserInterface/BasicFileSelector.cs +++ b/osu.Framework/Graphics/UserInterface/BasicFileSelector.cs @@ -6,6 +6,7 @@ using System.IO; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osuTK; namespace osu.Framework.Graphics.UserInterface { @@ -13,6 +14,13 @@ public class BasicFileSelector : FileSelector { protected override DirectorySelectorBreadcrumbDisplay CreateBreadcrumb() => new BasicDirectorySelectorBreadcrumbDisplay(); + protected override Drawable CreateHiddenToggleButton() => new BasicButton + { + Size = new Vector2(200, 25), + Text = "Toggle hidden items", + Action = ShowHiddenItems.Toggle, + }; + protected override DirectorySelectorDirectory CreateDirectoryItem(DirectoryInfo directory, string displayName = null) => new BasicDirectorySelectorDirectory(directory, displayName); protected override DirectorySelectorDirectory CreateParentDirectoryItem(DirectoryInfo directory) => new BasicDirectorySelectorParentDirectory(directory); diff --git a/osu.Framework/Graphics/UserInterface/DirectorySelector.cs b/osu.Framework/Graphics/UserInterface/DirectorySelector.cs index 3c88d1be80..9397b15edc 100644 --- a/osu.Framework/Graphics/UserInterface/DirectorySelector.cs +++ b/osu.Framework/Graphics/UserInterface/DirectorySelector.cs @@ -23,6 +23,8 @@ public abstract class DirectorySelector : CompositeDrawable { private FillFlowContainer directoryFlow; + protected readonly BindableBool ShowHiddenItems = new BindableBool(); + protected abstract ScrollContainer CreateScrollContainer(); /// @@ -30,6 +32,14 @@ public abstract class DirectorySelector : CompositeDrawable /// protected abstract DirectorySelectorBreadcrumbDisplay CreateBreadcrumb(); + /// + /// Create a button that toggles the display of hidden items. + /// + /// + /// Unless overridden, a toggle button will not be added. + /// + protected virtual Drawable CreateHiddenToggleButton() => Empty(); + protected abstract DirectorySelectorDirectory CreateDirectoryItem(DirectoryInfo directory, string displayName = null); /// @@ -71,7 +81,25 @@ private void load(GameHost gameHost) { new Drawable[] { - CreateBreadcrumb() + new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + }, + RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, + Content = new[] + { + new[] + { + CreateBreadcrumb(), + CreateHiddenToggleButton() + } + } + } }, new Drawable[] { @@ -90,7 +118,8 @@ private void load(GameHost gameHost) } }; - CurrentPath.BindValueChanged(updateDisplay, true); + ShowHiddenItems.ValueChanged += _ => updateDisplay(); + CurrentPath.BindValueChanged(_ => updateDisplay(), true); } /// @@ -100,7 +129,7 @@ private void load(GameHost gameHost) /// private bool directoryChanging; - private void updateDisplay(ValueChangedEvent directory) + private void updateDisplay() { if (directoryChanging) return; @@ -111,7 +140,7 @@ private void updateDisplay(ValueChangedEvent directory) directoryFlow.Clear(); - var newDirectory = directory.NewValue; + var newDirectory = CurrentPath.Value; bool notifyError = false; ICollection items = Array.Empty(); @@ -168,7 +197,7 @@ protected virtual bool TryGetEntriesForPath(DirectoryInfo path, out ICollection< { foreach (var dir in path.GetDirectories().OrderBy(d => d.Name)) { - if (!dir.Attributes.HasFlagFast(FileAttributes.Hidden)) + if (ShowHiddenItems.Value || !dir.Attributes.HasFlagFast(FileAttributes.Hidden)) items.Add(CreateDirectoryItem(dir)); } diff --git a/osu.Framework/Graphics/UserInterface/DirectorySelectorDirectory.cs b/osu.Framework/Graphics/UserInterface/DirectorySelectorDirectory.cs index 2b757303c9..b89a40ff89 100644 --- a/osu.Framework/Graphics/UserInterface/DirectorySelectorDirectory.cs +++ b/osu.Framework/Graphics/UserInterface/DirectorySelectorDirectory.cs @@ -3,10 +3,12 @@ #nullable disable +using System; using System.IO; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Input.Events; +using osu.Framework.Extensions.EnumExtensions; namespace osu.Framework.Graphics.UserInterface { @@ -22,6 +24,16 @@ protected DirectorySelectorDirectory(DirectoryInfo directory, string displayName : base(displayName) { Directory = directory; + + try + { + if (directory?.Attributes.HasFlagFast(FileAttributes.Hidden) == true) + ApplyHiddenState(); + } + catch (UnauthorizedAccessException) + { + // checking attributes on access-controlled directories will throw an error so we handle it here to prevent a crash + } } protected override bool OnClick(ClickEvent e) diff --git a/osu.Framework/Graphics/UserInterface/DirectorySelectorItem.cs b/osu.Framework/Graphics/UserInterface/DirectorySelectorItem.cs index 206ef1afbe..e204faf5e0 100644 --- a/osu.Framework/Graphics/UserInterface/DirectorySelectorItem.cs +++ b/osu.Framework/Graphics/UserInterface/DirectorySelectorItem.cs @@ -41,6 +41,12 @@ protected DirectorySelectorItem(string displayName = null) /// protected virtual SpriteText CreateSpriteText() => new SpriteText(); + /// + /// Called when this is a representation of a hidden item. + /// Used to customize the appearance of hidden items. + /// + protected virtual void ApplyHiddenState() => Alpha = 0.5f; + [BackgroundDependencyLoader] private void load() { diff --git a/osu.Framework/Graphics/UserInterface/FileSelector.cs b/osu.Framework/Graphics/UserInterface/FileSelector.cs index 88079f8db0..57bccd5aab 100644 --- a/osu.Framework/Graphics/UserInterface/FileSelector.cs +++ b/osu.Framework/Graphics/UserInterface/FileSelector.cs @@ -49,7 +49,7 @@ protected override bool TryGetEntriesForPath(DirectoryInfo path, out ICollection foreach (var file in files.OrderBy(d => d.Name)) { - if (!file.Attributes.HasFlagFast(FileAttributes.Hidden)) + if (ShowHiddenItems.Value || !file.Attributes.HasFlagFast(FileAttributes.Hidden)) items.Add(CreateFileItem(file)); } @@ -71,6 +71,16 @@ protected abstract class DirectoryListingFile : DirectorySelectorItem protected DirectoryListingFile(FileInfo file) { File = file; + + try + { + if (File?.Attributes.HasFlagFast(FileAttributes.Hidden) == true) + ApplyHiddenState(); + } + catch (UnauthorizedAccessException) + { + // checking attributes on access-controlled files will throw an error so we handle it here to prevent a crash + } } protected override bool OnClick(ClickEvent e) diff --git a/osu.Framework/Graphics/UserInterface/SliderBar.cs b/osu.Framework/Graphics/UserInterface/SliderBar.cs index 455ffb3695..e0a4b93cf3 100644 --- a/osu.Framework/Graphics/UserInterface/SliderBar.cs +++ b/osu.Framework/Graphics/UserInterface/SliderBar.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Globalization; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; using osuTK.Input; @@ -114,10 +115,28 @@ protected override void LoadComplete() private void updateValue() => UpdateValue(NormalizedValue); private bool handleClick; + private float? relativeValueAtMouseDown; protected override bool OnMouseDown(MouseDownEvent e) { - handleClick = true; + if (ShouldHandleAsRelativeDrag(e)) + { + float min = currentNumberInstantaneous.MinValue.ToSingle(NumberFormatInfo.InvariantInfo); + float max = currentNumberInstantaneous.MaxValue.ToSingle(NumberFormatInfo.InvariantInfo); + float val = currentNumberInstantaneous.Value.ToSingle(NumberFormatInfo.InvariantInfo); + + relativeValueAtMouseDown = (val - min) / (max - min); + + // Click shouldn't be handled if relative dragging is happening (i.e. while holding a nub). + // This is generally an expectation by most OSes and UIs. + handleClick = false; + } + else + { + handleClick = true; + relativeValueAtMouseDown = null; + } + return base.OnMouseDown(e); } @@ -151,11 +170,7 @@ protected override bool OnDragStart(DragStartEvent e) return true; } - protected override void OnDragEnd(DragEndEvent e) - { - handleMouseInput(e); - commit(); - } + protected override void OnDragEnd(DragEndEvent e) => commit(); protected override bool OnKeyDown(KeyDownEvent e) { @@ -203,14 +218,36 @@ private bool commit() return true; } - private void handleMouseInput(UIEvent e) + /// + /// Whether mouse handling should be relative to the distance travelled, or absolute in line with the exact position of the cursor. + /// + /// + /// Generally, this should be overridden and return true when the cursor is hovering a "nub" or "thumb" portion at the point of mouse down + /// to give the user more correct control. + /// + /// The mouse down event. + /// Whether to perform a relative drag. + protected virtual bool ShouldHandleAsRelativeDrag(MouseDownEvent e) => false; + + private void handleMouseInput(MouseButtonEvent e) { - float xPosition = ToLocalSpace(e.ScreenSpaceMousePosition).X - RangePadding; - if (currentNumberInstantaneous.Disabled) return; - currentNumberInstantaneous.SetProportional(xPosition / UsableWidth, e.ShiftPressed ? KeyboardStep : 0); + float localX = ToLocalSpace(e.ScreenSpaceMousePosition).X; + + float newValue; + + if (relativeValueAtMouseDown != null && e is DragEvent drag) + { + newValue = relativeValueAtMouseDown.Value + (localX - ToLocalSpace(drag.ScreenSpaceMouseDownPosition).X) / UsableWidth; + } + else + { + newValue = (localX - RangePadding) / UsableWidth; + } + + currentNumberInstantaneous.SetProportional(newValue, e.ShiftPressed ? KeyboardStep : 0); onUserChange(currentNumberInstantaneous.Value); } diff --git a/osu.Framework/Graphics/Visualisation/DrawVisualiser.cs b/osu.Framework/Graphics/Visualisation/DrawVisualiser.cs index 65b2f0271f..17e50aa87b 100644 --- a/osu.Framework/Graphics/Visualisation/DrawVisualiser.cs +++ b/osu.Framework/Graphics/Visualisation/DrawVisualiser.cs @@ -37,6 +37,8 @@ public Vector2 ToolPosition private readonly InfoOverlay overlay; private InputManager inputManager; + protected override bool BlockPositionalInput => Searching; + public DrawVisualiser() { RelativeSizeAxes = Axes.Both; @@ -319,8 +321,6 @@ private void setHighlight(VisualisedDrawable newHighlight) } } - protected override bool OnMouseDown(MouseDownEvent e) => Searching; - protected override bool OnClick(ClickEvent e) { if (Searching) diff --git a/osu.Framework/Input/Handlers/Joystick/JoystickHandler.cs b/osu.Framework/Input/Handlers/Joystick/JoystickHandler.cs index cf8c7c2c21..ae5a7cc760 100644 --- a/osu.Framework/Input/Handlers/Joystick/JoystickHandler.cs +++ b/osu.Framework/Input/Handlers/Joystick/JoystickHandler.cs @@ -20,8 +20,6 @@ public class JoystickHandler : InputHandler Precision = 0.005f, }; - private readonly JoystickButton[] axisDirectionButtons = new JoystickButton[(int)JoystickAxisSource.AxisCount]; - public override string Description => "Joystick / Gamepad"; public override bool IsActive => true; @@ -65,32 +63,9 @@ private void enqueueJoystickEvent(IInput evt) /// /// Enqueues a taking into account the axis deadzone. - /// Also enqueues events depending on whether the axis has changed direction. /// - private void enqueueJoystickAxisChanged(JoystickAxis axis) - { - float value = rescaleByDeadzone(axis.Value); - - int index = (int)axis.Source; - var currentButton = axisDirectionButtons[index]; - var expectedButton = getAxisButtonForInput(index, value); - - // if a directional button is pressed and does not match that for the new axis direction, release it - if (currentButton != 0 && expectedButton != currentButton) - { - enqueueJoystickButtonUp(currentButton); - axisDirectionButtons[index] = currentButton = 0; - } - - // if we expect a directional button to be pressed, and it is not, press it - if (expectedButton != 0 && expectedButton != currentButton) - { - enqueueJoystickButtonDown(expectedButton); - axisDirectionButtons[index] = expectedButton; - } - - enqueueJoystickEvent(new JoystickAxisInput(new JoystickAxis(axis.Source, value))); - } + private void enqueueJoystickAxisChanged(JoystickAxisSource source, float value) => + enqueueJoystickEvent(new JoystickAxisInput(new JoystickAxis(source, rescaleByDeadzone(value)))); private float rescaleByDeadzone(float axisValue) { @@ -103,16 +78,5 @@ private float rescaleByDeadzone(float axisValue) float absoluteRescaled = (absoluteValue - DeadzoneThreshold.Value) / (1f - DeadzoneThreshold.Value); return Math.Sign(axisValue) * absoluteRescaled; } - - private static JoystickButton getAxisButtonForInput(int axisIndex, float axisValue) - { - if (axisValue > 0) - return JoystickButton.FirstAxisPositive + axisIndex; - - if (axisValue < 0) - return JoystickButton.FirstAxisNegative + axisIndex; - - return 0; - } } } diff --git a/osu.Framework/Input/Handlers/Midi/MidiHandler.cs b/osu.Framework/Input/Handlers/Midi/MidiHandler.cs index 3b11085603..3b9bb5294d 100644 --- a/osu.Framework/Input/Handlers/Midi/MidiHandler.cs +++ b/osu.Framework/Input/Handlers/Midi/MidiHandler.cs @@ -216,8 +216,6 @@ private void readEvent(byte[] data, string senderId, ref int i, out byte eventTy private void dispatchEvent(byte eventType, byte key, byte velocity) { - Logger.Log($"Handling MIDI event {eventType:X2}:{key:X2}:{velocity:X2}"); - // Low nibble only contains channel data in note on/off messages // Ignore to receive messages from all channels switch (eventType & 0xF0) @@ -234,17 +232,15 @@ private void dispatchEvent(byte eventType, byte key, byte velocity) break; } - void noteOff() + void noteOn() { - Logger.Log($"NoteOff: {(MidiKey)key}/{velocity / 128f:P}"); - PendingInputs.Enqueue(new MidiKeyInput((MidiKey)key, 0, false)); + PendingInputs.Enqueue(new MidiKeyInput((MidiKey)key, velocity, true)); FrameStatistics.Increment(StatisticsCounterType.MidiEvents); } - void noteOn() + void noteOff() { - Logger.Log($"NoteOn: {(MidiKey)key}/{velocity / 128f:P}"); - PendingInputs.Enqueue(new MidiKeyInput((MidiKey)key, velocity, true)); + PendingInputs.Enqueue(new MidiKeyInput((MidiKey)key, 0, false)); FrameStatistics.Increment(StatisticsCounterType.MidiEvents); } } diff --git a/osu.Framework/Input/StateChanges/JoystickAxisInput.cs b/osu.Framework/Input/StateChanges/JoystickAxisInput.cs index 08042c4a84..ea62274c60 100644 --- a/osu.Framework/Input/StateChanges/JoystickAxisInput.cs +++ b/osu.Framework/Input/StateChanges/JoystickAxisInput.cs @@ -43,9 +43,46 @@ public void Apply(InputState state, IInputStateChangeHandler handler) if (oldValue == a.Value || (a.Value != 0 && Precision.AlmostEquals(oldValue, a.Value))) continue; + applyButtonInputsIfNeeded(state, handler, a); + state.Joystick.AxesValues[(int)a.Source] = a.Value; handler.HandleInputStateChange(new JoystickAxisChangeEvent(state, this, a, oldValue)); } } + + /// + /// Applies events depending on whether the axis has changed direction. + /// + private void applyButtonInputsIfNeeded(InputState state, IInputStateChangeHandler handler, JoystickAxis axis) + { + int index = (int)axis.Source; + var currentButton = state.Joystick.AxisDirectionButtons[index]; + var expectedButton = getAxisButtonForInput(index, axis.Value); + + // if a directional button is pressed and does not match that for the new axis direction, release it + if (currentButton != 0 && expectedButton != currentButton) + { + new JoystickButtonInput(currentButton, false).Apply(state, handler); + state.Joystick.AxisDirectionButtons[index] = currentButton = 0; + } + + // if we expect a directional button to be pressed, and it is not, press it + if (expectedButton != 0 && expectedButton != currentButton) + { + new JoystickButtonInput(expectedButton, true).Apply(state, handler); + state.Joystick.AxisDirectionButtons[index] = expectedButton; + } + } + + private static JoystickButton getAxisButtonForInput(int axisIndex, float axisValue) + { + if (axisValue > 0) + return JoystickButton.FirstAxisPositive + axisIndex; + + if (axisValue < 0) + return JoystickButton.FirstAxisNegative + axisIndex; + + return 0; + } } } diff --git a/osu.Framework/Input/States/JoystickState.cs b/osu.Framework/Input/States/JoystickState.cs index 92b021043c..6c3c356652 100644 --- a/osu.Framework/Input/States/JoystickState.cs +++ b/osu.Framework/Input/States/JoystickState.cs @@ -19,6 +19,11 @@ public class JoystickState /// public readonly float[] AxesValues = new float[MAX_AXES]; + /// + /// Currently simulated for each . 0 if no button press is simulated. + /// + internal readonly JoystickButton[] AxisDirectionButtons = new JoystickButton[MAX_AXES]; + /// /// Retrieves all with their current value (regardless of inactive ones). /// diff --git a/osu.Framework/Platform/NativeStorage.cs b/osu.Framework/Platform/NativeStorage.cs index f495325dbd..70f86f7d17 100644 --- a/osu.Framework/Platform/NativeStorage.cs +++ b/osu.Framework/Platform/NativeStorage.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using JetBrains.Annotations; +using osu.Framework.Utils; namespace osu.Framework.Platform { @@ -42,7 +43,12 @@ public override void Delete(string path) File.Delete(path); } - public override void Move(string from, string to) => File.Move(GetFullPath(from), GetFullPath(to)); + public override void Move(string from, string to) + { + // Retry move operations as it can fail on windows intermittently with IOExceptions: + // The process cannot access the file because it is being used by another process. + General.AttemptWithRetryOnException(() => File.Move(GetFullPath(from), GetFullPath(to))); + } public override IEnumerable GetDirectories(string path) => getRelativePaths(Directory.GetDirectories(GetFullPath(path))); diff --git a/osu.Framework/Platform/SDL2DesktopWindow.cs b/osu.Framework/Platform/SDL2DesktopWindow.cs index c49dc52cc3..589acabec2 100644 --- a/osu.Framework/Platform/SDL2DesktopWindow.cs +++ b/osu.Framework/Platform/SDL2DesktopWindow.cs @@ -629,7 +629,7 @@ private void enqueueJoystickAxisInput(JoystickAxisSource axisSource, short axisV { // SDL reports axis values in the range short.MinValue to short.MaxValue, so we scale and clamp it to the range of -1f to 1f float clamped = Math.Clamp((float)axisValue / short.MaxValue, -1f, 1f); - JoystickAxisChanged?.Invoke(new JoystickAxis(axisSource, clamped)); + JoystickAxisChanged?.Invoke(axisSource, clamped); } private void enqueueJoystickButtonInput(JoystickButton button, bool isPressed) @@ -1619,7 +1619,7 @@ private static Display displayFromSDL(int displayIndex) /// /// Invoked when a joystick axis changes. /// - public event Action JoystickAxisChanged; + public event Action JoystickAxisChanged; /// /// Invoked when the user presses a button on a joystick. diff --git a/osu.Framework/Testing/TestScene.cs b/osu.Framework/Testing/TestScene.cs index 052747f058..dc6be20a87 100644 --- a/osu.Framework/Testing/TestScene.cs +++ b/osu.Framework/Testing/TestScene.cs @@ -424,9 +424,12 @@ protected virtual void RunTestsFromNUnit() runner.RunTestBlocking(this); checkForErrors(); - // Force any unobserved exceptions to fire against the current test run. - // Without this they could be delayed until a future test scene is running, making tracking down the cause difficult. - collectAndFireUnobserved(); + if (Environment.GetEnvironmentVariable("OSU_TESTS_FORCED_GC") == "1") + { + // Force any unobserved exceptions to fire against the current test run. + // Without this they could be delayed until a future test scene is running, making tracking down the cause difficult. + collectAndFireUnobserved(); + } } [OneTimeTearDown] diff --git a/osu.Framework/Threading/ScheduledDelegate.cs b/osu.Framework/Threading/ScheduledDelegate.cs index 2b92c297f5..a383e27e24 100644 --- a/osu.Framework/Threading/ScheduledDelegate.cs +++ b/osu.Framework/Threading/ScheduledDelegate.cs @@ -37,7 +37,7 @@ public class ScheduledDelegate : IComparable /// public bool Cancelled => State == RunState.Cancelled; - public RunState State; + public RunState State { get; private set; } /// /// The work task. diff --git a/osu.Framework/Threading/Scheduler.cs b/osu.Framework/Threading/Scheduler.cs index a0cae318e8..112172bc8c 100644 --- a/osu.Framework/Threading/Scheduler.cs +++ b/osu.Framework/Threading/Scheduler.cs @@ -100,20 +100,29 @@ public void UpdateClock(IClock newClock) /// Run any pending work tasks. /// /// The number of tasks that were run. - public virtual int Update() + public int Update() { - lock (queueLock) + bool hasTimedTasks = timedTasks.Count > 0; + bool hasPerUpdateTasks = perUpdateTasks.Count > 0; + + if (hasTimedTasks || hasPerUpdateTasks) // avoid taking out a lock if there are no items. { - queueTimedTasks(); - queuePerUpdateTasks(); + lock (queueLock) + { + queueTimedTasks(); + queuePerUpdateTasks(); + } } int countToRun = runQueue.Count; + + if (countToRun == 0) + return 0; // avoid taking out a lock via getNextTask() if there are no items. + int countRun = 0; while (getNextTask(out ScheduledDelegate sd)) { - //todo: error handling sd.RunTaskInternal(); TotalTasksRun++; @@ -127,10 +136,11 @@ public virtual int Update() private void queueTimedTasks() { - double currentTimeLocal = currentTime; - - if (timedTasks.Count > 0) + // Already checked before this method is called, but helps with path prediction? + if (timedTasks.Count != 0) { + double currentTimeLocal = currentTime; + foreach (var sd in timedTasks) { if (sd.ExecutionTime <= currentTimeLocal) @@ -174,19 +184,23 @@ private void queueTimedTasks() private void queuePerUpdateTasks() { - for (int i = 0; i < perUpdateTasks.Count; i++) + // Already checked before this method is called, but helps with path prediction? + if (perUpdateTasks.Count != 0) { - ScheduledDelegate task = perUpdateTasks[i]; + for (int i = 0; i < perUpdateTasks.Count; i++) + { + ScheduledDelegate task = perUpdateTasks[i]; - task.SetNextExecution(null); + task.SetNextExecution(null); - if (task.Cancelled) - { - perUpdateTasks.RemoveAt(i--); - continue; - } + if (task.Cancelled) + { + perUpdateTasks.RemoveAt(i--); + continue; + } - enqueue(task); + enqueue(task); + } } } diff --git a/osu.Framework/Utils/Blur.cs b/osu.Framework/Utils/Blur.cs index 59609b0c21..863ff24ac2 100644 --- a/osu.Framework/Utils/Blur.cs +++ b/osu.Framework/Utils/Blur.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; namespace osu.Framework.Utils diff --git a/osu.Framework/Utils/ConvexPolygonClipper.cs b/osu.Framework/Utils/ConvexPolygonClipper.cs index fd84c6d203..a0de4e79e7 100644 --- a/osu.Framework/Utils/ConvexPolygonClipper.cs +++ b/osu.Framework/Utils/ConvexPolygonClipper.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.Runtime.CompilerServices; using osu.Framework.Graphics; diff --git a/osu.Framework/Utils/General.cs b/osu.Framework/Utils/General.cs new file mode 100644 index 0000000000..a06d476c26 --- /dev/null +++ b/osu.Framework/Utils/General.cs @@ -0,0 +1,51 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Threading; +using osu.Framework.Logging; + +namespace osu.Framework.Utils +{ + public static class General + { + /// + /// Attempt an operation and perform retries on a matching exception, up to a limit. + /// Useful for IO operations which can fail for a short period due to an open file handle. + /// + /// The action to perform. + /// The number of attempts (250ms wait between each). + /// Whether to throw an exception on failure. If false, will silently fail. + /// The type of exception which should trigger retries. + /// Whether the operation succeeded. + public static bool AttemptWithRetryOnException(this Action action, int attempts = 10, bool throwOnFailure = true) + where TException : Exception + { + while (true) + { + try + { + action(); + return true; + } + catch (Exception e) + { + if (e is not TException) + throw; + + if (attempts-- == 0) + { + if (throwOnFailure) + throw; + + return false; + } + + Logger.Log($"Operation failed ({e.Message}). Retrying {attempts} more times..."); + } + + Thread.Sleep(250); + } + } + } +} diff --git a/osu.Framework/Utils/HasOrderedElementsAttribute.cs b/osu.Framework/Utils/HasOrderedElementsAttribute.cs index c0c15c3115..24d1fcadad 100644 --- a/osu.Framework/Utils/HasOrderedElementsAttribute.cs +++ b/osu.Framework/Utils/HasOrderedElementsAttribute.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 osu.Framework.Extensions.EnumExtensions; diff --git a/osu.Framework/Utils/IInterpolable.cs b/osu.Framework/Utils/IInterpolable.cs index a571516cf0..aeca0b5919 100644 --- a/osu.Framework/Utils/IInterpolable.cs +++ b/osu.Framework/Utils/IInterpolable.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.Transforms; namespace osu.Framework.Utils diff --git a/osu.Framework/Utils/Interpolation.cs b/osu.Framework/Utils/Interpolation.cs index e547f97414..3e434835c9 100644 --- a/osu.Framework/Utils/Interpolation.cs +++ b/osu.Framework/Utils/Interpolation.cs @@ -1,11 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Linq; -using System.Reflection; using System.Runtime.Serialization; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -384,9 +381,10 @@ static GenericInterpolation() var parameters = typeof(InterpolationFunc) .GetMethod(nameof(InterpolationFunc.Invoke)) - ?.GetParameters().Select(p => p.ParameterType).ToArray(); + ?.GetParameters().Select(p => p.ParameterType).ToArray() + ?? Array.Empty(); - MethodInfo valueAtMethod = typeof(GenericInterpolation).GetMethod(interpolation_method, parameters); + var valueAtMethod = typeof(GenericInterpolation).GetMethod(interpolation_method, parameters); if (valueAtMethod != null) FUNCTION = (InterpolationFunc)valueAtMethod.CreateDelegate(typeof(InterpolationFunc)); diff --git a/osu.Framework/Utils/MathUtils.cs b/osu.Framework/Utils/MathUtils.cs index 52536df5ae..77136b329e 100644 --- a/osu.Framework/Utils/MathUtils.cs +++ b/osu.Framework/Utils/MathUtils.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; namespace osu.Framework.Utils diff --git a/osu.Framework/Utils/NumberFormatter.cs b/osu.Framework/Utils/NumberFormatter.cs index 8bd52d90b6..57966f3623 100644 --- a/osu.Framework/Utils/NumberFormatter.cs +++ b/osu.Framework/Utils/NumberFormatter.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; namespace osu.Framework.Utils diff --git a/osu.Framework/Utils/OrderAttribute.cs b/osu.Framework/Utils/OrderAttribute.cs index 45a74755cc..e30aa7dd94 100644 --- a/osu.Framework/Utils/OrderAttribute.cs +++ b/osu.Framework/Utils/OrderAttribute.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 osu.Framework.Extensions.EnumExtensions; diff --git a/osu.Framework/Utils/PathApproximator.cs b/osu.Framework/Utils/PathApproximator.cs index 7e6a6d653b..2420423556 100644 --- a/osu.Framework/Utils/PathApproximator.cs +++ b/osu.Framework/Utils/PathApproximator.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.Linq; diff --git a/osu.Framework/Utils/Precision.cs b/osu.Framework/Utils/Precision.cs index 6b2f99556e..7a35bb26e0 100644 --- a/osu.Framework/Utils/Precision.cs +++ b/osu.Framework/Utils/Precision.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 osuTK; using System; using osu.Framework.Graphics.Primitives; diff --git a/osu.Framework/Utils/RNG.cs b/osu.Framework/Utils/RNG.cs index c43339a725..6a81f837d3 100644 --- a/osu.Framework/Utils/RNG.cs +++ b/osu.Framework/Utils/RNG.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; namespace osu.Framework.Utils