diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 56b3ebe87b..213c5082ab 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -31,7 +31,7 @@ jobs:
run: dotnet tool restore
- name: Restore Packages
- run: dotnet restore
+ run: dotnet restore osu.Desktop.slnf
- name: Restore inspectcode cache
uses: actions/cache@v3
@@ -113,27 +113,36 @@ jobs:
with:
dotnet-version: "6.0.x"
- - name: Setup MSBuild
- uses: microsoft/setup-msbuild@v1
+ - name: Install .NET workloads
+ run: dotnet workload install maui-android
- - name: Build
- run: msbuild osu.Android/osu.Android.csproj /restore /p:Configuration=Debug
+ - name: Compile
+ run: dotnet build -c Debug osu.Android.slnf
build-only-ios:
name: Build only (iOS)
- runs-on: macos-latest
+ # change to macos-latest once GitHub finishes migrating all repositories to macOS 12.
+ runs-on: macos-12
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@v2
+ # see https://github.com/actions/runner-images/issues/6771#issuecomment-1354713617
+ # remove once all workflow VMs use Xcode 14.1
+ - name: Set Xcode Version
+ shell: bash
+ run: |
+ sudo xcode-select -s "/Applications/Xcode_14.1.app"
+ echo "MD_APPLE_SDK_ROOT=/Applications/Xcode_14.1.app" >> $GITHUB_ENV
+
- name: Install .NET 6.0.x
uses: actions/setup-dotnet@v1
with:
dotnet-version: "6.0.x"
- # Contrary to seemingly any other msbuild, msbuild running on macOS/Mono
- # cannot accept .sln(f) files as arguments.
- # Build just the main game for now.
+ - name: Install .NET Workloads
+ run: dotnet workload install maui-ios
+
- name: Build
- run: msbuild osu.iOS/osu.iOS.csproj /restore /p:Configuration=Debug
+ run: dotnet build -c Debug osu.iOS
diff --git a/README.md b/README.md
index 75d61dad4d..0de82eba75 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ If you are looking to install or test osu! without setting up a development envi
**Latest build:**
-| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | macOS 10.15+ ([Intel](https://github.com/ppy/osu/releases/latest/download/osu.app.Intel.zip), [Apple Silicon](https://github.com/ppy/osu/releases/latest/download/osu.app.Apple.Silicon.zip)) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 10+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) |
+| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | macOS 10.15+ ([Intel](https://github.com/ppy/osu/releases/latest/download/osu.app.Intel.zip), [Apple Silicon](https://github.com/ppy/osu/releases/latest/download/osu.app.Apple.Silicon.zip)) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 13.4+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) |
| ------------- | ------------- | ------------- | ------------- | ------------- |
- The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets.
diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/osu.Game.Rulesets.EmptyFreeform.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/osu.Game.Rulesets.EmptyFreeform.csproj
index 092a013614..d09e7647e0 100644
--- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/osu.Game.Rulesets.EmptyFreeform.csproj
+++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/osu.Game.Rulesets.EmptyFreeform.csproj
@@ -1,6 +1,6 @@
- netstandard2.1
+ net6.0
osu.Game.Rulesets.EmptyFreeform
Library
AnyCPU
@@ -12,4 +12,4 @@
-
\ No newline at end of file
+
diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/osu.Game.Rulesets.Pippidon.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/osu.Game.Rulesets.Pippidon.csproj
index a3607343c9..9c8867f4ef 100644
--- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/osu.Game.Rulesets.Pippidon.csproj
+++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/osu.Game.Rulesets.Pippidon.csproj
@@ -1,6 +1,6 @@
- netstandard2.1
+ net6.0
osu.Game.Rulesets.Pippidon
Library
AnyCPU
@@ -12,4 +12,4 @@
-
\ No newline at end of file
+
diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/osu.Game.Rulesets.EmptyScrolling.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/osu.Game.Rulesets.EmptyScrolling.csproj
index 2ea52429ab..5bf3884f53 100644
--- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/osu.Game.Rulesets.EmptyScrolling.csproj
+++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/osu.Game.Rulesets.EmptyScrolling.csproj
@@ -1,6 +1,6 @@
- netstandard2.1
+ net6.0
osu.Game.Rulesets.EmptyScrolling
Library
AnyCPU
@@ -12,4 +12,4 @@
-
\ No newline at end of file
+
diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/osu.Game.Rulesets.Pippidon.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/osu.Game.Rulesets.Pippidon.csproj
index a3607343c9..9c8867f4ef 100644
--- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/osu.Game.Rulesets.Pippidon.csproj
+++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/osu.Game.Rulesets.Pippidon.csproj
@@ -1,6 +1,6 @@
- netstandard2.1
+ net6.0
osu.Game.Rulesets.Pippidon
Library
AnyCPU
@@ -12,4 +12,4 @@
-
\ No newline at end of file
+
diff --git a/appveyor.yml b/appveyor.yml
index 5be73f9875..ed48a997e8 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,6 +1,6 @@
clone_depth: 1
version: '{branch}-{build}'
-image: Visual Studio 2019
+image: Visual Studio 2022
cache:
- '%LOCALAPPDATA%\NuGet\v3-cache -> appveyor.yml'
@@ -11,6 +11,8 @@ dotnet_csproj:
before_build:
- cmd: dotnet --info # Useful when version mismatch between CI and local
+ - cmd: dotnet workload install maui-android # Change to `dotnet workload restore` once there's no old projects
+ - cmd: dotnet workload install maui-ios # Change to `dotnet workload restore` once there's no old projects
- cmd: nuget restore -verbosity quiet # Only nuget.exe knows both new (.NET Core) and old (Xamarin) projects
build:
diff --git a/osu.Android.props b/osu.Android.props
index 147d236d98..e934b2da6a 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -1,64 +1,20 @@
- 8.0
- bin\$(Configuration)
- 4
- 2.0
- false
- false
- Library
- 512
- Off
- True
- Xamarin.Android.Net.AndroidClientHandler
- v10.0
- false
- true
- armeabi-v7a;x86;arm64-v8a
- true
- cjk,mideast,other,rare,west
- SdkOnly
- prompt
-
-
- True
- portable
- False
- DEBUG;TRACE
- false
- true
- false
-
-
- false
- None
- True
- false
- False
+ 21.0
+ android-x86;android-arm;android-arm64
+ apk
+ CJK;Mideast;Rare;West;Other;
+ Xamarin.Android.Net.AndroidMessageHandler
+
+ true
true
-
- osu.licenseheader
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ true
+
diff --git a/osu.Android/Properties/AndroidManifest.xml b/osu.Android/AndroidManifest.xml
similarity index 95%
rename from osu.Android/Properties/AndroidManifest.xml
rename to osu.Android/AndroidManifest.xml
index 165a64a424..be326be5eb 100644
--- a/osu.Android/Properties/AndroidManifest.xml
+++ b/osu.Android/AndroidManifest.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/osu.Android/Linker.xml b/osu.Android/Linker.xml
deleted file mode 100644
index c7d31fe087..0000000000
--- a/osu.Android/Linker.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs
index be40db7508..ca3d628447 100644
--- a/osu.Android/OsuGameActivity.cs
+++ b/osu.Android/OsuGameActivity.cs
@@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Reflection;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
@@ -74,11 +75,23 @@ namespace osu.Android
Debug.Assert(Resources?.DisplayMetrics != null);
Point displaySize = new Point();
+#pragma warning disable 618 // GetSize is deprecated
WindowManager.DefaultDisplay.GetSize(displaySize);
+#pragma warning restore 618
float smallestWidthDp = Math.Min(displaySize.X, displaySize.Y) / Resources.DisplayMetrics.Density;
bool isTablet = smallestWidthDp >= 600f;
RequestedOrientation = DefaultOrientation = isTablet ? ScreenOrientation.FullUser : ScreenOrientation.SensorLandscape;
+
+ // Currently (SDK 6.0.200), BundleAssemblies is not runnable for net6-android.
+ // The assembly files are not available as files either after native AOT.
+ // Manually load them so that they can be loaded by RulesetStore.loadFromAppDomain.
+ // REMEMBER to fully uninstall previous version every time when investigating this!
+ // Don't forget osu.Game.Tests.Android too.
+ Assembly.Load("osu.Game.Rulesets.Osu");
+ Assembly.Load("osu.Game.Rulesets.Taiko");
+ Assembly.Load("osu.Game.Rulesets.Catch");
+ Assembly.Load("osu.Game.Rulesets.Mania");
}
protected override void OnNewIntent(Intent intent) => handleIntent(intent);
@@ -127,7 +140,7 @@ namespace osu.Android
cursor.MoveToFirst();
- int filenameColumn = cursor.GetColumnIndex(OpenableColumns.DisplayName);
+ int filenameColumn = cursor.GetColumnIndex(IOpenableColumns.DisplayName);
string filename = cursor.GetString(filenameColumn);
// SharpCompress requires archive streams to be seekable, which the stream opened by
diff --git a/osu.Android/OsuGameAndroid.cs b/osu.Android/OsuGameAndroid.cs
index 1c6f41a7ec..0227d2aec2 100644
--- a/osu.Android/OsuGameAndroid.cs
+++ b/osu.Android/OsuGameAndroid.cs
@@ -5,7 +5,7 @@
using System;
using Android.App;
-using Android.OS;
+using Microsoft.Maui.Devices;
using osu.Framework.Allocation;
using osu.Framework.Android.Input;
using osu.Framework.Input.Handlers;
@@ -14,7 +14,6 @@ using osu.Game;
using osu.Game.Overlays.Settings;
using osu.Game.Updater;
using osu.Game.Utils;
-using Xamarin.Essentials;
namespace osu.Android
{
@@ -48,7 +47,7 @@ namespace osu.Android
// https://stackoverflow.com/questions/52977079/android-sdk-28-versioncode-in-packageinfo-has-been-deprecated
string versionName = string.Empty;
- if (Build.VERSION.SdkInt >= BuildVersionCodes.P)
+ if (OperatingSystem.IsAndroidVersionAtLeast(28))
{
versionName = packageInfo.LongVersionCode.ToString();
// ensure we only read the trailing portion of long (the part we are interested in).
diff --git a/osu.Android/osu.Android.csproj b/osu.Android/osu.Android.csproj
index 004cc8c39c..de53e5dd59 100644
--- a/osu.Android/osu.Android.csproj
+++ b/osu.Android/osu.Android.csproj
@@ -1,73 +1,19 @@
-
-
+
- Debug
- AnyCPU
- 8.0.30703
- 2.0
- {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}
- {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- {122416d6-6b49-4ee2-a1e8-b825f31c79fe}
+ net6.0-android
+ Exe
osu.Android
osu.Android
- Properties\AndroidManifest.xml
- armeabi-v7a;x86;arm64-v8a
- false
-
-
- cjk;mideast;other;rare;west
- d8
- r8
-
-
- None
- cjk;mideast;other;rare;west
- true
+ true
+
+ false
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
- {58f6c80c-1253-4a0e-a465-b8c85ebeadf3}
- osu.Game.Rulesets.Catch
-
-
- {48f4582b-7687-4621-9cbe-5c24197cb536}
- osu.Game.Rulesets.Mania
-
-
- {c92a607b-1fdd-4954-9f92-03ff547d9080}
- osu.Game.Rulesets.Osu
-
-
- {f167e17a-7de6-4af5-b920-a5112296c695}
- osu.Game.Rulesets.Taiko
-
-
- {2a66dd92-adb1-4994-89e2-c94e04acda0d}
- osu.Game
-
-
-
-
-
-
-
- 5.0.0
-
-
-
-
-
-
-
\ No newline at end of file
+
diff --git a/osu.Game.Rulesets.Catch.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml
similarity index 96%
rename from osu.Game.Rulesets.Catch.Tests.Android/Properties/AndroidManifest.xml
rename to osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml
index f8c3fcd894..bf7c0bfeca 100644
--- a/osu.Game.Rulesets.Catch.Tests.Android/Properties/AndroidManifest.xml
+++ b/osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch.Tests.Android/osu.Game.Rulesets.Catch.Tests.Android.csproj b/osu.Game.Rulesets.Catch.Tests.Android/osu.Game.Rulesets.Catch.Tests.Android.csproj
index 94fdba4a3e..4ee3219442 100644
--- a/osu.Game.Rulesets.Catch.Tests.Android/osu.Game.Rulesets.Catch.Tests.Android.csproj
+++ b/osu.Game.Rulesets.Catch.Tests.Android/osu.Game.Rulesets.Catch.Tests.Android.csproj
@@ -1,49 +1,24 @@
-
-
+
- Debug
- AnyCPU
- 8.0.30703
- 2.0
- {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}
- {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- {122416d6-6b49-4ee2-a1e8-b825f31c79fe}
+ net6.0-android
+ Exe
osu.Game.Rulesets.Catch.Tests
osu.Game.Rulesets.Catch.Tests.Android
- Properties\AndroidManifest.xml
- armeabi-v7a;x86;arm64-v8a
-
-
- None
- cjk;mideast;other;rare;west
- true
-
-
-
-
-
-
-
+
%(RecursiveDir)%(Filename)%(Extension)
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+ Android\%(RecursiveDir)%(Filename)%(Extension)
+
-
- {58f6c80c-1253-4a0e-a465-b8c85ebeadf3}
- osu.Game.Rulesets.Catch
-
-
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}
- osu.Game
-
+
+
-
-
- 5.0.0
-
-
-
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs b/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs
index 71d943ece1..1fcb0aa427 100644
--- a/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs
+++ b/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs
@@ -3,7 +3,6 @@
#nullable disable
-using osu.Framework.iOS;
using UIKit;
namespace osu.Game.Rulesets.Catch.Tests.iOS
@@ -12,7 +11,7 @@ namespace osu.Game.Rulesets.Catch.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, typeof(GameUIApplication), typeof(AppDelegate));
+ UIApplication.Main(args, null, typeof(AppDelegate));
}
}
}
diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist b/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist
index 16a2b99997..5ace6c07f5 100644
--- a/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist
+++ b/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist
@@ -13,7 +13,7 @@
LSRequiresIPhoneOS
MinimumOSVersion
- 10.0
+ 13.4
UIDeviceFamily
1
diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj b/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj
index be6044bbd0..acf12bb0ac 100644
--- a/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj
+++ b/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj
@@ -1,35 +1,19 @@
-
-
+
- Debug
- iPhoneSimulator
- {4004C7B7-1A62-43F1-9DF2-52450FA67E70}
Exe
+ net6.0-ios
+ 13.4
osu.Game.Rulesets.Catch.Tests
osu.Game.Rulesets.Catch.Tests.iOS
-
-
-
- Linker.xml
-
-
-
%(RecursiveDir)%(Filename)%(Extension)
-
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}
- osu.Game
-
-
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}
- osu.Game.Rulesets.Catch
-
+
+
-
-
\ No newline at end of file
+
diff --git a/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs b/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs
index e5cdcf706c..43918bda57 100644
--- a/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs
+++ b/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs
@@ -121,9 +121,7 @@ namespace osu.Game.Rulesets.Catch.Edit
return new SnapResult(originPosition, StartTime);
}
- return enumerateSnappingCandidates(time)
- .OrderBy(pos => Vector2.DistanceSquared(screenSpacePosition, pos.ScreenSpacePosition))
- .FirstOrDefault();
+ return enumerateSnappingCandidates(time).MinBy(pos => Vector2.DistanceSquared(screenSpacePosition, pos.ScreenSpacePosition));
}
private IEnumerable enumerateSnappingCandidates(double time)
diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
index e2f95ca177..ecce7c1b3f 100644
--- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
+++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
@@ -1,6 +1,6 @@
- netstandard2.1
+ net6.0
Library
true
catch the fruit. to the beat.
@@ -15,4 +15,4 @@
-
\ No newline at end of file
+
diff --git a/osu.Game.Rulesets.Mania.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml
similarity index 95%
rename from osu.Game.Rulesets.Mania.Tests.Android/Properties/AndroidManifest.xml
rename to osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml
index de7935b2ef..4a1545a423 100644
--- a/osu.Game.Rulesets.Mania.Tests.Android/Properties/AndroidManifest.xml
+++ b/osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania.Tests.Android/osu.Game.Rulesets.Mania.Tests.Android.csproj b/osu.Game.Rulesets.Mania.Tests.Android/osu.Game.Rulesets.Mania.Tests.Android.csproj
index 9674186039..25335754d2 100644
--- a/osu.Game.Rulesets.Mania.Tests.Android/osu.Game.Rulesets.Mania.Tests.Android.csproj
+++ b/osu.Game.Rulesets.Mania.Tests.Android/osu.Game.Rulesets.Mania.Tests.Android.csproj
@@ -1,49 +1,24 @@
-
-
+
- Debug
- AnyCPU
- 8.0.30703
- 2.0
- {531F1092-DB27-445D-AA33-2A77C7187C99}
- {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- {122416d6-6b49-4ee2-a1e8-b825f31c79fe}
+ net6.0-android
+ Exe
osu.Game.Rulesets.Mania.Tests
osu.Game.Rulesets.Mania.Tests.Android
- Properties\AndroidManifest.xml
- armeabi-v7a;x86;arm64-v8a
-
-
- None
- cjk;mideast;other;rare;west
- true
-
-
-
-
-
-
-
+
%(RecursiveDir)%(Filename)%(Extension)
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+ Android\%(RecursiveDir)%(Filename)%(Extension)
+
-
- {48f4582b-7687-4621-9cbe-5c24197cb536}
- osu.Game.Rulesets.Mania
-
-
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}
- osu.Game
-
+
+
-
-
- 5.0.0
-
-
-
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs b/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs
index 2d1015387a..a508198f7f 100644
--- a/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs
+++ b/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs
@@ -3,7 +3,6 @@
#nullable disable
-using osu.Framework.iOS;
using UIKit;
namespace osu.Game.Rulesets.Mania.Tests.iOS
@@ -12,7 +11,7 @@ namespace osu.Game.Rulesets.Mania.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, typeof(GameUIApplication), typeof(AppDelegate));
+ UIApplication.Main(args, null, typeof(AppDelegate));
}
}
}
diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist b/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist
index 82d1c8ea24..ff5dde856e 100644
--- a/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist
+++ b/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist
@@ -13,7 +13,7 @@
LSRequiresIPhoneOS
MinimumOSVersion
- 10.0
+ 13.4
UIDeviceFamily
1
diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj b/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj
index 88ad484bc1..51e07dd6c1 100644
--- a/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj
+++ b/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj
@@ -1,35 +1,19 @@
-
-
+
- Debug
- iPhoneSimulator
- {39FD990E-B6CE-4B2A-999F-BC008CF2C64C}
Exe
+ net6.0-ios
+ 13.4
osu.Game.Rulesets.Mania.Tests
osu.Game.Rulesets.Mania.Tests.iOS
-
-
-
- Linker.xml
-
-
-
%(RecursiveDir)%(Filename)%(Extension)
-
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}
- osu.Game
-
-
- {48F4582B-7687-4621-9CBE-5C24197CB536}
- osu.Game.Rulesets.Mania
-
+
+
-
-
\ No newline at end of file
+
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs
index 308238d87a..77f93b4ef9 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs
@@ -35,8 +35,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
protected PatternGenerator(LegacyRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap)
: base(hitObject, beatmap, previousPattern)
{
- if (random == null) throw new ArgumentNullException(nameof(random));
- if (originalBeatmap == null) throw new ArgumentNullException(nameof(originalBeatmap));
+ ArgumentNullException.ThrowIfNull(random);
+ ArgumentNullException.ThrowIfNull(originalBeatmap);
Random = random;
OriginalBeatmap = originalBeatmap;
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs
index b2e89c3410..931673f337 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs
@@ -33,9 +33,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
protected PatternGenerator(HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern)
{
- if (hitObject == null) throw new ArgumentNullException(nameof(hitObject));
- if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
- if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern));
+ ArgumentNullException.ThrowIfNull(hitObject);
+ ArgumentNullException.ThrowIfNull(beatmap);
+ ArgumentNullException.ThrowIfNull(previousPattern);
HitObject = hitObject;
Beatmap = beatmap;
diff --git a/osu.Game.Rulesets.Mania/MathUtils/LegacySortHelper.cs b/osu.Game.Rulesets.Mania/MathUtils/LegacySortHelper.cs
index 1a67117c03..4d93826240 100644
--- a/osu.Game.Rulesets.Mania/MathUtils/LegacySortHelper.cs
+++ b/osu.Game.Rulesets.Mania/MathUtils/LegacySortHelper.cs
@@ -22,8 +22,7 @@ namespace osu.Game.Rulesets.Mania.MathUtils
public static void Sort(T[] keys, IComparer comparer)
{
- if (keys == null)
- throw new ArgumentNullException(nameof(keys));
+ ArgumentNullException.ThrowIfNull(keys);
if (keys.Length == 0)
return;
diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs
index 6a31fb3fda..10460f52fd 100644
--- a/osu.Game.Rulesets.Mania/UI/Column.cs
+++ b/osu.Game.Rulesets.Mania/UI/Column.cs
@@ -134,6 +134,9 @@ namespace osu.Game.Rulesets.Mania.UI
protected override void Dispose(bool isDisposing)
{
+ // must happen before children are disposed in base call to prevent illegal accesses to the hit explosion pool.
+ NewResult -= OnNewResult;
+
base.Dispose(isDisposing);
if (skin != null)
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
index 01e9926ad7..e3ebadc836 100644
--- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
+++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs
@@ -29,8 +29,7 @@ namespace osu.Game.Rulesets.Mania.UI
public ManiaPlayfield(List stageDefinitions)
{
- if (stageDefinitions == null)
- throw new ArgumentNullException(nameof(stageDefinitions));
+ ArgumentNullException.ThrowIfNull(stageDefinitions);
if (stageDefinitions.Count <= 0)
throw new ArgumentException("Can't have zero or fewer stages.");
diff --git a/osu.Game.Rulesets.Mania/UI/Stage.cs b/osu.Game.Rulesets.Mania/UI/Stage.cs
index fc38a96a35..c1d3e85bf1 100644
--- a/osu.Game.Rulesets.Mania/UI/Stage.cs
+++ b/osu.Game.Rulesets.Mania/UI/Stage.cs
@@ -156,6 +156,9 @@ namespace osu.Game.Rulesets.Mania.UI
protected override void Dispose(bool isDisposing)
{
+ // must happen before children are disposed in base call to prevent illegal accesses to the judgement pool.
+ NewResult -= OnNewResult;
+
base.Dispose(isDisposing);
if (currentSkin != null)
diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
index 4f6840f9ca..72f172188e 100644
--- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
+++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
@@ -1,6 +1,6 @@
- netstandard2.1
+ net6.0
Library
true
smash the keys. to the beat.
@@ -15,4 +15,4 @@
-
\ No newline at end of file
+
diff --git a/osu.Game.Rulesets.Osu.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Rulesets.Osu.Tests.Android/AndroidManifest.xml
similarity index 95%
rename from osu.Game.Rulesets.Osu.Tests.Android/Properties/AndroidManifest.xml
rename to osu.Game.Rulesets.Osu.Tests.Android/AndroidManifest.xml
index 3ce17ccc27..45d27dda70 100644
--- a/osu.Game.Rulesets.Osu.Tests.Android/Properties/AndroidManifest.xml
+++ b/osu.Game.Rulesets.Osu.Tests.Android/AndroidManifest.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Osu.Tests.Android/osu.Game.Rulesets.Osu.Tests.Android.csproj b/osu.Game.Rulesets.Osu.Tests.Android/osu.Game.Rulesets.Osu.Tests.Android.csproj
index f4b673f10b..e8a46a9828 100644
--- a/osu.Game.Rulesets.Osu.Tests.Android/osu.Game.Rulesets.Osu.Tests.Android.csproj
+++ b/osu.Game.Rulesets.Osu.Tests.Android/osu.Game.Rulesets.Osu.Tests.Android.csproj
@@ -1,49 +1,27 @@
-
-
+
- Debug
- AnyCPU
- 8.0.30703
- 2.0
- {90CAB706-39CB-4B93-9629-3218A6FF8E9B}
- {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- {122416d6-6b49-4ee2-a1e8-b825f31c79fe}
+ net6.0-android
+ Exe
osu.Game.Rulesets.Osu.Tests
osu.Game.Rulesets.Osu.Tests.Android
- Properties\AndroidManifest.xml
- armeabi-v7a;x86;arm64-v8a
-
-
- None
- cjk;mideast;other;rare;west
- true
-
-
-
-
-
-
-
+
%(RecursiveDir)%(Filename)%(Extension)
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+ Android\%(RecursiveDir)%(Filename)%(Extension)
+
-
- {c92a607b-1fdd-4954-9f92-03ff547d9080}
- osu.Game.Rulesets.Osu
-
-
- {2a66dd92-adb1-4994-89e2-c94e04acda0d}
- osu.Game
-
+
+
-
- 5.0.0
-
+
-
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs b/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs
index ad23f3ee33..6ef29fa68e 100644
--- a/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs
+++ b/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs
@@ -3,7 +3,6 @@
#nullable disable
-using osu.Framework.iOS;
using UIKit;
namespace osu.Game.Rulesets.Osu.Tests.iOS
@@ -12,7 +11,7 @@ namespace osu.Game.Rulesets.Osu.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, typeof(GameUIApplication), typeof(AppDelegate));
+ UIApplication.Main(args, null, typeof(AppDelegate));
}
}
}
diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist b/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist
index a88b74695c..1e33f2ff16 100644
--- a/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist
+++ b/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist
@@ -13,7 +13,7 @@
LSRequiresIPhoneOS
MinimumOSVersion
- 10.0
+ 13.4
UIDeviceFamily
1
diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj b/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj
index 545abcec6c..7d50deb8ba 100644
--- a/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj
+++ b/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj
@@ -1,35 +1,20 @@
-
-
+
- Debug
- iPhoneSimulator
- {6653CA6F-DB06-4604-A3FD-762E25C2AF96}
+ Exe
+ net6.0-ios
+ 13.4
Exe
osu.Game.Rulesets.Osu.Tests
osu.Game.Rulesets.Osu.Tests.iOS
-
-
-
- Linker.xml
-
-
-
%(RecursiveDir)%(Filename)%(Extension)
-
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}
- osu.Game
-
-
- {C92A607B-1FDD-4954-9F92-03FF547D9080}
- osu.Game.Rulesets.Osu
-
+
+
-
-
\ No newline at end of file
+
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs
index 3a175888d9..66d99e0bf1 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs
@@ -133,6 +133,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
+ Debug.Assert(e.NewItems != null);
+
// If inserting in the path (not appending),
// update indices of existing connections after insert location
if (e.NewStartingIndex < Pieces.Count)
@@ -164,6 +166,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
break;
case NotifyCollectionChangedAction.Remove:
+ Debug.Assert(e.OldItems != null);
+
foreach (var point in e.OldItems.Cast())
{
foreach (var piece in Pieces.Where(p => p.ControlPoint == point).ToArray())
diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs
index 1cb3208c30..74e16f7e0b 100644
--- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs
+++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs
@@ -82,10 +82,10 @@ namespace osu.Game.Rulesets.Osu.Replays
private class ReplayFrameComparer : IComparer
{
- public int Compare(ReplayFrame f1, ReplayFrame f2)
+ public int Compare(ReplayFrame? f1, ReplayFrame? f2)
{
- if (f1 == null) throw new ArgumentNullException(nameof(f1));
- if (f2 == null) throw new ArgumentNullException(nameof(f2));
+ ArgumentNullException.ThrowIfNull(f1);
+ ArgumentNullException.ThrowIfNull(f2);
return f1.Time.CompareTo(f2.Time);
}
diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
index 98f1e69bd1..bf776fe5dd 100644
--- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
+++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
@@ -1,6 +1,6 @@
- netstandard2.1
+ net6.0
Library
true
click the circles. to the beat.
@@ -15,4 +15,4 @@
-
\ No newline at end of file
+
diff --git a/osu.Game.Rulesets.Taiko.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Rulesets.Taiko.Tests.Android/AndroidManifest.xml
similarity index 95%
rename from osu.Game.Rulesets.Taiko.Tests.Android/Properties/AndroidManifest.xml
rename to osu.Game.Rulesets.Taiko.Tests.Android/AndroidManifest.xml
index d9de0fde4e..452b9683ec 100644
--- a/osu.Game.Rulesets.Taiko.Tests.Android/Properties/AndroidManifest.xml
+++ b/osu.Game.Rulesets.Taiko.Tests.Android/AndroidManifest.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko.Tests.Android/osu.Game.Rulesets.Taiko.Tests.Android.csproj b/osu.Game.Rulesets.Taiko.Tests.Android/osu.Game.Rulesets.Taiko.Tests.Android.csproj
index 4d4dabebe6..a639326ebd 100644
--- a/osu.Game.Rulesets.Taiko.Tests.Android/osu.Game.Rulesets.Taiko.Tests.Android.csproj
+++ b/osu.Game.Rulesets.Taiko.Tests.Android/osu.Game.Rulesets.Taiko.Tests.Android.csproj
@@ -1,49 +1,24 @@
-
-
+
- Debug
- AnyCPU
- 8.0.30703
- 2.0
- {3701A0A1-8476-42C6-B5C4-D24129B4A484}
- {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- {122416d6-6b49-4ee2-a1e8-b825f31c79fe}
+ net6.0-android
+ Exe
osu.Game.Rulesets.Taiko.Tests
osu.Game.Rulesets.Taiko.Tests.Android
- Properties\AndroidManifest.xml
- armeabi-v7a;x86;arm64-v8a
-
-
- None
- cjk;mideast;other;rare;west
- true
-
-
-
-
-
-
-
+
%(RecursiveDir)%(Filename)%(Extension)
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+ Android\%(RecursiveDir)%(Filename)%(Extension)
+
-
- {f167e17a-7de6-4af5-b920-a5112296c695}
- osu.Game.Rulesets.Taiko
-
-
- {2a66dd92-adb1-4994-89e2-c94e04acda0d}
- osu.Game
-
+
+
-
-
- 5.0.0
-
-
-
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs b/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs
index 1ebbd61a94..0e3a953728 100644
--- a/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs
+++ b/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs
@@ -3,7 +3,6 @@
#nullable disable
-using osu.Framework.iOS;
using UIKit;
namespace osu.Game.Rulesets.Taiko.Tests.iOS
@@ -12,7 +11,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, typeof(GameUIApplication), typeof(AppDelegate));
+ UIApplication.Main(args, null, typeof(AppDelegate));
}
}
}
diff --git a/osu.Game.Rulesets.Taiko.Tests.iOS/Info.plist b/osu.Game.Rulesets.Taiko.Tests.iOS/Info.plist
index 9628475b3e..76cb3c0db0 100644
--- a/osu.Game.Rulesets.Taiko.Tests.iOS/Info.plist
+++ b/osu.Game.Rulesets.Taiko.Tests.iOS/Info.plist
@@ -13,7 +13,7 @@
LSRequiresIPhoneOS
MinimumOSVersion
- 10.0
+ 13.4
UIDeviceFamily
1
diff --git a/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj b/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj
index 8ee640cd99..e648a11299 100644
--- a/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj
+++ b/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj
@@ -1,35 +1,19 @@
-
-
+
- Debug
- iPhoneSimulator
- {7E408809-66AC-49D1-AF4D-98834F9B979A}
Exe
+ net6.0-ios
+ 13.4
osu.Game.Rulesets.Taiko.Tests
osu.Game.Rulesets.Taiko.Tests.iOS
-
-
-
- Linker.xml
-
-
-
%(RecursiveDir)%(Filename)%(Extension)
-
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}
- osu.Game
-
-
- {F167E17A-7DE6-4AF5-B920-A5112296C695}
- osu.Game.Rulesets.Taiko
-
+
+
-
-
\ No newline at end of file
+
diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
index b752c13d18..f0e1cb8e8f 100644
--- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
+++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
@@ -1,6 +1,6 @@
- netstandard2.1
+ net6.0
Library
true
bash the drum. to the beat.
diff --git a/osu.Game.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Tests.Android/AndroidManifest.xml
similarity index 95%
rename from osu.Game.Tests.Android/Properties/AndroidManifest.xml
rename to osu.Game.Tests.Android/AndroidManifest.xml
index 4a63f0c357..f25b2e5328 100644
--- a/osu.Game.Tests.Android/Properties/AndroidManifest.xml
+++ b/osu.Game.Tests.Android/AndroidManifest.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/osu.Game.Tests.Android/MainActivity.cs b/osu.Game.Tests.Android/MainActivity.cs
index 6c4f9bac58..bdb947fbb4 100644
--- a/osu.Game.Tests.Android/MainActivity.cs
+++ b/osu.Game.Tests.Android/MainActivity.cs
@@ -3,7 +3,9 @@
#nullable disable
+using System.Reflection;
using Android.App;
+using Android.OS;
using osu.Framework.Android;
namespace osu.Game.Tests.Android
@@ -12,5 +14,16 @@ namespace osu.Game.Tests.Android
public class MainActivity : AndroidGameActivity
{
protected override Framework.Game CreateGame() => new OsuTestBrowser();
+
+ protected override void OnCreate(Bundle savedInstanceState)
+ {
+ base.OnCreate(savedInstanceState);
+
+ // See the comment in OsuGameActivity
+ Assembly.Load("osu.Game.Rulesets.Osu");
+ Assembly.Load("osu.Game.Rulesets.Taiko");
+ Assembly.Load("osu.Game.Rulesets.Catch");
+ Assembly.Load("osu.Game.Rulesets.Mania");
+ }
}
}
diff --git a/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj b/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj
index afafec6b1f..b745d91980 100644
--- a/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj
+++ b/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj
@@ -1,88 +1,34 @@
-
-
+
- Debug
- AnyCPU
- 8.0.30703
- 2.0
- {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}
- {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- {122416d6-6b49-4ee2-a1e8-b825f31c79fe}
+ net6.0-android
+ Exe
osu.Game.Tests
osu.Game.Tests.Android
- Properties\AndroidManifest.xml
- armeabi-v7a;x86;arm64-v8a
-
-
-
-
-
-
$(NoWarn);CA2007
-
- None
- cjk;mideast;other;rare;west
- true
-
-
+
%(RecursiveDir)%(Filename)%(Extension)
-
-
+
+
%(RecursiveDir)%(Filename)%(Extension)
-
-
- %(RecursiveDir)%(Filename)%(Extension)
-
-
- %(RecursiveDir)%(Filename)%(Extension)
-
-
- %(RecursiveDir)%(Filename)%(Extension)
-
-
- %(RecursiveDir)%(Filename)%(Extension)
-
-
- %(RecursiveDir)%(Filename)%(Extension)
-
-
- %(RecursiveDir)%(Filename)%(Extension)
-
+ Android\%(RecursiveDir)%(Filename)%(Extension)
+
-
- {58f6c80c-1253-4a0e-a465-b8c85ebeadf3}
- osu.Game.Rulesets.Catch
-
-
- {48f4582b-7687-4621-9cbe-5c24197cb536}
- osu.Game.Rulesets.Mania
-
-
- {c92a607b-1fdd-4954-9f92-03ff547d9080}
- osu.Game.Rulesets.Osu
-
-
- {f167e17a-7de6-4af5-b920-a5112296c695}
- osu.Game.Rulesets.Taiko
-
-
- {2a66dd92-adb1-4994-89e2-c94e04acda0d}
- osu.Game
-
+
+
+
+
+
-
- 5.0.0
-
-
diff --git a/osu.Game.Tests.iOS/Application.cs b/osu.Game.Tests.iOS/Application.cs
index cf36fea139..4678be4fb8 100644
--- a/osu.Game.Tests.iOS/Application.cs
+++ b/osu.Game.Tests.iOS/Application.cs
@@ -3,7 +3,6 @@
#nullable disable
-using osu.Framework.iOS;
using UIKit;
namespace osu.Game.Tests.iOS
@@ -12,7 +11,7 @@ namespace osu.Game.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, typeof(GameUIApplication), typeof(AppDelegate));
+ UIApplication.Main(args, null, typeof(AppDelegate));
}
}
}
diff --git a/osu.Game.Tests.iOS/Info.plist b/osu.Game.Tests.iOS/Info.plist
index 31e2b3f257..ac661f6263 100644
--- a/osu.Game.Tests.iOS/Info.plist
+++ b/osu.Game.Tests.iOS/Info.plist
@@ -13,7 +13,7 @@
LSRequiresIPhoneOS
MinimumOSVersion
- 10.0
+ 13.4
UIDeviceFamily
1
diff --git a/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj b/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj
index 05b3cad6da..79771fcd50 100644
--- a/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj
+++ b/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj
@@ -1,54 +1,26 @@
-
-
+
- Debug
- iPhoneSimulator
Exe
- {65FF8E19-6934-469B-B690-23C6D6E56A17}
+ net6.0-ios
+ 13.4
osu.Game.Tests
osu.Game.Tests.iOS
-
-
-
- Linker.xml
-
-
-
%(RecursiveDir)%(Filename)%(Extension)
-
- $(NoWarn);CA2007
-
-
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}
- osu.Game
-
-
- {C92A607B-1FDD-4954-9F92-03FF547D9080}
- osu.Game.Rulesets.Osu
-
-
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}
- osu.Game.Rulesets.Catch
-
-
- {48F4582B-7687-4621-9CBE-5C24197CB536}
- osu.Game.Rulesets.Mania
-
-
- {F167E17A-7DE6-4AF5-B920-A5112296C695}
- osu.Game.Rulesets.Taiko
-
+
+
+
+
+
-
diff --git a/osu.Game.Tests/Chat/MessageFormatterTests.cs b/osu.Game.Tests/Chat/MessageFormatterTests.cs
index ebfa9bd8b7..3c35dc311f 100644
--- a/osu.Game.Tests/Chat/MessageFormatterTests.cs
+++ b/osu.Game.Tests/Chat/MessageFormatterTests.cs
@@ -26,6 +26,16 @@ namespace osu.Game.Tests.Chat
MessageFormatter.WebsiteRootUrl = originalWebsiteRootUrl;
}
+ [Test]
+ public void TestUnsupportedProtocolLink()
+ {
+ Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a gopher://really-old-protocol we don't support." });
+
+ Assert.AreEqual(result.Content, result.DisplayContent);
+ Assert.AreEqual(1, result.Links.Count);
+ Assert.AreEqual("gopher://really-old-protocol", result.Links[0].Url);
+ }
+
[Test]
public void TestBareLink()
{
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs b/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs
index 6bc2922253..a141e4d431 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs
@@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Editing
{
public partial class TestSceneZoomableScrollContainer : OsuManualInputManagerTestScene
{
- private ZoomableScrollContainer scrollContainer;
+ private TestZoomableScrollContainer scrollContainer;
private Drawable innerBox;
[SetUpSteps]
@@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.Editing
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(30)
},
- scrollContainer = new ZoomableScrollContainer(1, 60, 1)
+ scrollContainer = new TestZoomableScrollContainer(1, 60, 1)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -93,6 +93,14 @@ namespace osu.Game.Tests.Visual.Editing
AddAssert("Inner container width matches scroll container", () => innerBox.DrawWidth == scrollContainer.DrawWidth);
}
+ [Test]
+ public void TestWidthUpdatesOnSecondZoomSetup()
+ {
+ AddAssert("Inner container width = 1x", () => innerBox.DrawWidth == scrollContainer.DrawWidth);
+ AddStep("reload zoom", () => scrollContainer.SetupZoom(10, 10, 60));
+ AddAssert("Inner container width = 10x", () => innerBox.DrawWidth == scrollContainer.DrawWidth * 10);
+ }
+
[Test]
public void TestZoom0()
{
@@ -190,5 +198,15 @@ namespace osu.Game.Tests.Visual.Editing
private Quad scrollQuad => scrollContainer.ScreenSpaceDrawQuad;
private Quad boxQuad => innerBox.ScreenSpaceDrawQuad;
+
+ private partial class TestZoomableScrollContainer : ZoomableScrollContainer
+ {
+ public TestZoomableScrollContainer(int minimum, float maximum, float initial)
+ : base(minimum, maximum, initial)
+ {
+ }
+
+ public new void SetupZoom(float initial, float minimum, float maximum) => base.SetupZoom(initial, minimum, maximum);
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs
index 7981e212d4..d925141510 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs
@@ -77,14 +77,14 @@ namespace osu.Game.Tests.Visual.Online
{
var comments = this.ChildrenOfType();
var ourComment = comments.SingleOrDefault(x => x.Comment.Id == 1);
- return ourComment != null && ourComment.ChildrenOfType().Any(x => x.Text == "Delete");
+ return ourComment != null && ourComment.ChildrenOfType().Any(x => x.Text == "delete");
});
AddAssert("Second doesn't", () =>
{
var comments = this.ChildrenOfType();
var ourComment = comments.Single(x => x.Comment.Id == 2);
- return ourComment.ChildrenOfType().All(x => x.Text != "Delete");
+ return ourComment.ChildrenOfType().All(x => x.Text != "delete");
});
}
@@ -102,7 +102,7 @@ namespace osu.Game.Tests.Visual.Online
});
AddStep("It has delete button", () =>
{
- var btn = ourComment.ChildrenOfType().Single(x => x.Text == "Delete");
+ var btn = ourComment.ChildrenOfType().Single(x => x.Text == "delete");
InputManager.MoveMouseTo(btn);
});
AddStep("Click delete button", () =>
@@ -175,7 +175,7 @@ namespace osu.Game.Tests.Visual.Online
});
AddStep("It has delete button", () =>
{
- var btn = ourComment.ChildrenOfType().Single(x => x.Text == "Delete");
+ var btn = ourComment.ChildrenOfType().Single(x => x.Text == "delete");
InputManager.MoveMouseTo(btn);
});
AddStep("Click delete button", () =>
@@ -189,7 +189,7 @@ namespace osu.Game.Tests.Visual.Online
if (request is not CommentDeleteRequest req)
return false;
- req.TriggerFailure(new Exception());
+ req.TriggerFailure(new InvalidOperationException());
delete = true;
return false;
};
@@ -245,7 +245,7 @@ namespace osu.Game.Tests.Visual.Online
});
AddStep("Click the button", () =>
{
- var btn = targetComment.ChildrenOfType().Single(x => x.Text == "Report");
+ var btn = targetComment.ChildrenOfType().Single(x => x.Text == "report");
InputManager.MoveMouseTo(btn);
InputManager.Click(MouseButton.Left);
});
diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs
index b486f800c6..b353123649 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs
@@ -16,13 +16,17 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Graphics.Containers.Markdown;
+using osu.Game.Graphics.Containers.Markdown.Footnotes;
using osu.Game.Overlays;
using osu.Game.Overlays.Wiki.Markdown;
+using osu.Game.Users.Drawables;
+using osuTK.Input;
namespace osu.Game.Tests.Visual.Online
{
- public partial class TestSceneWikiMarkdownContainer : OsuTestScene
+ public partial class TestSceneWikiMarkdownContainer : OsuManualInputManagerTestScene
{
+ private OverlayScrollContainer scrollContainer;
private TestMarkdownContainer markdownContainer;
[Cached]
@@ -38,15 +42,25 @@ namespace osu.Game.Tests.Visual.Online
Colour = overlayColour.Background5,
RelativeSizeAxes = Axes.Both,
},
- new BasicScrollContainer
+ scrollContainer = new OverlayScrollContainer
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(20),
- Child = markdownContainer = new TestMarkdownContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- }
+ }
+ };
+
+ scrollContainer.Child = new DependencyProvidingContainer
+ {
+ CachedDependencies = new (Type, object)[]
+ {
+ (typeof(OverlayScrollContainer), scrollContainer)
+ },
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Child = markdownContainer = new TestMarkdownContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
}
};
});
@@ -197,6 +211,63 @@ Line after image";
markdownContainer.CurrentPath = @"https://dev.ppy.sh";
markdownContainer.Text = "::{flag=\"AU\"}:: ::{flag=\"ZZ\"}::";
});
+ AddAssert("Two flags visible", () => markdownContainer.ChildrenOfType().Count(), () => Is.EqualTo(2));
+ }
+
+ [Test]
+ public void TestHeadingWithIdAttribute()
+ {
+ AddStep("Add heading with ID", () =>
+ {
+ markdownContainer.Text = "# This is a heading with an ID {#this-is-the-id}";
+ });
+ AddAssert("ID not visible", () => markdownContainer.ChildrenOfType().All(spriteText => spriteText.Text != "{#this-is-the-id}"));
+ }
+
+ [Test]
+ public void TestFootnotes()
+ {
+ AddStep("set content", () => markdownContainer.Text = @"This text has a footnote[^test].
+
+Here's some more text[^test2] with another footnote!
+
+# Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam efficitur laoreet posuere. Ut accumsan tortor in ipsum tincidunt ultrices. Suspendisse a malesuada tellus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce a sagittis nibh. In et velit sit amet mauris aliquet consectetur quis vehicula lorem. Etiam sit amet tellus ac velit ornare maximus. Donec quis metus eget libero ullamcorper imperdiet id vitae arcu. Vivamus iaculis rhoncus purus malesuada mollis. Vestibulum dictum at nisi sed tincidunt. Suspendisse finibus, ipsum ut dapibus commodo, leo eros porttitor sapien, non scelerisque nisi ligula sed ex. Pellentesque magna orci, hendrerit eu iaculis sit amet, ullamcorper in urna. Vivamus dictum mauris orci, nec facilisis dolor fringilla eu. Sed at porttitor nisi, at venenatis urna. Ut at orci vitae libero semper ullamcorper eu ut risus. Mauris hendrerit varius enim, ut varius nisi feugiat mattis.
+
+## In at eros urna. Sed ipsum lorem, tempor sit amet purus in, vehicula pellentesque leo. Fusce volutpat pellentesque velit sit amet porttitor. Nulla eget erat ex. Praesent eu lacinia est, quis vehicula lacus. Donec consequat ultrices neque, at finibus quam efficitur vel. Vestibulum molestie nisl sit amet metus semper, at vestibulum massa rhoncus. Quisque imperdiet suscipit augue, et dignissim odio eleifend ut.
+
+Aliquam sed vestibulum mauris, ut lobortis elit. Sed quis lacinia erat. Nam ultricies, risus non pellentesque sollicitudin, mauris dolor tincidunt neque, ac porta ipsum dui quis libero. Integer eget velit neque. Vestibulum venenatis mauris vitae rutrum vestibulum. Maecenas suscipit eu purus eu tempus. Nam dui nisl, bibendum condimentum mollis et, gravida vel dui. Sed et eros rutrum, facilisis sapien eu, mattis ligula. Fusce finibus pulvinar dolor quis consequat.
+
+Donec ipsum felis, feugiat vel fermentum at, commodo eu sapien. Suspendisse nec enim vitae felis laoreet laoreet. Phasellus purus quam, fermentum a pharetra vel, tempor et urna. Integer vitae quam diam. Aliquam tincidunt tortor a iaculis convallis. Suspendisse potenti. Cras quis risus quam. Nullam tincidunt in lorem posuere sagittis.
+
+Phasellus eu nunc nec ligula semper fringilla. Aliquam magna neque, placerat sed urna tristique, laoreet pharetra nulla. Vivamus maximus turpis purus, eu viverra dolor sodales porttitor. Praesent bibendum sapien purus, sed ultricies dolor iaculis sed. Fusce congue hendrerit malesuada. Nulla nulla est, auctor ac fringilla sed, ornare a lorem. Donec quis velit imperdiet, imperdiet sem non, pellentesque sapien. Maecenas in orci id ipsum placerat facilisis non sed nisi. Duis dictum lorem sodales odio dictum eleifend. Vestibulum bibendum euismod quam, eget pharetra orci facilisis sed. Vivamus at diam non ipsum consequat tristique. Pellentesque gravida dignissim pellentesque. Donec ullamcorper lacinia orci, id consequat purus faucibus quis. Phasellus metus nunc, iaculis a interdum vel, congue sed erat. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Etiam eros libero, hendrerit luctus nulla vitae, luctus maximus nunc.
+
+[^test]: This is a **footnote**.
+[^test2]: This is another footnote [with a link](https://google.com/)!");
+ AddStep("shrink scroll height", () => scrollContainer.Height = 0.5f);
+
+ AddStep("press second footnote link", () =>
+ {
+ InputManager.MoveMouseTo(markdownContainer.ChildrenOfType().ElementAt(1));
+ InputManager.Click(MouseButton.Left);
+ });
+ AddUntilStep("second footnote scrolled into view", () =>
+ {
+ var footnote = markdownContainer.ChildrenOfType().ElementAt(1);
+ return scrollContainer.ScreenSpaceDrawQuad.Contains(footnote.ScreenSpaceDrawQuad.TopLeft)
+ && scrollContainer.ScreenSpaceDrawQuad.Contains(footnote.ScreenSpaceDrawQuad.BottomRight);
+ });
+
+ AddStep("press first footnote backlink", () =>
+ {
+ InputManager.MoveMouseTo(markdownContainer.ChildrenOfType().First());
+ InputManager.Click(MouseButton.Left);
+ });
+ AddUntilStep("first footnote link scrolled into view", () =>
+ {
+ var footnote = markdownContainer.ChildrenOfType().First();
+ return scrollContainer.ScreenSpaceDrawQuad.Contains(footnote.ScreenSpaceDrawQuad.TopLeft)
+ && scrollContainer.ScreenSpaceDrawQuad.Contains(footnote.ScreenSpaceDrawQuad.BottomRight);
+ });
}
private partial class TestMarkdownContainer : WikiMarkdownContainer
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs
index e47b7e25a8..11d55bc0bd 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs
@@ -136,7 +136,7 @@ namespace osu.Game.Tests.Visual.SongSelect
if (testRequest.Progress >= 0.5f)
{
- testRequest.TriggerFailure(new Exception());
+ testRequest.TriggerFailure(new InvalidOperationException());
return true;
}
}
diff --git a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs
index 52769321a9..1157b50377 100644
--- a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs
+++ b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs
@@ -32,7 +32,7 @@ namespace osu.Game.Tournament.Components
public TournamentBeatmapPanel(TournamentBeatmap beatmap, string mod = null)
{
- if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
+ ArgumentNullException.ThrowIfNull(beatmap);
Beatmap = beatmap;
this.mod = mod;
diff --git a/osu.Game.Tournament/IPC/FileBasedIPC.cs b/osu.Game.Tournament/IPC/FileBasedIPC.cs
index f940571ffe..2d47560947 100644
--- a/osu.Game.Tournament/IPC/FileBasedIPC.cs
+++ b/osu.Game.Tournament/IPC/FileBasedIPC.cs
@@ -245,8 +245,10 @@ namespace osu.Game.Tournament.IPC
{
string stableInstallPath;
+#pragma warning disable CA1416
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu"))
stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(string.Empty)?.ToString()?.Split('"')[1].Replace("osu!.exe", "");
+#pragma warning restore CA1416
if (ipcFileExistsInDirectory(stableInstallPath))
return stableInstallPath;
diff --git a/osu.Game.Tournament/SaveChangesOverlay.cs b/osu.Game.Tournament/SaveChangesOverlay.cs
index a81f11cbe1..1bc576bc63 100644
--- a/osu.Game.Tournament/SaveChangesOverlay.cs
+++ b/osu.Game.Tournament/SaveChangesOverlay.cs
@@ -70,7 +70,7 @@ namespace osu.Game.Tournament
private async Task checkForChanges()
{
- string serialisedLadder = await Task.Run(() => tournamentGame.GetSerialisedLadder());
+ string serialisedLadder = await Task.Run(() => tournamentGame.GetSerialisedLadder()).ConfigureAwait(false);
// If a save hasn't been triggered by the user yet, populate the initial value
lastSerialisedLadder ??= serialisedLadder;
diff --git a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs
index 988f0a02f0..eb5c9a879a 100644
--- a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs
+++ b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs
@@ -5,7 +5,6 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -54,8 +53,6 @@ namespace osu.Game.Tournament.Screens.Editors
});
}
- Debug.Assert(countries != null);
-
foreach (var c in countries)
Storage.Add(c);
}
diff --git a/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs
index 8f0d1de0cb..0fb6c1367b 100644
--- a/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs
+++ b/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs
@@ -4,6 +4,7 @@
#nullable disable
using System.Collections.Specialized;
+using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -102,10 +103,14 @@ namespace osu.Game.Tournament.Screens.Editors
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
+ Debug.Assert(args.NewItems != null);
+
args.NewItems.Cast().ForEach(i => flow.Add(CreateDrawable(i)));
break;
case NotifyCollectionChangedAction.Remove:
+ Debug.Assert(args.OldItems != null);
+
args.OldItems.Cast().ForEach(i => flow.RemoveAll(d => d.Model == i, true));
break;
}
diff --git a/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs b/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs
index 603a7830c7..5aea551c00 100644
--- a/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs
+++ b/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -20,8 +21,6 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
{
public partial class LadderEditorSettings : PlayerSettingsGroup
{
- private const int padding = 10;
-
private SettingsDropdown roundDropdown;
private PlayerCheckbox losersCheckbox;
private DateTextBox dateTimeBox;
@@ -103,10 +102,14 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
+ Debug.Assert(args.NewItems != null);
+
args.NewItems.Cast().ForEach(add);
break;
case NotifyCollectionChangedAction.Remove:
+ Debug.Assert(args.OldItems != null);
+
args.OldItems.Cast().ForEach(i => Control.RemoveDropdownItem(i));
break;
}
diff --git a/osu.Game.Tournament/Screens/Ladder/Components/SettingsTeamDropdown.cs b/osu.Game.Tournament/Screens/Ladder/Components/SettingsTeamDropdown.cs
index c90cdb7775..f7a42e4f50 100644
--- a/osu.Game.Tournament/Screens/Ladder/Components/SettingsTeamDropdown.cs
+++ b/osu.Game.Tournament/Screens/Ladder/Components/SettingsTeamDropdown.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Diagnostics;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
@@ -25,10 +26,14 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
+ Debug.Assert(args.NewItems != null);
+
args.NewItems.Cast().ForEach(add);
break;
case NotifyCollectionChangedAction.Remove:
+ Debug.Assert(args.OldItems != null);
+
args.OldItems.Cast().ForEach(i => Control.RemoveDropdownItem(i));
break;
}
diff --git a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs
index 595f08ed36..176c06c0e5 100644
--- a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs
+++ b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs
@@ -4,6 +4,7 @@
#nullable disable
using System.Collections.Specialized;
+using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Caching;
@@ -81,11 +82,15 @@ namespace osu.Game.Tournament.Screens.Ladder
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
+ Debug.Assert(args.NewItems != null);
+
foreach (var p in args.NewItems.Cast())
addMatch(p);
break;
case NotifyCollectionChangedAction.Remove:
+ Debug.Assert(args.OldItems != null);
+
foreach (var p in args.OldItems.Cast())
{
foreach (var d in MatchesContainer.Where(d => d.Match == p))
@@ -153,7 +158,7 @@ namespace osu.Game.Tournament.Screens.Ladder
foreach (var round in LadderInfo.Rounds)
{
- var topMatch = MatchesContainer.Where(p => !p.Match.Losers.Value && p.Match.Round.Value == round).OrderBy(p => p.Y).FirstOrDefault();
+ var topMatch = MatchesContainer.Where(p => !p.Match.Losers.Value && p.Match.Round.Value == round).MinBy(p => p.Y);
if (topMatch == null) continue;
@@ -167,7 +172,7 @@ namespace osu.Game.Tournament.Screens.Ladder
foreach (var round in LadderInfo.Rounds)
{
- var topMatch = MatchesContainer.Where(p => p.Match.Losers.Value && p.Match.Round.Value == round).OrderBy(p => p.Y).FirstOrDefault();
+ var topMatch = MatchesContainer.Where(p => p.Match.Losers.Value && p.Match.Round.Value == round).MinBy(p => p.Y);
if (topMatch == null) continue;
diff --git a/osu.Game.Tournament/osu.Game.Tournament.csproj b/osu.Game.Tournament/osu.Game.Tournament.csproj
index b049542bb0..ab67e490cd 100644
--- a/osu.Game.Tournament/osu.Game.Tournament.csproj
+++ b/osu.Game.Tournament/osu.Game.Tournament.csproj
@@ -1,6 +1,6 @@
- netstandard2.1
+ net6.0
Library
true
tools for tournaments.
@@ -11,4 +11,4 @@
-
\ No newline at end of file
+
diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs
index 19c78f34b2..0191f96825 100644
--- a/osu.Game/Audio/SampleInfo.cs
+++ b/osu.Game/Audio/SampleInfo.cs
@@ -35,7 +35,7 @@ namespace osu.Game.Audio
public bool Equals(SampleInfo? other)
=> other != null && sampleNames.SequenceEqual(other.sampleNames);
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
=> obj is SampleInfo other && Equals(other);
}
}
diff --git a/osu.Game/Beatmaps/BeatmapImporter.cs b/osu.Game/Beatmaps/BeatmapImporter.cs
index 8a6315fc65..4752a88199 100644
--- a/osu.Game/Beatmaps/BeatmapImporter.cs
+++ b/osu.Game/Beatmaps/BeatmapImporter.cs
@@ -44,7 +44,7 @@ namespace osu.Game.Beatmaps
public override async Task?> ImportAsUpdate(ProgressNotification notification, ImportTask importTask, BeatmapSetInfo original)
{
- var imported = await Import(notification, new[] { importTask });
+ var imported = await Import(notification, new[] { importTask }).ConfigureAwait(true);
if (!imported.Any())
return null;
diff --git a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs
index 2fd1d06b7b..71d40b1a48 100644
--- a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs
+++ b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs
@@ -178,7 +178,7 @@ namespace osu.Game.Beatmaps
{
try
{
- await cacheDownloadRequest.PerformAsync();
+ await cacheDownloadRequest.PerformAsync().ConfigureAwait(false);
}
catch
{
diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs
index 0a09e6e7e6..f46e4af332 100644
--- a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs
+++ b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Beatmaps.ControlPoints
public void AttachGroup(ControlPointGroup pointGroup) => Time = pointGroup.Time;
- public int CompareTo(ControlPoint other) => Time.CompareTo(other.Time);
+ public int CompareTo(ControlPoint? other) => Time.CompareTo(other?.Time);
public virtual Color4 GetRepresentingColour(OsuColour colours) => colours.Yellow;
@@ -32,7 +32,7 @@ namespace osu.Game.Beatmaps.ControlPoints
///
public ControlPoint DeepClone()
{
- var copy = (ControlPoint)Activator.CreateInstance(GetType());
+ var copy = (ControlPoint)Activator.CreateInstance(GetType())!;
copy.CopyFrom(this);
diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs
index db479f0e5b..1f34f3777d 100644
--- a/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs
+++ b/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs
@@ -26,7 +26,7 @@ namespace osu.Game.Beatmaps.ControlPoints
Time = time;
}
- public int CompareTo(ControlPointGroup other) => Time.CompareTo(other.Time);
+ public int CompareTo(ControlPointGroup? other) => Time.CompareTo(other?.Time);
public void Add(ControlPoint point)
{
diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs
index 422e306450..29b7191ecf 100644
--- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs
+++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs
@@ -70,14 +70,14 @@ namespace osu.Game.Beatmaps.ControlPoints
///
[JsonIgnore]
public double BPMMaximum =>
- 60000 / (TimingPoints.OrderBy(c => c.BeatLength).FirstOrDefault() ?? TimingControlPoint.DEFAULT).BeatLength;
+ 60000 / (TimingPoints.MinBy(c => c.BeatLength) ?? TimingControlPoint.DEFAULT).BeatLength;
///
/// Finds the minimum BPM represented by any timing control point.
///
[JsonIgnore]
public double BPMMinimum =>
- 60000 / (TimingPoints.OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? TimingControlPoint.DEFAULT).BeatLength;
+ 60000 / (TimingPoints.MaxBy(c => c.BeatLength) ?? TimingControlPoint.DEFAULT).BeatLength;
///
/// Remove all s and return to a pristine state.
@@ -211,8 +211,7 @@ namespace osu.Game.Beatmaps.ControlPoints
public static T BinarySearch(IReadOnlyList list, double time)
where T : class, IControlPoint
{
- if (list == null)
- throw new ArgumentNullException(nameof(list));
+ ArgumentNullException.ThrowIfNull(list);
if (list.Count == 0)
return null;
@@ -300,7 +299,7 @@ namespace osu.Game.Beatmaps.ControlPoints
public ControlPointInfo DeepClone()
{
- var controlPointInfo = (ControlPointInfo)Activator.CreateInstance(GetType());
+ var controlPointInfo = (ControlPointInfo)Activator.CreateInstance(GetType())!;
foreach (var point in AllControlPoints)
controlPointInfo.Add(point.Time, point.DeepClone());
diff --git a/osu.Game/Beatmaps/DifficultyRecommender.cs b/osu.Game/Beatmaps/DifficultyRecommender.cs
index 7a23b32c84..ec00756fd9 100644
--- a/osu.Game/Beatmaps/DifficultyRecommender.cs
+++ b/osu.Game/Beatmaps/DifficultyRecommender.cs
@@ -51,11 +51,11 @@ namespace osu.Game.Beatmaps
if (!recommendedDifficultyMapping.TryGetValue(r, out double recommendation))
continue;
- BeatmapInfo beatmapInfo = beatmaps.Where(b => b.Ruleset.ShortName.Equals(r)).OrderBy(b =>
+ BeatmapInfo beatmapInfo = beatmaps.Where(b => b.Ruleset.ShortName.Equals(r, StringComparison.Ordinal)).MinBy(b =>
{
double difference = b.StarRating - recommendation;
return difference >= 0 ? difference * 2 : difference * -1; // prefer easier over harder
- }).FirstOrDefault();
+ });
if (beatmapInfo != null)
return beatmapInfo;
@@ -90,7 +90,7 @@ namespace osu.Game.Beatmaps
return recommendedDifficultyMapping
.OrderByDescending(pair => pair.Value)
.Select(pair => pair.Key)
- .Where(r => !r.Equals(ruleset.Value.ShortName))
+ .Where(r => !r.Equals(ruleset.Value.ShortName, StringComparison.Ordinal))
.Prepend(ruleset.Value.ShortName);
}
}
diff --git a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs
index d31a7ae2fe..767504fcb1 100644
--- a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs
+++ b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs
@@ -15,8 +15,7 @@ namespace osu.Game.Beatmaps.Drawables
public BeatmapBackgroundSprite(IWorkingBeatmap working)
{
- if (working == null)
- throw new ArgumentNullException(nameof(working));
+ ArgumentNullException.ThrowIfNull(working);
this.working = working;
}
diff --git a/osu.Game/Beatmaps/Drawables/OnlineBeatmapSetCover.cs b/osu.Game/Beatmaps/Drawables/OnlineBeatmapSetCover.cs
index e4ffc1d553..fc7c14e734 100644
--- a/osu.Game/Beatmaps/Drawables/OnlineBeatmapSetCover.cs
+++ b/osu.Game/Beatmaps/Drawables/OnlineBeatmapSetCover.cs
@@ -18,8 +18,7 @@ namespace osu.Game.Beatmaps.Drawables
public OnlineBeatmapSetCover(IBeatmapSetOnlineInfo set, BeatmapSetCoverType type = BeatmapSetCoverType.Cover)
{
- if (set == null)
- throw new ArgumentNullException(nameof(set));
+ ArgumentNullException.ThrowIfNull(set);
this.set = set;
this.type = type;
diff --git a/osu.Game/Beatmaps/Formats/Decoder.cs b/osu.Game/Beatmaps/Formats/Decoder.cs
index ca1bcc97fd..4f0f11d053 100644
--- a/osu.Game/Beatmaps/Formats/Decoder.cs
+++ b/osu.Game/Beatmaps/Formats/Decoder.cs
@@ -57,8 +57,7 @@ namespace osu.Game.Beatmaps.Formats
public static Decoder GetDecoder(LineBufferedReader stream)
where T : new()
{
- if (stream == null)
- throw new ArgumentNullException(nameof(stream));
+ ArgumentNullException.ThrowIfNull(stream);
if (!decoders.TryGetValue(typeof(T), out var typedDecoders))
throw new IOException(@"Unknown decoder type");
diff --git a/osu.Game/Configuration/SettingSourceAttribute.cs b/osu.Game/Configuration/SettingSourceAttribute.cs
index 043bba3134..1e425c88a6 100644
--- a/osu.Game/Configuration/SettingSourceAttribute.cs
+++ b/osu.Game/Configuration/SettingSourceAttribute.cs
@@ -91,15 +91,15 @@ namespace osu.Game.Configuration
OrderPosition = orderPosition;
}
- public int CompareTo(SettingSourceAttribute other)
+ public int CompareTo(SettingSourceAttribute? other)
{
- if (OrderPosition == other.OrderPosition)
+ if (OrderPosition == other?.OrderPosition)
return 0;
// unordered items come last (are greater than any ordered items).
if (OrderPosition == null)
return 1;
- if (other.OrderPosition == null)
+ if (other?.OrderPosition == null)
return -1;
// ordered items are sorted by the order value.
@@ -113,7 +113,7 @@ namespace osu.Game.Configuration
{
foreach (var (attr, property) in obj.GetOrderedSettingsSourceProperties())
{
- object value = property.GetValue(obj);
+ object value = property.GetValue(obj)!;
if (attr.SettingControlType != null)
{
@@ -121,7 +121,7 @@ namespace osu.Game.Configuration
if (controlType.EnumerateBaseTypes().All(t => !t.IsGenericType || t.GetGenericTypeDefinition() != typeof(SettingsItem<>)))
throw new InvalidOperationException($"{nameof(SettingSourceAttribute)} had an unsupported custom control type ({controlType.ReadableName()})");
- var control = (Drawable)Activator.CreateInstance(controlType);
+ var control = (Drawable)Activator.CreateInstance(controlType)!;
controlType.GetProperty(nameof(SettingsItem
public virtual event Action? OnUserFinishedPlaying;
+ ///
+ /// Called whenever a user-submitted score has been fully processed.
+ ///
+ public virtual event Action? OnUserScoreProcessed;
+
///
/// A dictionary containing all users currently being watched, with the number of watching components for each user.
///
@@ -160,6 +165,13 @@ namespace osu.Game.Online.Spectator
return Task.CompletedTask;
}
+ Task ISpectatorClient.UserScoreProcessed(int userId, long scoreId)
+ {
+ Schedule(() => OnUserScoreProcessed?.Invoke(userId, scoreId));
+
+ return Task.CompletedTask;
+ }
+
public void BeginPlaying(long? scoreToken, GameplayState state, Score score)
{
// This schedule is only here to match the one below in `EndPlaying`.
diff --git a/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs b/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs
index 75b6a6e83b..1c505ea107 100644
--- a/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs
+++ b/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs
@@ -184,7 +184,7 @@ namespace osu.Game.Online.Spectator
Header = header;
}
- public int CompareTo(TimedFrame other) => Time.CompareTo(other.Time);
+ public int CompareTo(TimedFrame? other) => Time.CompareTo(other?.Time);
}
}
}
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 8fb6806c27..de9a009f44 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -16,6 +16,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Configuration;
+using osu.Framework.Extensions;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Extensions.TypeExtensions;
using osu.Framework.Graphics;
@@ -332,7 +333,7 @@ namespace osu.Game
/// The link to load.
public void HandleLink(LinkDetails link) => Schedule(() =>
{
- string argString = link.Argument.ToString();
+ string argString = link.Argument.ToString() ?? string.Empty;
switch (link.Action)
{
@@ -406,6 +407,16 @@ namespace osu.Game
if (url.StartsWith('/'))
url = $"{API.APIEndpointUrl}{url}";
+ if (!url.CheckIsValidUrl())
+ {
+ Notifications.Post(new SimpleErrorNotification
+ {
+ Text = $"The URL {url} has an unsupported or dangerous protocol and will not be opened.",
+ });
+
+ return;
+ }
+
externalLinkOpener.OpenUrlExternally(url, bypassExternalUrlWarning);
});
@@ -1029,7 +1040,7 @@ namespace osu.Game
Logger.NewEntry += entry =>
{
- if (entry.Level < LogLevel.Important || entry.Target > LoggingTarget.Database) return;
+ if (entry.Level < LogLevel.Important || entry.Target > LoggingTarget.Database || entry.Target == null) return;
const int short_term_display_limit = 3;
@@ -1043,7 +1054,7 @@ namespace osu.Game
}
else if (recentLogCount == short_term_display_limit)
{
- string logFile = $@"{entry.Target.ToString().ToLowerInvariant()}.log";
+ string logFile = $@"{entry.Target.Value.ToString().ToLowerInvariant()}.log";
Schedule(() => Notifications.Post(new SimpleNotification
{
diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs
index 90863a90a2..671d649dcf 100644
--- a/osu.Game/Overlays/ChangelogOverlay.cs
+++ b/osu.Game/Overlays/ChangelogOverlay.cs
@@ -70,7 +70,7 @@ namespace osu.Game.Overlays
/// are specified, the header will instantly display them.
public void ShowBuild([NotNull] APIChangelogBuild build)
{
- if (build == null) throw new ArgumentNullException(nameof(build));
+ ArgumentNullException.ThrowIfNull(build);
Current.Value = build;
Show();
@@ -78,8 +78,8 @@ namespace osu.Game.Overlays
public void ShowBuild([NotNull] string updateStream, [NotNull] string version)
{
- if (updateStream == null) throw new ArgumentNullException(nameof(updateStream));
- if (version == null) throw new ArgumentNullException(nameof(version));
+ ArgumentNullException.ThrowIfNull(updateStream);
+ ArgumentNullException.ThrowIfNull(version);
performAfterFetch(() =>
{
diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs
index 98e153108f..c539cdc5ec 100644
--- a/osu.Game/Overlays/ChatOverlay.cs
+++ b/osu.Game/Overlays/ChatOverlay.cs
@@ -352,11 +352,13 @@ namespace osu.Game.Overlays
protected virtual DrawableChannel CreateDrawableChannel(Channel newChannel) => new DrawableChannel(newChannel);
- private void joinedChannelsChanged(object sender, NotifyCollectionChangedEventArgs args)
+ private void joinedChannelsChanged(object? sender, NotifyCollectionChangedEventArgs args)
{
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
+ Debug.Assert(args.NewItems != null);
+
IEnumerable newChannels = args.NewItems.OfType().Where(isChatChannel);
foreach (var channel in newChannels)
@@ -365,6 +367,8 @@ namespace osu.Game.Overlays
break;
case NotifyCollectionChangedAction.Remove:
+ Debug.Assert(args.OldItems != null);
+
IEnumerable leftChannels = args.OldItems.OfType().Where(isChatChannel);
foreach (var channel in leftChannels)
@@ -384,7 +388,7 @@ namespace osu.Game.Overlays
}
}
- private void availableChannelsChanged(object sender, NotifyCollectionChangedEventArgs args)
+ private void availableChannelsChanged(object? sender, NotifyCollectionChangedEventArgs args)
=> channelListing.UpdateAvailableChannels(channelManager.AvailableChannels);
private void handleChatMessage(string message)
diff --git a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs
index 664946fc63..9cc20caa05 100644
--- a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs
+++ b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs
@@ -11,7 +11,10 @@ namespace osu.Game.Overlays.Comments
{
public partial class CommentMarkdownContainer : OsuMarkdownContainer
{
- protected override bool Autolinks => true;
+ protected override OsuMarkdownContainerOptions Options => new OsuMarkdownContainerOptions
+ {
+ Autolinks = true
+ };
protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new CommentMarkdownHeading(headingBlock);
diff --git a/osu.Game/Overlays/Comments/CommentReportButton.cs b/osu.Game/Overlays/Comments/CommentReportButton.cs
index 10bd3a64bf..ba5319094b 100644
--- a/osu.Game/Overlays/Comments/CommentReportButton.cs
+++ b/osu.Game/Overlays/Comments/CommentReportButton.cs
@@ -3,6 +3,7 @@
using osu.Framework.Allocation;
using osu.Framework.Extensions;
+using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
@@ -53,7 +54,7 @@ namespace osu.Game.Overlays.Comments
}
};
- link.AddLink(UsersStrings.ReportButtonText, this.ShowPopover);
+ link.AddLink(ReportStrings.CommentButton.ToLower(), this.ShowPopover);
}
private void report(CommentReportReason reason, string comments)
diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs
index 7bada5ef2a..834abd5e9f 100644
--- a/osu.Game/Overlays/Comments/DrawableComment.cs
+++ b/osu.Game/Overlays/Comments/DrawableComment.cs
@@ -19,6 +19,8 @@ using System;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Extensions.IEnumerableExtensions;
using System.Collections.Specialized;
+using System.Diagnostics;
+using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Localisation;
using osu.Framework.Platform;
using osu.Game.Graphics.UserInterface;
@@ -335,7 +337,7 @@ namespace osu.Game.Overlays.Comments
actionsContainer.AddArbitraryDrawable(Empty().With(d => d.Width = 10));
if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id)
- actionsContainer.AddLink(CommonStrings.ButtonsDelete, deleteComment);
+ actionsContainer.AddLink(CommonStrings.ButtonsDelete.ToLower(), deleteComment);
else
actionsContainer.AddArbitraryDrawable(new CommentReportButton(Comment));
@@ -359,6 +361,8 @@ namespace osu.Game.Overlays.Comments
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
+ Debug.Assert(args.NewItems != null);
+
onRepliesAdded(args.NewItems.Cast());
break;
diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs
index 04aa976ff1..8b85bb49a5 100644
--- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs
+++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs
@@ -126,7 +126,8 @@ namespace osu.Game.Overlays.FirstRunSetup
if (available)
{
- copyInformation.Text = "Data migration will use \"hard links\". No extra disk space will be used, and you can delete either data folder at any point without affecting the other installation.";
+ copyInformation.Text =
+ "Data migration will use \"hard links\". No extra disk space will be used, and you can delete either data folder at any point without affecting the other installation.";
}
else if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows)
copyInformation.Text = "Lightweight linking of files is not supported on your operating system yet, so a copy of all files will be made during import.";
@@ -173,6 +174,18 @@ namespace osu.Game.Overlays.FirstRunSetup
c.Current.Disabled = !allow;
}
+ public override void OnSuspending(ScreenTransitionEvent e)
+ {
+ stableLocatorTextBox.HidePopover();
+ base.OnSuspending(e);
+ }
+
+ public override bool OnExiting(ScreenExitEvent e)
+ {
+ stableLocatorTextBox.HidePopover();
+ return base.OnExiting(e);
+ }
+
private partial class ImportCheckbox : SettingsCheckbox
{
public readonly StableContent StableContent;
diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs
index 63688841d0..1bcb1bcdf4 100644
--- a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs
+++ b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs
@@ -13,7 +13,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
using osu.Framework.Localisation;
-using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Graphics;
@@ -58,7 +57,7 @@ namespace osu.Game.Overlays.FirstRunSetup
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.None,
- Size = new Vector2(screen_width, screen_width / 16f * 9 / 2),
+ Size = new Vector2(screen_width, screen_width / 16f * 9),
Children = new Drawable[]
{
new GridContainer
@@ -68,7 +67,6 @@ namespace osu.Game.Overlays.FirstRunSetup
{
new Drawable[]
{
- new SampleScreenContainer(new PinnedMainMenu()),
new SampleScreenContainer(new NestedSongSelect()),
},
// TODO: add more screens here in the future (gameplay / results)
@@ -109,17 +107,6 @@ namespace osu.Game.Overlays.FirstRunSetup
public override bool? AllowTrackAdjustments => false;
}
- private partial class PinnedMainMenu : MainMenu
- {
- public override void OnEntering(ScreenTransitionEvent e)
- {
- base.OnEntering(e);
-
- Buttons.ReturnToTopOnIdle = false;
- Buttons.State = ButtonSystemState.TopLevel;
- }
- }
-
private partial class UIScaleSlider : OsuSliderBar
{
public override LocalisableString TooltipText => base.TooltipText + "x";
diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs
index fe3aaeb9d8..4af40e5ad6 100644
--- a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs
+++ b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs
@@ -87,18 +87,21 @@ namespace osu.Game.Overlays.FirstRunSetup
});
frameworkLocale = frameworkConfig.GetBindable(FrameworkSetting.Locale);
+ frameworkLocale.BindValueChanged(_ => onLanguageChange());
localisationParameters = localisation.CurrentParameters.GetBoundCopy();
- localisationParameters.BindValueChanged(p =>
- {
- var language = LanguageExtensions.GetLanguageFor(frameworkLocale.Value, p.NewValue);
+ localisationParameters.BindValueChanged(_ => onLanguageChange(), true);
+ }
- // Changing language may cause a short period of blocking the UI thread while the new glyphs are loaded.
- // Scheduling ensures the button animation plays smoothly after any blocking operation completes.
- // Note that a delay is required (the alternative would be a double-schedule; delay feels better).
- updateSelectedDelegate?.Cancel();
- updateSelectedDelegate = Scheduler.AddDelayed(() => updateSelectedStates(language), 50);
- }, true);
+ private void onLanguageChange()
+ {
+ var language = LanguageExtensions.GetLanguageFor(frameworkLocale.Value, localisationParameters.Value);
+
+ // Changing language may cause a short period of blocking the UI thread while the new glyphs are loaded.
+ // Scheduling ensures the button animation plays smoothly after any blocking operation completes.
+ // Note that a delay is required (the alternative would be a double-schedule; delay feels better).
+ updateSelectedDelegate?.Cancel();
+ updateSelectedDelegate = Scheduler.AddDelayed(() => updateSelectedStates(language), 50);
}
private void updateSelectedStates(Language language)
@@ -147,7 +150,7 @@ namespace osu.Game.Overlays.FirstRunSetup
[BackgroundDependencyLoader]
private void load()
{
- InternalChildren = new Drawable[]
+ AddRange(new Drawable[]
{
backgroundBox = new Box
{
@@ -162,7 +165,7 @@ namespace osu.Game.Overlays.FirstRunSetup
Colour = colourProvider.Light1,
Text = Language.GetDescription(),
}
- };
+ });
}
protected override void LoadComplete()
diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs
index 45fc9d27ea..f2fdaefbb4 100644
--- a/osu.Game/Overlays/FirstRunSetupOverlay.cs
+++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs
@@ -301,7 +301,7 @@ namespace osu.Game.Overlays
if (currentStepIndex < steps.Count)
{
- var nextScreen = (Screen)Activator.CreateInstance(steps[currentStepIndex.Value]);
+ var nextScreen = (Screen)Activator.CreateInstance(steps[currentStepIndex.Value])!;
loadingShowDelegate = Scheduler.AddDelayed(() => loading.Show(), 200);
nextScreen.OnLoadComplete += _ =>
diff --git a/osu.Game/Overlays/OnScreenDisplay.cs b/osu.Game/Overlays/OnScreenDisplay.cs
index d60077cfa9..4f2dba7b2c 100644
--- a/osu.Game/Overlays/OnScreenDisplay.cs
+++ b/osu.Game/Overlays/OnScreenDisplay.cs
@@ -58,7 +58,7 @@ namespace osu.Game.Overlays
/// If is already being tracked from the same .
public void BeginTracking(object source, ITrackableConfigManager configManager)
{
- if (configManager == null) throw new ArgumentNullException(nameof(configManager));
+ ArgumentNullException.ThrowIfNull(configManager);
if (trackedConfigManagers.ContainsKey((source, configManager)))
throw new InvalidOperationException($"{nameof(configManager)} is already registered.");
@@ -82,7 +82,7 @@ namespace osu.Game.Overlays
/// If is not being tracked from the same .
public void StopTracking(object source, ITrackableConfigManager configManager)
{
- if (configManager == null) throw new ArgumentNullException(nameof(configManager));
+ ArgumentNullException.ThrowIfNull(configManager);
if (!trackedConfigManagers.TryGetValue((source, configManager), out var existing))
return;
diff --git a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs
index 414c6f194a..a31ee88f3b 100644
--- a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs
+++ b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs
@@ -3,7 +3,6 @@
#nullable disable
-using System.Diagnostics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -131,8 +130,6 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
{
var metadata = beatmapInfo.Metadata;
- Debug.Assert(metadata != null);
-
return new Drawable[]
{
new OsuSpriteText
diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
index f1f3ecd4fb..67df4825cc 100644
--- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
+++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs
@@ -4,7 +4,6 @@
#nullable disable
using System;
-using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
@@ -269,8 +268,6 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
{
var metadata = beatmapInfo.Metadata;
- Debug.Assert(metadata != null);
-
return new Drawable[]
{
new OsuSpriteText
diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs
index 24dec44588..9d5e5db6e6 100644
--- a/osu.Game/Overlays/RestoreDefaultValueButton.cs
+++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs
@@ -7,18 +7,20 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Cursor;
+using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osuTK;
namespace osu.Game.Overlays
{
- public partial class RestoreDefaultValueButton : OsuButton, IHasTooltip, IHasCurrentValue
+ public partial class RestoreDefaultValueButton : OsuClickableContainer, IHasCurrentValue
{
public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks;
@@ -51,15 +53,32 @@ namespace osu.Game.Overlays
private const float size = 4;
+ private CircularContainer circle = null!;
+ private Box background = null!;
+
+ public RestoreDefaultValueButton()
+ : base(HoverSampleSet.Button)
+ {
+ }
+
[BackgroundDependencyLoader]
private void load(OsuColour colour)
{
- BackgroundColour = colour.Lime1;
+ // size intentionally much larger than actual drawn content, so that the button is easier to click.
Size = new Vector2(3 * size);
- Content.RelativeSizeAxes = Axes.None;
- Content.Size = new Vector2(size);
- Content.CornerRadius = size / 2;
+ Add(circle = new CircularContainer
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(size),
+ Masking = true,
+ Child = background = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = colour.Lime1
+ }
+ });
Alpha = 0f;
@@ -77,7 +96,7 @@ namespace osu.Game.Overlays
FinishTransforms(true);
}
- public LocalisableString TooltipText => "revert to default";
+ public override LocalisableString TooltipText => "revert to default";
protected override bool OnHover(HoverEvent e)
{
@@ -104,8 +123,8 @@ namespace osu.Game.Overlays
if (!Current.Disabled)
{
this.FadeTo(Current.IsDefault ? 0 : 1, fade_duration, Easing.OutQuint);
- Background.FadeColour(IsHovered ? colours.Lime0 : colours.Lime1, fade_duration, Easing.OutQuint);
- Content.TweenEdgeEffectTo(new EdgeEffectParameters
+ background.FadeColour(IsHovered ? colours.Lime0 : colours.Lime1, fade_duration, Easing.OutQuint);
+ circle.TweenEdgeEffectTo(new EdgeEffectParameters
{
Colour = (IsHovered ? colours.Lime1 : colours.Lime3).Opacity(0.4f),
Radius = IsHovered ? 8 : 4,
@@ -114,8 +133,8 @@ namespace osu.Game.Overlays
}
else
{
- Background.FadeColour(colours.Lime3, fade_duration, Easing.OutQuint);
- Content.TweenEdgeEffectTo(new EdgeEffectParameters
+ background.FadeColour(colours.Lime3, fade_duration, Easing.OutQuint);
+ circle.TweenEdgeEffectTo(new EdgeEffectParameters
{
Colour = colours.Lime3.Opacity(0.1f),
Radius = 2,
diff --git a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs
index a4ec919658..982cbec376 100644
--- a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs
@@ -44,10 +44,13 @@ namespace osu.Game.Overlays.Settings.Sections.General
},
};
- localisationParameters.BindValueChanged(p
- => languageSelection.Current.Value = LanguageExtensions.GetLanguageFor(frameworkLocale.Value, p.NewValue), true);
+ frameworkLocale.BindValueChanged(_ => updateSelection());
+ localisationParameters.BindValueChanged(_ => updateSelection(), true);
languageSelection.Current.BindValueChanged(val => frameworkLocale.Value = val.NewValue.ToCultureCode());
}
+
+ private void updateSelection() =>
+ languageSelection.Current.Value = LanguageExtensions.GetLanguageFor(frameworkLocale.Value, localisationParameters.Value);
}
}
diff --git a/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs b/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs
index dcdb15fc19..19f0d0f7d1 100644
--- a/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs
+++ b/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs
@@ -3,7 +3,6 @@
#nullable disable
-using System.Diagnostics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
@@ -29,8 +28,6 @@ namespace osu.Game.Overlays.Settings.Sections.Input
var r = ruleset.CreateInstance();
- Debug.Assert(r != null);
-
foreach (int variant in r.AvailableVariants)
Add(new VariantBindingsSubsection(ruleset, variant));
}
diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
index 826a1e7404..f75656cc99 100644
--- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs
+++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs
@@ -105,6 +105,7 @@ namespace osu.Game.Overlays.Settings.Sections
dropdownItems.Clear();
dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.ARGON_SKIN).ToLive(realm));
+ dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.ARGON_PRO_SKIN).ToLive(realm));
dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.TRIANGLES_SKIN).ToLive(realm));
dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.CLASSIC_SKIN).ToLive(realm));
diff --git a/osu.Game/Overlays/Volume/MuteButton.cs b/osu.Game/Overlays/Volume/MuteButton.cs
index 3bea1c840e..9cc346a38b 100644
--- a/osu.Game/Overlays/Volume/MuteButton.cs
+++ b/osu.Game/Overlays/Volume/MuteButton.cs
@@ -28,8 +28,7 @@ namespace osu.Game.Overlays.Volume
get => current;
set
{
- if (value == null)
- throw new ArgumentNullException(nameof(value));
+ ArgumentNullException.ThrowIfNull(value);
current.UnbindBindings();
current.BindTo(value);
diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs
index 4ef9be90c9..7c36caa62f 100644
--- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs
+++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs
@@ -16,8 +16,12 @@ namespace osu.Game.Overlays.Wiki.Markdown
{
public partial class WikiMarkdownContainer : OsuMarkdownContainer
{
- protected override bool Footnotes => true;
- protected override bool CustomContainers => true;
+ protected override OsuMarkdownContainerOptions Options => new OsuMarkdownContainerOptions
+ {
+ Footnotes = true,
+ CustomContainers = true,
+ BlockAttributes = true
+ };
public string CurrentPath
{
diff --git a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs
index 9d9c10b3ea..38ced4c9e7 100644
--- a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs
+++ b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs
@@ -126,8 +126,7 @@ namespace osu.Game.Rulesets.Mods
get => this;
set
{
- if (value == null)
- throw new ArgumentNullException(nameof(value));
+ ArgumentNullException.ThrowIfNull(value);
if (currentBound != null) UnbindFrom(currentBound);
BindTo(currentBound = value);
diff --git a/osu.Game/Rulesets/Mods/IMod.cs b/osu.Game/Rulesets/Mods/IMod.cs
index 1f9e26c9d7..05b2510e53 100644
--- a/osu.Game/Rulesets/Mods/IMod.cs
+++ b/osu.Game/Rulesets/Mods/IMod.cs
@@ -55,6 +55,6 @@ namespace osu.Game.Rulesets.Mods
///
/// Create a fresh instance based on this mod.
///
- Mod CreateInstance() => (Mod)Activator.CreateInstance(GetType());
+ Mod CreateInstance() => (Mod)Activator.CreateInstance(GetType())!;
}
}
diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs
index 98df540de4..04d55bc5fe 100644
--- a/osu.Game/Rulesets/Mods/Mod.cs
+++ b/osu.Game/Rulesets/Mods/Mod.cs
@@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Mods
foreach ((SettingSourceAttribute attr, PropertyInfo property) in this.GetOrderedSettingsSourceProperties())
{
- var bindable = (IBindable)property.GetValue(this);
+ var bindable = (IBindable)property.GetValue(this)!;
if (!bindable.IsDefault)
tooltipTexts.Add($"{attr.Label} {bindable}");
@@ -134,7 +134,7 @@ namespace osu.Game.Rulesets.Mods
///
public virtual Mod DeepClone()
{
- var result = (Mod)Activator.CreateInstance(GetType());
+ var result = (Mod)Activator.CreateInstance(GetType())!;
result.CopyFrom(this);
return result;
}
@@ -150,8 +150,8 @@ namespace osu.Game.Rulesets.Mods
foreach (var (_, prop) in this.GetSettingsSourceProperties())
{
- var targetBindable = (IBindable)prop.GetValue(this);
- var sourceBindable = (IBindable)prop.GetValue(source);
+ var targetBindable = (IBindable)prop.GetValue(this)!;
+ var sourceBindable = (IBindable)prop.GetValue(source)!;
CopyAdjustedSetting(targetBindable, sourceBindable);
}
@@ -183,9 +183,9 @@ namespace osu.Game.Rulesets.Mods
}
}
- public bool Equals(IMod other) => other is Mod them && Equals(them);
+ public bool Equals(IMod? other) => other is Mod them && Equals(them);
- public bool Equals(Mod other)
+ public bool Equals(Mod? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
@@ -209,16 +209,16 @@ namespace osu.Game.Rulesets.Mods
///
/// Reset all custom settings for this mod back to their defaults.
///
- public virtual void ResetSettingsToDefaults() => CopyFrom((Mod)Activator.CreateInstance(GetType()));
+ public virtual void ResetSettingsToDefaults() => CopyFrom((Mod)Activator.CreateInstance(GetType())!);
private class ModSettingsEqualityComparer : IEqualityComparer
{
public static ModSettingsEqualityComparer Default { get; } = new ModSettingsEqualityComparer();
- public bool Equals(IBindable x, IBindable y)
+ public bool Equals(IBindable? x, IBindable? y)
{
- object xValue = x.GetUnderlyingSettingValue();
- object yValue = y.GetUnderlyingSettingValue();
+ object? xValue = x?.GetUnderlyingSettingValue();
+ object? yValue = y?.GetUnderlyingSettingValue();
return EqualityComparer.Default.Equals(xValue, yValue);
}
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index 096132d024..be5a7f71e7 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -208,8 +208,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
///
public void Apply([NotNull] HitObject hitObject)
{
- if (hitObject == null)
- throw new ArgumentNullException($"Cannot apply a null {nameof(HitObject)}.");
+ ArgumentNullException.ThrowIfNull(hitObject);
Apply(new SyntheticHitObjectEntry(hitObject));
}
diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs
index ddc121eb5b..c9d2928dc3 100644
--- a/osu.Game/Rulesets/Objects/SliderPath.cs
+++ b/osu.Game/Rulesets/Objects/SliderPath.cs
@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Diagnostics;
using System.Linq;
using Newtonsoft.Json;
using osu.Framework.Bindables;
@@ -57,12 +58,16 @@ namespace osu.Game.Rulesets.Objects
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
+ Debug.Assert(args.NewItems != null);
+
foreach (var c in args.NewItems.Cast())
c.Changed += invalidate;
break;
case NotifyCollectionChangedAction.Reset:
case NotifyCollectionChangedAction.Remove:
+ Debug.Assert(args.OldItems != null);
+
foreach (var c in args.OldItems.Cast())
c.Changed -= invalidate;
break;
diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs
index a446210c8a..a73151362b 100644
--- a/osu.Game/Rulesets/Ruleset.cs
+++ b/osu.Game/Rulesets/Ruleset.cs
@@ -89,6 +89,8 @@ namespace osu.Game.Rulesets
// Confine all mods of each mod type into a single IEnumerable
.SelectMany(GetModsFor)
// Filter out all null mods
+ // This is to handle old rulesets which were doing mods bad. Can be removed at some point we are sure nulls will not appear here.
+ // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
.Where(mod => mod != null)
// Resolve MultiMods as their .Mods property
.SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod });
diff --git a/osu.Game/Rulesets/RulesetInfo.cs b/osu.Game/Rulesets/RulesetInfo.cs
index 91954320a4..6a4e0f0b48 100644
--- a/osu.Game/Rulesets/RulesetInfo.cs
+++ b/osu.Game/Rulesets/RulesetInfo.cs
@@ -53,21 +53,21 @@ namespace osu.Game.Rulesets
public bool Equals(IRulesetInfo? other) => other is RulesetInfo r && Equals(r);
- public int CompareTo(RulesetInfo other)
+ public int CompareTo(RulesetInfo? other)
{
- if (OnlineID >= 0 && other.OnlineID >= 0)
+ if (OnlineID >= 0 && other?.OnlineID >= 0)
return OnlineID.CompareTo(other.OnlineID);
// Official rulesets are always given precedence for the time being.
if (OnlineID >= 0)
return -1;
- if (other.OnlineID >= 0)
+ if (other?.OnlineID >= 0)
return 1;
- return string.Compare(ShortName, other.ShortName, StringComparison.Ordinal);
+ return string.Compare(ShortName, other?.ShortName, StringComparison.Ordinal);
}
- public int CompareTo(IRulesetInfo other)
+ public int CompareTo(IRulesetInfo? other)
{
if (!(other is RulesetInfo ruleset))
throw new ArgumentException($@"Object is not of type {nameof(RulesetInfo)}.", nameof(other));
diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs
index e2b8cd2c4e..881b09bd1b 100644
--- a/osu.Game/Rulesets/RulesetStore.cs
+++ b/osu.Game/Rulesets/RulesetStore.cs
@@ -75,10 +75,7 @@ namespace osu.Game.Rulesets
return false;
return args.Name.Contains(name, StringComparison.Ordinal);
- })
- // Pick the greatest assembly version.
- .OrderByDescending(a => a.GetName().Version)
- .FirstOrDefault();
+ }).MaxBy(a => a.GetName().Version);
if (domainAssembly != null)
return domainAssembly;
@@ -114,7 +111,10 @@ namespace osu.Game.Rulesets
{
try
{
- string[] files = Directory.GetFiles(RuntimeInfo.StartupDirectory, @$"{ruleset_library_prefix}.*.dll");
+ // On net6-android (Debug), StartupDirectory can be different from where assemblies are placed.
+ // Search sub-directories too.
+
+ string[] files = Directory.GetFiles(RuntimeInfo.StartupDirectory, @$"{ruleset_library_prefix}.*.dll", SearchOption.AllDirectories);
foreach (string file in files.Where(f => !Path.GetFileName(f).Contains("Tests")))
loadRulesetFromFile(file);
@@ -127,7 +127,7 @@ namespace osu.Game.Rulesets
private void loadRulesetFromFile(string file)
{
- string? filename = Path.GetFileNameWithoutExtension(file);
+ string filename = Path.GetFileNameWithoutExtension(file);
if (LoadedAssemblies.Values.Any(t => Path.GetFileNameWithoutExtension(t.Assembly.Location) == filename))
return;
@@ -158,7 +158,7 @@ namespace osu.Game.Rulesets
}
catch (Exception e)
{
- LogFailedLoad(assembly.GetName().Name.Split('.').Last(), e);
+ LogFailedLoad(assembly.GetName().Name!.Split('.').Last(), e);
}
}
diff --git a/osu.Game/Rulesets/Scoring/HealthProcessor.cs b/osu.Game/Rulesets/Scoring/HealthProcessor.cs
index cdfe71943e..b70ddd5e24 100644
--- a/osu.Game/Rulesets/Scoring/HealthProcessor.cs
+++ b/osu.Game/Rulesets/Scoring/HealthProcessor.cs
@@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Scoring
{
foreach (var condition in FailConditions.GetInvocationList())
{
- bool conditionResult = (bool)condition.Method.Invoke(condition.Target, new object[] { this, result });
+ bool conditionResult = (bool)condition.Method.Invoke(condition.Target, new object[] { this, result })!;
if (conditionResult)
return true;
}
diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs
index b048566c8a..4228840461 100644
--- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs
+++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs
@@ -534,7 +534,7 @@ namespace osu.Game.Rulesets.Scoring
break;
default:
- maxResult = maxBasicResult ??= ruleset.GetHitResults().OrderByDescending(kvp => Judgement.ToNumericResult(kvp.result)).First().result;
+ maxResult = maxBasicResult ??= ruleset.GetHitResults().MaxBy(kvp => Judgement.ToNumericResult(kvp.result)).result;
break;
}
diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs
index d068f8d016..d2244df3b8 100644
--- a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs
+++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs
@@ -79,9 +79,7 @@ namespace osu.Game.Rulesets.UI
// We need to use lifetime entries to find the next object (we can't just use `hitObjectContainer.Objects` due to pooling - it may even be empty).
// If required, we can make this lookup more efficient by adding support to get next-future-entry in LifetimeEntryManager.
fallbackObject = hitObjectContainer.Entries
- .Where(e => e.Result?.HasResult != true)
- .OrderBy(e => e.HitObject.StartTime)
- .FirstOrDefault();
+ .Where(e => e.Result?.HasResult != true).MinBy(e => e.HitObject.StartTime);
// In the case there are no unjudged objects, the last hit object should be used instead.
fallbackObject ??= hitObjectContainer.Entries.LastOrDefault();
diff --git a/osu.Game/Rulesets/UI/JudgementContainer.cs b/osu.Game/Rulesets/UI/JudgementContainer.cs
index 8381e6d6b5..7181e80206 100644
--- a/osu.Game/Rulesets/UI/JudgementContainer.cs
+++ b/osu.Game/Rulesets/UI/JudgementContainer.cs
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.UI
{
public override void Add(T judgement)
{
- if (judgement == null) throw new ArgumentNullException(nameof(judgement));
+ ArgumentNullException.ThrowIfNull(judgement);
// remove any existing judgements for the judged object.
// this can be the case when rewinding.
diff --git a/osu.Game/Scoring/ScoreImporter.cs b/osu.Game/Scoring/ScoreImporter.cs
index 4656f02897..a3d7fe5de0 100644
--- a/osu.Game/Scoring/ScoreImporter.cs
+++ b/osu.Game/Scoring/ScoreImporter.cs
@@ -71,8 +71,8 @@ namespace osu.Game.Scoring
// These properties are known to be non-null, but these final checks ensure a null hasn't come from somewhere (or the refetch has failed).
// Under no circumstance do we want these to be written to realm as null.
- if (model.BeatmapInfo == null) throw new ArgumentNullException(nameof(model.BeatmapInfo));
- if (model.Ruleset == null) throw new ArgumentNullException(nameof(model.Ruleset));
+ ArgumentNullException.ThrowIfNull(model.BeatmapInfo);
+ ArgumentNullException.ThrowIfNull(model.Ruleset);
PopulateMaximumStatistics(model);
@@ -101,8 +101,7 @@ namespace osu.Game.Scoring
// Populate the maximum statistics.
HitResult maxBasicResult = rulesetInstance.GetHitResults()
.Select(h => h.result)
- .Where(h => h.IsBasic())
- .OrderByDescending(Judgement.ToNumericResult).First();
+ .Where(h => h.IsBasic()).MaxBy(Judgement.ToNumericResult);
foreach ((HitResult result, int count) in score.Statistics)
{
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index a9ced62c95..1009474d89 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -317,7 +317,7 @@ namespace osu.Game.Scoring
#endregion
- public bool Equals(ScoreInfo other) => other.ID == ID;
+ public bool Equals(ScoreInfo? other) => other?.ID == ID;
public override string ToString() => this.GetDisplayTitle();
}
diff --git a/osu.Game/Scoring/ScoreModelDownloader.cs b/osu.Game/Scoring/ScoreModelDownloader.cs
index 514b7a57de..c5434e8faf 100644
--- a/osu.Game/Scoring/ScoreModelDownloader.cs
+++ b/osu.Game/Scoring/ScoreModelDownloader.cs
@@ -17,7 +17,7 @@ namespace osu.Game.Scoring
protected override ArchiveDownloadRequest CreateDownloadRequest(IScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score);
- public override ArchiveDownloadRequest GetExistingDownload(IScoreInfo model)
+ public override ArchiveDownloadRequest? GetExistingDownload(IScoreInfo model)
=> CurrentDownloads.Find(r => r.Model.MatchesOnlineID(model));
}
}
diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs
index 2d26e6f90b..111ba0b732 100644
--- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs
+++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Specialized;
+using System.Diagnostics;
using System.Linq;
using osu.Framework.Bindables;
using osu.Game.Beatmaps.ControlPoints;
@@ -33,6 +34,8 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
break;
case NotifyCollectionChangedAction.Add:
+ Debug.Assert(args.NewItems != null);
+
foreach (var group in args.NewItems.OfType())
{
// as an optimisation, don't add a visualisation if there are already groups with the same types in close proximity.
@@ -47,6 +50,8 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
break;
case NotifyCollectionChangedAction.Remove:
+ Debug.Assert(args.OldItems != null);
+
foreach (var group in args.OldItems.OfType())
{
var matching = Children.SingleOrDefault(gv => ReferenceEquals(gv.Group, group));
diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
index 903c117422..9f422d5aa9 100644
--- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
@@ -479,7 +479,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
// copied from SliderBar so we can do custom spacing logic.
float xPosition = (ToLocalSpace(screenSpaceMousePosition).X - RangePadding) / UsableWidth;
- CurrentNumber.Value = beatDivisor.ValidDivisors.Value.Presets.OrderBy(d => Math.Abs(getMappedPosition(d) - xPosition)).First();
+ CurrentNumber.Value = beatDivisor.ValidDivisors.Value.Presets.MinBy(d => Math.Abs(getMappedPosition(d) - xPosition));
OnUserChange(Current.Value);
}
diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
index 60fec5bcc6..77892f21e6 100644
--- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs
@@ -58,6 +58,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
+ Debug.Assert(args.NewItems != null);
+
foreach (object o in args.NewItems)
{
if (blueprintMap.TryGetValue((T)o, out var blueprint))
@@ -67,6 +69,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
break;
case NotifyCollectionChangedAction.Remove:
+ Debug.Assert(args.OldItems != null);
+
foreach (object o in args.OldItems)
{
if (blueprintMap.TryGetValue((T)o, out var blueprint))
diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs
index 9783c4184a..29983c9cbf 100644
--- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs
@@ -4,6 +4,7 @@
#nullable disable
using System.Collections.Specialized;
+using System.Diagnostics;
using System.Linq;
using osu.Framework.Bindables;
using osu.Game.Beatmaps.ControlPoints;
@@ -33,11 +34,15 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
break;
case NotifyCollectionChangedAction.Add:
+ Debug.Assert(args.NewItems != null);
+
foreach (var group in args.NewItems.OfType())
Add(new TimelineControlPointGroup(group));
break;
case NotifyCollectionChangedAction.Remove:
+ Debug.Assert(args.OldItems != null);
+
foreach (var group in args.OldItems.OfType())
{
var matching = Children.SingleOrDefault(gv => ReferenceEquals(gv.Group, group));
diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs
index 28f7731354..951f4129d4 100644
--- a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs
@@ -99,9 +99,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
minZoom = minimum;
maxZoom = maximum;
- CurrentZoom = zoomTarget = initial;
- isZoomSetUp = true;
+ CurrentZoom = zoomTarget = initial;
+ zoomedContentWidthCache.Invalidate();
+
+ isZoomSetUp = true;
zoomedContent.Show();
}
diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs
index 3af7a400e2..dc026f7eac 100644
--- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs
+++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs
@@ -152,7 +152,7 @@ namespace osu.Game.Screens.Edit.Compose
if (composer == null)
return string.Empty;
- double displayTime = EditorBeatmap.SelectedHitObjects.OrderBy(h => h.StartTime).FirstOrDefault()?.StartTime ?? clock.CurrentTime;
+ double displayTime = EditorBeatmap.SelectedHitObjects.MinBy(h => h.StartTime)?.StartTime ?? clock.CurrentTime;
string selectionAsString = composer.ConvertSelectionToString();
return !string.IsNullOrEmpty(selectionAsString)
diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs
index e204b44db3..1554bf1bb1 100644
--- a/osu.Game/Screens/Edit/EditorBeatmap.cs
+++ b/osu.Game/Screens/Edit/EditorBeatmap.cs
@@ -304,7 +304,7 @@ namespace osu.Game.Screens.Edit
/// The index of the to remove.
public void RemoveAt(int index)
{
- var hitObject = (HitObject)mutableHitObjects[index];
+ HitObject hitObject = (HitObject)mutableHitObjects[index]!;
mutableHitObjects.RemoveAt(index);
diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs
index c67850bdf6..5000a97b3d 100644
--- a/osu.Game/Screens/Menu/LogoVisualisation.cs
+++ b/osu.Game/Screens/Menu/LogoVisualisation.cs
@@ -147,7 +147,7 @@ namespace osu.Game.Screens.Menu
private void addAmplitudesFromSource(IHasAmplitudes source)
{
- if (source == null) throw new ArgumentNullException(nameof(source));
+ ArgumentNullException.ThrowIfNull(source);
var amplitudes = source.CurrentAmplitudes.FrequencyAmplitudes.Span;
diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs
index 3b66355dab..c31633eefc 100644
--- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs
+++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs
@@ -4,6 +4,7 @@
#nullable disable
using System.Collections.Specialized;
+using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -197,11 +198,15 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
+ Debug.Assert(e.NewItems != null);
+
foreach (var added in e.NewItems.OfType())
addUser(added);
break;
case NotifyCollectionChangedAction.Remove:
+ Debug.Assert(e.OldItems != null);
+
foreach (var removed in e.OldItems.OfType())
removeUser(removed);
break;
diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs
index e723dfe3e6..ac6403bb34 100644
--- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs
+++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs
@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -117,10 +118,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
+ Debug.Assert(args.NewItems != null);
+
addRooms(args.NewItems.Cast());
break;
case NotifyCollectionChangedAction.Remove:
+ Debug.Assert(args.OldItems != null);
+
removeRooms(args.OldItems.Cast());
break;
}
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs
index fe27e2cf20..2d2aa0f1d5 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs
@@ -34,7 +34,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
///
/// Whether all spectating players have finished loading.
///
- public bool AllPlayersLoaded => instances.All(p => p?.PlayerLoaded == true);
+ public bool AllPlayersLoaded => instances.All(p => p.PlayerLoaded);
protected override UserActivity InitialActivity => new UserActivity.SpectatingMultiplayerGame(Beatmap.Value.BeatmapInfo, Ruleset.Value);
@@ -171,9 +171,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
if (!isCandidateAudioSource(currentAudioSource?.SpectatorPlayerClock))
{
- currentAudioSource = instances.Where(i => isCandidateAudioSource(i.SpectatorPlayerClock))
- .OrderBy(i => Math.Abs(i.SpectatorPlayerClock.CurrentTime - syncManager.CurrentMasterTime))
- .FirstOrDefault();
+ currentAudioSource = instances.Where(i => isCandidateAudioSource(i.SpectatorPlayerClock)).MinBy(i => Math.Abs(i.SpectatorPlayerClock.CurrentTime - syncManager.CurrentMasterTime));
// Only bind adjustments if there's actually a valid source, else just use the previous ones to ensure no sudden changes to audio.
if (currentAudioSource != null)
diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs
index 50a9992f4f..e93f56c2e2 100644
--- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs
+++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs
@@ -349,7 +349,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
public void SelectBeatmap() => editPlaylistButton.TriggerClick();
- private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) =>
+ private void onPlaylistChanged(object? sender, NotifyCollectionChangedEventArgs e) =>
playlistLength.Text = $"Length: {Playlist.GetTotalDuration()}";
private bool hasValidSettings => RoomID.Value == null && NameField.Text.Length > 0 && Playlist.Count > 0;
diff --git a/osu.Game/Screens/Play/HUD/ModDisplay.cs b/osu.Game/Screens/Play/HUD/ModDisplay.cs
index 3b50a22e3c..8b2b8f9464 100644
--- a/osu.Game/Screens/Play/HUD/ModDisplay.cs
+++ b/osu.Game/Screens/Play/HUD/ModDisplay.cs
@@ -33,8 +33,7 @@ namespace osu.Game.Screens.Play.HUD
get => current.Current;
set
{
- if (value == null)
- throw new ArgumentNullException(nameof(value));
+ ArgumentNullException.ThrowIfNull(value);
current.Current = value;
}
diff --git a/osu.Game/Screens/Play/HUD/ModFlowDisplay.cs b/osu.Game/Screens/Play/HUD/ModFlowDisplay.cs
index 23030e640b..38027c64ac 100644
--- a/osu.Game/Screens/Play/HUD/ModFlowDisplay.cs
+++ b/osu.Game/Screens/Play/HUD/ModFlowDisplay.cs
@@ -30,8 +30,7 @@ namespace osu.Game.Screens.Play.HUD
get => current.Current;
set
{
- if (value == null)
- throw new ArgumentNullException(nameof(value));
+ ArgumentNullException.ThrowIfNull(value);
current.Current = value;
}
diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs
index 2743173a6d..620f3718c2 100644
--- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs
+++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Diagnostics;
using System.Linq;
using System.Threading;
using osu.Framework.Allocation;
@@ -153,11 +154,13 @@ namespace osu.Game.Screens.Play.HUD
}
}
- private void playingUsersChanged(object sender, NotifyCollectionChangedEventArgs e)
+ private void playingUsersChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Remove:
+ Debug.Assert(e.OldItems != null);
+
foreach (int userId in e.OldItems.OfType())
{
spectatorClient.StopWatchingUser(userId);
diff --git a/osu.Game/Screens/Play/HUD/SkinnableInfo.cs b/osu.Game/Screens/Play/HUD/SkinnableInfo.cs
index 6d63776dbb..da759b4329 100644
--- a/osu.Game/Screens/Play/HUD/SkinnableInfo.cs
+++ b/osu.Game/Screens/Play/HUD/SkinnableInfo.cs
@@ -67,7 +67,7 @@ namespace osu.Game.Screens.Play.HUD
foreach (var (_, property) in component.GetSettingsSourceProperties())
{
- var bindable = (IBindable)property.GetValue(component);
+ var bindable = (IBindable)property.GetValue(component)!;
if (!bindable.IsDefault)
Settings.Add(property.Name.ToSnakeCase(), bindable.GetUnderlyingSettingValue());
@@ -88,7 +88,7 @@ namespace osu.Game.Screens.Play.HUD
{
try
{
- Drawable d = (Drawable)Activator.CreateInstance(Type);
+ Drawable d = (Drawable)Activator.CreateInstance(Type)!;
d.ApplySkinnableInfo(this);
return d;
}
diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs
index d9ad3cfaf7..bb50d4a539 100644
--- a/osu.Game/Screens/Play/KeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs
@@ -54,7 +54,7 @@ namespace osu.Game.Screens.Play
public override void Add(KeyCounter key)
{
- if (key == null) throw new ArgumentNullException(nameof(key));
+ ArgumentNullException.ThrowIfNull(key);
base.Add(key);
key.IsCounting = IsCounting;
diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs
index 4c507f8c67..5fa6508a31 100644
--- a/osu.Game/Screens/Play/SubmittingPlayer.cs
+++ b/osu.Game/Screens/Play/SubmittingPlayer.cs
@@ -13,6 +13,7 @@ using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Online.API;
+using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Online.Spectator;
using osu.Game.Rulesets.Scoring;
@@ -130,6 +131,7 @@ namespace osu.Game.Screens.Play
score.ScoreInfo.Date = DateTimeOffset.Now;
await submitScore(score).ConfigureAwait(false);
+ spectatorClient.EndPlaying(GameplayState);
}
[Resolved]
@@ -157,8 +159,11 @@ namespace osu.Game.Screens.Play
if (LoadedBeatmapSuccessfully)
{
- submitScore(Score.DeepClone());
- spectatorClient.EndPlaying(GameplayState);
+ Task.Run(async () =>
+ {
+ await submitScore(Score.DeepClone()).ConfigureAwait(false);
+ spectatorClient.EndPlaying(GameplayState);
+ }).FireAndForget();
}
return exiting;
diff --git a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs
index 8ff6d3cf4f..212cebeaf5 100644
--- a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs
+++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs
@@ -259,10 +259,7 @@ namespace osu.Game.Screens.Utility
var displayMode = host.Window?.CurrentDisplayMode.Value;
- string exclusive = "unknown";
-
- if (host.Renderer is IWindowsRenderer windowsRenderer)
- exclusive = windowsRenderer.FullscreenCapability.ToString();
+ string exclusive = (host.Renderer as IWindowsRenderer)?.FullscreenCapability.ToString() ?? "unknown";
statusText.Clear();
diff --git a/osu.Game/Skinning/ArgonProSkin.cs b/osu.Game/Skinning/ArgonProSkin.cs
new file mode 100644
index 0000000000..b753dd8fbe
--- /dev/null
+++ b/osu.Game/Skinning/ArgonProSkin.cs
@@ -0,0 +1,48 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using JetBrains.Annotations;
+using osu.Framework.Audio.Sample;
+using osu.Game.Audio;
+using osu.Game.Extensions;
+using osu.Game.IO;
+
+namespace osu.Game.Skinning
+{
+ public class ArgonProSkin : ArgonSkin
+ {
+ public new static SkinInfo CreateInfo() => new SkinInfo
+ {
+ ID = Skinning.SkinInfo.ARGON_PRO_SKIN,
+ Name = "osu! \"argon\" pro (2022)",
+ Creator = "team osu!",
+ Protected = true,
+ InstantiationInfo = typeof(ArgonProSkin).GetInvariantInstantiationInfo()
+ };
+
+ public override ISample? GetSample(ISampleInfo sampleInfo)
+ {
+ foreach (string lookup in sampleInfo.LookupNames)
+ {
+ string remappedLookup = lookup.Replace(@"Gameplay/", @"Gameplay/ArgonPro/");
+
+ var sample = Samples?.Get(remappedLookup) ?? Resources.AudioManager?.Samples.Get(remappedLookup);
+ if (sample != null)
+ return sample;
+ }
+
+ return null;
+ }
+
+ public ArgonProSkin(IStorageResourceProvider resources)
+ : this(CreateInfo(), resources)
+ {
+ }
+
+ [UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)]
+ public ArgonProSkin(SkinInfo skin, IStorageResourceProvider resources)
+ : base(skin, resources)
+ {
+ }
+ }
+}
diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs
index 6a0c4a23e5..d78147aaea 100644
--- a/osu.Game/Skinning/ArgonSkin.cs
+++ b/osu.Game/Skinning/ArgonSkin.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Skinning
InstantiationInfo = typeof(ArgonSkin).GetInvariantInstantiationInfo()
};
- private readonly IStorageResourceProvider resources;
+ protected readonly IStorageResourceProvider Resources;
public ArgonSkin(IStorageResourceProvider resources)
: this(CreateInfo(), resources)
@@ -41,7 +41,7 @@ namespace osu.Game.Skinning
public ArgonSkin(SkinInfo skin, IStorageResourceProvider resources)
: base(skin, resources)
{
- this.resources = resources;
+ Resources = resources;
Configuration.CustomComboColours = new List
{
@@ -72,7 +72,7 @@ namespace osu.Game.Skinning
{
foreach (string lookup in sampleInfo.LookupNames)
{
- var sample = Samples?.Get(lookup) ?? resources.AudioManager?.Samples.Get(lookup);
+ var sample = Samples?.Get(lookup) ?? Resources.AudioManager?.Samples.Get(lookup);
if (sample != null)
return sample;
}
diff --git a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs
index 8e9256214f..9812406aad 100644
--- a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs
+++ b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -65,17 +66,24 @@ namespace osu.Game.Skinning.Editor
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
+ Debug.Assert(e.NewItems != null);
+
foreach (var item in e.NewItems.Cast())
AddBlueprintFor(item);
break;
case NotifyCollectionChangedAction.Remove:
case NotifyCollectionChangedAction.Reset:
+ Debug.Assert(e.OldItems != null);
+
foreach (var item in e.OldItems.Cast())
RemoveBlueprintFor(item);
break;
case NotifyCollectionChangedAction.Replace:
+ Debug.Assert(e.NewItems != null);
+ Debug.Assert(e.OldItems != null);
+
foreach (var item in e.OldItems.Cast())
RemoveBlueprintFor(item);
diff --git a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs
index 68ac84df48..053119557f 100644
--- a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs
+++ b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using System;
-using System.Diagnostics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -59,9 +58,7 @@ namespace osu.Game.Skinning.Editor
{
try
{
- var instance = (Drawable)Activator.CreateInstance(type);
-
- Debug.Assert(instance != null);
+ Drawable instance = (Drawable)Activator.CreateInstance(type)!;
if (!((ISkinnableDrawable)instance).IsEditable) return;
diff --git a/osu.Game/Skinning/GameplaySkinComponentLookup.cs b/osu.Game/Skinning/GameplaySkinComponentLookup.cs
index 2d1dec4691..9247ca0e4d 100644
--- a/osu.Game/Skinning/GameplaySkinComponentLookup.cs
+++ b/osu.Game/Skinning/GameplaySkinComponentLookup.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Skinning
}
protected virtual string RulesetPrefix => string.Empty;
- protected virtual string ComponentName => Component.ToString();
+ protected virtual string ComponentName => Component.ToString() ?? string.Empty;
public string LookupName =>
string.Join('/', new[] { "Gameplay", RulesetPrefix, ComponentName }.Where(s => !string.IsNullOrEmpty(s)));
diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs
index ea223d172d..5f12d2ce23 100644
--- a/osu.Game/Skinning/LegacySkin.cs
+++ b/osu.Game/Skinning/LegacySkin.cs
@@ -105,7 +105,7 @@ namespace osu.Game.Skinning
return SkinUtils.As(GetComboColour(Configuration, comboColour.ColourIndex, comboColour.Combo));
case SkinCustomColourLookup customColour:
- return SkinUtils.As(getCustomColour(Configuration, customColour.Lookup.ToString()));
+ return SkinUtils.As(getCustomColour(Configuration, customColour.Lookup.ToString() ?? string.Empty));
case LegacyManiaSkinConfigurationLookup maniaLookup:
if (!AllowManiaSkin)
@@ -277,7 +277,7 @@ namespace osu.Game.Skinning
=> source.CustomColours.TryGetValue(lookup, out var col) ? new Bindable(col) : null;
private IBindable? getManiaImage(LegacyManiaSkinConfiguration source, string lookup)
- => source.ImageLookups.TryGetValue(lookup, out string image) ? new Bindable(image) : null;
+ => source.ImageLookups.TryGetValue(lookup, out string? image) ? new Bindable(image) : null;
private IBindable? legacySettingLookup(SkinConfiguration.LegacySetting legacySetting)
where TValue : notnull
@@ -298,7 +298,7 @@ namespace osu.Game.Skinning
{
try
{
- if (Configuration.ConfigDictionary.TryGetValue(lookup.ToString(), out string val))
+ if (Configuration.ConfigDictionary.TryGetValue(lookup.ToString() ?? string.Empty, out string? val))
{
// special case for handling skins which use 1 or 0 to signify a boolean state.
// ..or in some cases 2 (https://github.com/ppy/osu/issues/18579).
diff --git a/osu.Game/Skinning/RealmBackedResourceStore.cs b/osu.Game/Skinning/RealmBackedResourceStore.cs
index 0cc90f1dcb..cc887a7a61 100644
--- a/osu.Game/Skinning/RealmBackedResourceStore.cs
+++ b/osu.Game/Skinning/RealmBackedResourceStore.cs
@@ -52,7 +52,7 @@ namespace osu.Game.Skinning
private string? getPathForFile(string filename)
{
- if (fileToStoragePathMapping.Value.TryGetValue(filename.ToLowerInvariant(), out string path))
+ if (fileToStoragePathMapping.Value.TryGetValue(filename.ToLowerInvariant(), out string? path))
return path;
return null;
diff --git a/osu.Game/Skinning/SkinImporter.cs b/osu.Game/Skinning/SkinImporter.cs
index f594a7b2d2..1685562cc7 100644
--- a/osu.Game/Skinning/SkinImporter.cs
+++ b/osu.Game/Skinning/SkinImporter.cs
@@ -37,7 +37,7 @@ namespace osu.Game.Skinning
protected override string[] HashableFileTypes => new[] { ".ini", ".json" };
- protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == @".osk";
+ protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path).ToLowerInvariant() == @".osk";
protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name ?? @"No name" };
diff --git a/osu.Game/Skinning/SkinInfo.cs b/osu.Game/Skinning/SkinInfo.cs
index d051149155..9ad91f8725 100644
--- a/osu.Game/Skinning/SkinInfo.cs
+++ b/osu.Game/Skinning/SkinInfo.cs
@@ -20,6 +20,7 @@ namespace osu.Game.Skinning
{
internal static readonly Guid TRIANGLES_SKIN = new Guid("2991CFD8-2140-469A-BCB9-2EC23FBCE4AD");
internal static readonly Guid ARGON_SKIN = new Guid("CFFA69DE-B3E3-4DEE-8563-3C4F425C05D0");
+ internal static readonly Guid ARGON_PRO_SKIN = new Guid("9FC9CF5D-0F16-4C71-8256-98868321AC43");
internal static readonly Guid CLASSIC_SKIN = new Guid("81F02CD3-EEC6-4865-AC23-FAE26A386187");
internal static readonly Guid RANDOM_SKIN = new Guid("D39DFEFB-477C-4372-B1EA-2BCEA5FB8908");
@@ -56,7 +57,7 @@ namespace osu.Game.Skinning
return new TrianglesSkin(this, resources);
}
- return (Skin)Activator.CreateInstance(type, this, resources);
+ return (Skin)Activator.CreateInstance(type, this, resources)!;
}
public IList Files { get; } = null!;
diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs
index 2ad62dbb61..f750bfad8a 100644
--- a/osu.Game/Skinning/SkinManager.cs
+++ b/osu.Game/Skinning/SkinManager.cs
@@ -84,6 +84,7 @@ namespace osu.Game.Skinning
DefaultClassicSkin = new DefaultLegacySkin(this),
trianglesSkin = new TrianglesSkin(this),
argonSkin = new ArgonSkin(this),
+ new ArgonProSkin(this),
};
// Ensure the default entries are present.
diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs
index 1a8a3a26c9..a66f3e0549 100644
--- a/osu.Game/Skinning/SkinnableSprite.cs
+++ b/osu.Game/Skinning/SkinnableSprite.cs
@@ -111,6 +111,7 @@ namespace osu.Game.Skinning
// Temporarily used to exclude undesirable ISkin implementations
static bool isUserSkin(ISkin skin)
=> skin.GetType() == typeof(TrianglesSkin)
+ || skin.GetType() == typeof(ArgonProSkin)
|| skin.GetType() == typeof(ArgonSkin)
|| skin.GetType() == typeof(DefaultLegacySkin)
|| skin.GetType() == typeof(LegacySkin);
diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs
index e86ee9e63d..e598c79b08 100644
--- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs
+++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs
@@ -137,7 +137,7 @@ namespace osu.Game.Storyboards.Drawables
// When reading from a skin, we match stables weird behaviour where `FrameCount` is ignored
// and resources are retrieved until the end of the animation.
- foreach (var texture in skin.GetTextures(Path.GetFileNameWithoutExtension(Animation.Path), default, default, true, string.Empty, out _))
+ foreach (var texture in skin.GetTextures(Path.GetFileNameWithoutExtension(Animation.Path)!, default, default, true, string.Empty, out _))
AddFrame(texture, Animation.FrameDelay);
}
diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs
index 8133244e89..566e064aad 100644
--- a/osu.Game/Storyboards/Storyboard.cs
+++ b/osu.Game/Storyboards/Storyboard.cs
@@ -32,7 +32,7 @@ namespace osu.Game.Storyboards
///
/// This iterates all elements and as such should be used sparingly or stored locally.
///
- public double? EarliestEventTime => Layers.SelectMany(l => l.Elements).OrderBy(e => e.StartTime).FirstOrDefault()?.StartTime;
+ public double? EarliestEventTime => Layers.SelectMany(l => l.Elements).MinBy(e => e.StartTime)?.StartTime;
///
/// Across all layers, find the latest point in time that a storyboard element ends at.
@@ -42,7 +42,7 @@ namespace osu.Game.Storyboards
/// This iterates all elements and as such should be used sparingly or stored locally.
/// Videos and samples return StartTime as their EndTIme.
///
- public double? LatestEventTime => Layers.SelectMany(l => l.Elements).OrderBy(e => e.GetEndTime()).LastOrDefault()?.GetEndTime();
+ public double? LatestEventTime => Layers.SelectMany(l => l.Elements).MaxBy(e => e.GetEndTime())?.GetEndTime();
///
/// Depth of the currently front-most storyboard layer, excluding the overlay layer.
diff --git a/osu.Game/Storyboards/StoryboardSprite.cs b/osu.Game/Storyboards/StoryboardSprite.cs
index cd7788bb08..5b7b194be7 100644
--- a/osu.Game/Storyboards/StoryboardSprite.cs
+++ b/osu.Game/Storyboards/StoryboardSprite.cs
@@ -48,7 +48,7 @@ namespace osu.Game.Storyboards
if (alphaCommands.Count > 0)
{
- var firstAlpha = alphaCommands.OrderBy(t => t.startTime).First();
+ var firstAlpha = alphaCommands.MinBy(t => t.startTime);
if (firstAlpha.isZeroStartValue)
return firstAlpha.startTime;
diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs
index c5f6f58b86..79f629ce49 100644
--- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs
+++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs
@@ -185,7 +185,7 @@ namespace osu.Game.Tests.Beatmaps
private Stream openResource(string name)
{
- string localPath = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path)).AsNonNull();
+ string localPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).AsNonNull();
return Assembly.LoadFrom(Path.Combine(localPath, $"{ResourceAssembly}.dll")).GetManifestResourceStream($@"{ResourceAssembly}.Resources.{name}");
}
diff --git a/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs b/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs
index c7441f68bd..16434406b5 100644
--- a/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs
+++ b/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs
@@ -3,7 +3,6 @@
#nullable disable
-using System;
using System.IO;
using System.Reflection;
using NUnit.Framework;
@@ -54,7 +53,7 @@ namespace osu.Game.Tests.Beatmaps
private Stream openResource(string name)
{
- string localPath = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path)).AsNonNull();
+ string localPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).AsNonNull();
return Assembly.LoadFrom(Path.Combine(localPath, $"{ResourceAssembly}.dll")).GetManifestResourceStream($@"{ResourceAssembly}.Resources.{name}");
}
diff --git a/osu.Game/Tests/PollingNotificationsClient.cs b/osu.Game/Tests/PollingNotificationsClient.cs
index 571a7a1ed1..450c763170 100644
--- a/osu.Game/Tests/PollingNotificationsClient.cs
+++ b/osu.Game/Tests/PollingNotificationsClient.cs
@@ -24,8 +24,8 @@ namespace osu.Game.Tests
{
while (!cancellationToken.IsCancellationRequested)
{
- await API.PerformAsync(CreateInitialFetchRequest());
- await Task.Delay(1000, cancellationToken);
+ await API.PerformAsync(CreateInitialFetchRequest()).ConfigureAwait(true);
+ await Task.Delay(1000, cancellationToken).ConfigureAwait(true);
}
}, cancellationToken);
diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs
index 765c665966..ad5e3f6c4d 100644
--- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs
+++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs
@@ -108,9 +108,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
// simulate the server's automatic assignment of users to teams on join.
// the "best" team is the one with the least users on it.
int bestTeam = teamVersus.Teams
- .Select(team => (teamID: team.ID, userCount: ServerRoom.Users.Count(u => (u.MatchState as TeamVersusUserState)?.TeamID == team.ID)))
- .OrderBy(pair => pair.userCount)
- .First().teamID;
+ .Select(team => (teamID: team.ID, userCount: ServerRoom.Users.Count(u => (u.MatchState as TeamVersusUserState)?.TeamID == team.ID))).MinBy(pair => pair.userCount).teamID;
user.MatchState = new TeamVersusUserState { TeamID = bestTeam };
((IMultiplayerClient)this).MatchUserStateChanged(clone(user.UserID), clone(user.MatchState)).WaitSafely();
diff --git a/osu.Game/Users/Drawables/DrawableFlag.cs b/osu.Game/Users/Drawables/DrawableFlag.cs
index 0d209f47e8..929a29251d 100644
--- a/osu.Game/Users/Drawables/DrawableFlag.cs
+++ b/osu.Game/Users/Drawables/DrawableFlag.cs
@@ -27,8 +27,7 @@ namespace osu.Game.Users.Drawables
[BackgroundDependencyLoader]
private void load(TextureStore ts)
{
- if (ts == null)
- throw new ArgumentNullException(nameof(ts));
+ ArgumentNullException.ThrowIfNull(ts);
string textureName = countryCode == CountryCode.Unknown ? "__" : countryCode.ToString();
Texture = ts.Get($@"Flags/{textureName}") ?? ts.Get(@"Flags/__");
diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs
index e7af127a30..2f7232d5ea 100644
--- a/osu.Game/Users/UserPanel.cs
+++ b/osu.Game/Users/UserPanel.cs
@@ -36,8 +36,7 @@ namespace osu.Game.Users
protected UserPanel(APIUser user)
: base(HoverSampleSet.Button)
{
- if (user == null)
- throw new ArgumentNullException(nameof(user));
+ ArgumentNullException.ThrowIfNull(user);
User = user;
}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 8639ce6361..83dbf7e370 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -1,6 +1,6 @@
- netstandard2.1
+ net6.0
Library
true
@@ -35,8 +35,8 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 184e3303c8..c6798cd5e4 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -1,92 +1,26 @@
- 8.0
- {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Resources
- PackageReference
- bin\$(Platform)\$(Configuration)
- cjk,mideast,other,rare,west
- false
- NSUrlSessionHandler
-
iPhone Developer
- true
-
-
-
- --nosymbolstrip=BASS_FX_BPM_BeatCallbackReset --nosymbolstrip=BASS_FX_BPM_BeatCallbackSet --nosymbolstrip=BASS_FX_BPM_BeatDecodeGet --nosymbolstrip=BASS_FX_BPM_BeatFree --nosymbolstrip=BASS_FX_BPM_BeatGetParameters --nosymbolstrip=BASS_FX_BPM_BeatSetParameters --nosymbolstrip=BASS_FX_BPM_CallbackReset --nosymbolstrip=BASS_FX_BPM_CallbackSet --nosymbolstrip=BASS_FX_BPM_DecodeGet --nosymbolstrip=BASS_FX_BPM_Free --nosymbolstrip=BASS_FX_BPM_Translate --nosymbolstrip=BASS_FX_GetVersion --nosymbolstrip=BASS_FX_ReverseCreate --nosymbolstrip=BASS_FX_ReverseGetSource --nosymbolstrip=BASS_FX_TempoCreate --nosymbolstrip=BASS_FX_TempoGetRateRatio --nosymbolstrip=BASS_FX_TempoGetSource --nosymbolstrip=BASS_Mixer_ChannelFlags --nosymbolstrip=BASS_Mixer_ChannelGetData --nosymbolstrip=BASS_Mixer_ChannelGetEnvelopePos --nosymbolstrip=BASS_Mixer_ChannelGetLevel --nosymbolstrip=BASS_Mixer_ChannelGetLevelEx --nosymbolstrip=BASS_Mixer_ChannelGetMatrix --nosymbolstrip=BASS_Mixer_ChannelGetMixer --nosymbolstrip=BASS_Mixer_ChannelGetPosition --nosymbolstrip=BASS_Mixer_ChannelGetPositionEx --nosymbolstrip=BASS_Mixer_ChannelIsActive --nosymbolstrip=BASS_Mixer_ChannelRemove --nosymbolstrip=BASS_Mixer_ChannelRemoveSync --nosymbolstrip=BASS_Mixer_ChannelSetEnvelope --nosymbolstrip=BASS_Mixer_ChannelSetEnvelopePos --nosymbolstrip=BASS_Mixer_ChannelSetMatrix --nosymbolstrip=BASS_Mixer_ChannelSetMatrixEx --nosymbolstrip=BASS_Mixer_ChannelSetPosition --nosymbolstrip=BASS_Mixer_ChannelSetSync --nosymbolstrip=BASS_Mixer_GetVersion --nosymbolstrip=BASS_Mixer_StreamAddChannel --nosymbolstrip=BASS_Mixer_StreamAddChannelEx --nosymbolstrip=BASS_Mixer_StreamCreate --nosymbolstrip=BASS_Mixer_StreamGetChannels --nosymbolstrip=BASS_Split_StreamCreate --nosymbolstrip=BASS_Split_StreamGetAvailable --nosymbolstrip=BASS_Split_StreamGetSource --nosymbolstrip=BASS_Split_StreamGetSplits --nosymbolstrip=BASS_Split_StreamReset --nosymbolstrip=BASS_Split_StreamResetEx
-
- --nolinkaway --nostrip $(GeneratedMtouchSymbolStripFlags)
-
-
- true
- full
- false
- DEBUG;ENABLE_TEST_CLOUD;
- true
- true
-
-
- pdbonly
- true
-
-
- x86_64
- None
+ true
+
+ true
+
+ $(NoWarn);MT7091
- true
- SdkOnly
- ARM64
- Entitlements.plist
+ ios-arm64
-
- true
- 25823
- false
-
-
- true
-
-
- true
- 28126
+
+ iossimulator-x64
-
-
-
-
-
-
-
-
-
-
-
-
-
- $(NoWarn);NU1605
-
-
-
-
- none
-
-
- none
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/osu.iOS/Application.cs b/osu.iOS/Application.cs
index c5b2d0b451..64eb5c63f5 100644
--- a/osu.iOS/Application.cs
+++ b/osu.iOS/Application.cs
@@ -3,7 +3,6 @@
#nullable disable
-using osu.Framework.iOS;
using UIKit;
namespace osu.iOS
@@ -12,7 +11,7 @@ namespace osu.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, typeof(GameUIApplication), typeof(AppDelegate));
+ UIApplication.Main(args, null, typeof(AppDelegate));
}
}
}
diff --git a/osu.iOS/Info.plist b/osu.iOS/Info.plist
index 16cb68fa7d..c4b08ab78e 100644
--- a/osu.iOS/Info.plist
+++ b/osu.iOS/Info.plist
@@ -15,7 +15,7 @@
LSRequiresIPhoneOS
MinimumOSVersion
- 10.0
+ 13.4
UIDeviceFamily
1
diff --git a/osu.iOS/Linker.xml b/osu.iOS/Linker.xml
deleted file mode 100644
index b55be3be39..0000000000
--- a/osu.iOS/Linker.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/osu.iOS/OsuGameIOS.cs b/osu.iOS/OsuGameIOS.cs
index b3194e497b..3e79bc6ad6 100644
--- a/osu.iOS/OsuGameIOS.cs
+++ b/osu.iOS/OsuGameIOS.cs
@@ -5,6 +5,7 @@
using System;
using Foundation;
+using Microsoft.Maui.Devices;
using osu.Framework.Graphics;
using osu.Framework.Input.Handlers;
using osu.Framework.iOS.Input;
@@ -12,7 +13,6 @@ using osu.Game;
using osu.Game.Overlays.Settings;
using osu.Game.Updater;
using osu.Game.Utils;
-using Xamarin.Essentials;
namespace osu.iOS
{
@@ -33,7 +33,7 @@ namespace osu.iOS
{
switch (handler)
{
- case IOSMouseHandler _:
+ case IOSMouseHandler:
return new IOSMouseSettings();
default:
diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj
index b9da874f30..def538af1a 100644
--- a/osu.iOS/osu.iOS.csproj
+++ b/osu.iOS/osu.iOS.csproj
@@ -1,124 +1,16 @@
-
-
-
- Debug
- iPhoneSimulator
+
+
+ net6.0-ios
+ 13.4
Exe
- {3F082D0B-A964-43D7-BDF7-C256D76A50D0}
- osu.iOS
- osu.iOS
- false
+ true
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}
- osu.Game
-
-
- {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}
- osu.Game.Rulesets.Catch
-
-
- {48F4582B-7687-4621-9CBE-5C24197CB536}
- osu.Game.Rulesets.Mania
-
-
- {C92A607B-1FDD-4954-9F92-03FF547D9080}
- osu.Game.Rulesets.Osu
-
-
- {F167E17A-7DE6-4AF5-B920-A5112296C695}
- osu.Game.Rulesets.Taiko
-
-
-
-
-
-
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
- false
-
-
-
-
-
-
diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings
index 154ad0fe8c..ef3b08e1f5 100644
--- a/osu.sln.DotSettings
+++ b/osu.sln.DotSettings
@@ -218,6 +218,7 @@
WARNING
WARNING
WARNING
+ WARNING
WARNING
HINT
WARNING