diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index b8dc201559..99906f0895 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,13 +3,13 @@
"isRoot": true,
"tools": {
"jetbrains.resharper.globaltools": {
- "version": "2022.2.3",
+ "version": "2023.3.3",
"commands": [
"jb"
]
},
"nvika": {
- "version": "2.2.0",
+ "version": "3.0.0",
"commands": [
"nvika"
]
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 103e4dbc30..de902df93f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -15,17 +15,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- # FIXME: Tools won't run in .NET 6.0 unless you install 3.1.x LTS side by side.
- # https://itnext.io/how-to-support-multiple-net-sdks-in-github-actions-workflows-b988daa884e
- - name: Install .NET 3.1.x LTS
+ - name: Install .NET 8.0.x
uses: actions/setup-dotnet@v3
with:
- dotnet-version: "3.1.x"
-
- - name: Install .NET 6.0.x
- uses: actions/setup-dotnet@v3
- with:
- dotnet-version: "6.0.x"
+ dotnet-version: "8.0.x"
- name: Restore Tools
run: dotnet tool restore
@@ -79,10 +72,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- - name: Install .NET 6.0.x
+ - name: Install .NET 8.0.x
uses: actions/setup-dotnet@v3
with:
- dotnet-version: "6.0.x"
+ dotnet-version: "8.0.x"
- name: Compile
run: dotnet build -c Debug -warnaserror osu.Desktop.slnf
@@ -114,10 +107,10 @@ jobs:
distribution: microsoft
java-version: 11
- - name: Install .NET 6.0.x
+ - name: Install .NET 8.0.x
uses: actions/setup-dotnet@v3
with:
- dotnet-version: "6.0.x"
+ dotnet-version: "8.0.x"
- name: Install .NET workloads
run: dotnet workload install maui-android
@@ -135,13 +128,16 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- - name: Install .NET 6.0.x
+ - name: Install .NET 8.0.x
uses: actions/setup-dotnet@v3
with:
- dotnet-version: "6.0.x"
+ dotnet-version: "8.0.x"
- name: Install .NET Workloads
run: dotnet workload install maui-ios
+ - name: Select Xcode 15.2
+ run: sudo xcode-select -s /Applications/Xcode_15.2.app/Contents/Developer
+
- name: Build
run: dotnet build -c Debug osu.iOS
diff --git a/.github/workflows/update-web-mod-definitions.yml b/.github/workflows/update-web-mod-definitions.yml
index 32d3d37ffe..5827a6cdbf 100644
--- a/.github/workflows/update-web-mod-definitions.yml
+++ b/.github/workflows/update-web-mod-definitions.yml
@@ -12,10 +12,10 @@ jobs:
name: Update osu-web mod definitions
runs-on: ubuntu-latest
steps:
- - name: Install .NET 6.0.x
+ - name: Install .NET 8.0.x
uses: actions/setup-dotnet@v3
with:
- dotnet-version: "6.0.x"
+ dotnet-version: "8.0.x"
- name: Checkout ppy/osu
uses: actions/checkout@v3
diff --git a/.globalconfig b/.globalconfig
index a7b652c454..a4d4707f9b 100644
--- a/.globalconfig
+++ b/.globalconfig
@@ -1,5 +1,3 @@
-is_global = true
-
# .NET Code Style
# IDE styles reference: https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/
@@ -56,4 +54,4 @@ dotnet_diagnostic.RS0030.severity = error
# Temporarily disable analysing CanBeNull = true in NRT contexts due to mobile issues.
# See: https://github.com/ppy/osu/pull/19677
-dotnet_diagnostic.OSUF001.severity = none
\ No newline at end of file
+dotnet_diagnostic.OSUF001.severity = none
diff --git a/Directory.Build.props b/Directory.Build.props
index b08283f071..2d289d0f22 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,7 +1,7 @@
- 10.0
+ 12.0
true
enable
diff --git a/README.md b/README.md
index d7e710f392..dc5809d46b 100644
--- a/README.md
+++ b/README.md
@@ -30,8 +30,8 @@ If you are just looking to give the game a whirl, you can grab the latest releas
### Latest release:
-| [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) |
-| ------------- | ------------- | ------------- | ------------- | ------------- |
+| [Windows 10+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | macOS 12+ ([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) |
+|--------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------------- | ------------- | ------------- |
You can also generally download a version for your current device from the [osu! site](https://osu.ppy.sh/home/download).
diff --git a/Templates/Rulesets/ruleset-empty/Directory.Build.props b/Templates/Rulesets/ruleset-empty/Directory.Build.props
new file mode 100644
index 0000000000..74d05ff690
--- /dev/null
+++ b/Templates/Rulesets/ruleset-empty/Directory.Build.props
@@ -0,0 +1,10 @@
+
+
+
+ $(MSBuildThisFileDirectory)app.manifest
+
+
+ true
+ $(NoWarn);CS1591
+
+
diff --git a/Templates/Rulesets/ruleset-empty/app.manifest b/Templates/Rulesets/ruleset-empty/app.manifest
new file mode 100644
index 0000000000..1c1e5f540c
--- /dev/null
+++ b/Templates/Rulesets/ruleset-empty/app.manifest
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
index 5babdb47ff..7d43eb2b05 100644
--- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
+++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
@@ -18,7 +18,7 @@
WinExe
- net6.0
+ net8.0
osu.Game.Rulesets.EmptyFreeform.Tests
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 d09e7647e0..89abd5665c 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 @@
- net6.0
+ net8.0
osu.Game.Rulesets.EmptyFreeform
Library
AnyCPU
diff --git a/Templates/Rulesets/ruleset-example/Directory.Build.props b/Templates/Rulesets/ruleset-example/Directory.Build.props
new file mode 100644
index 0000000000..74d05ff690
--- /dev/null
+++ b/Templates/Rulesets/ruleset-example/Directory.Build.props
@@ -0,0 +1,10 @@
+
+
+
+ $(MSBuildThisFileDirectory)app.manifest
+
+
+ true
+ $(NoWarn);CS1591
+
+
diff --git a/Templates/Rulesets/ruleset-example/app.manifest b/Templates/Rulesets/ruleset-example/app.manifest
new file mode 100644
index 0000000000..1c1e5f540c
--- /dev/null
+++ b/Templates/Rulesets/ruleset-example/app.manifest
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
index 5d64ca832a..7dc8a1336b 100644
--- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
+++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
@@ -18,7 +18,7 @@
WinExe
- net6.0
+ net8.0
osu.Game.Rulesets.Pippidon.Tests
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 9c8867f4ef..165b6b6c6b 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 @@
- net6.0
+ net8.0
osu.Game.Rulesets.Pippidon
Library
AnyCPU
diff --git a/Templates/Rulesets/ruleset-scrolling-empty/Directory.Build.props b/Templates/Rulesets/ruleset-scrolling-empty/Directory.Build.props
new file mode 100644
index 0000000000..74d05ff690
--- /dev/null
+++ b/Templates/Rulesets/ruleset-scrolling-empty/Directory.Build.props
@@ -0,0 +1,10 @@
+
+
+
+ $(MSBuildThisFileDirectory)app.manifest
+
+
+ true
+ $(NoWarn);CS1591
+
+
diff --git a/Templates/Rulesets/ruleset-scrolling-empty/app.manifest b/Templates/Rulesets/ruleset-scrolling-empty/app.manifest
new file mode 100644
index 0000000000..1c1e5f540c
--- /dev/null
+++ b/Templates/Rulesets/ruleset-scrolling-empty/app.manifest
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
index 6796a8962b..9c4c8217f0 100644
--- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
+++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
@@ -18,7 +18,7 @@
WinExe
- net6.0
+ net8.0
osu.Game.Rulesets.EmptyScrolling.Tests
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 5bf3884f53..6d9565a6f2 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 @@
- net6.0
+ net8.0
osu.Game.Rulesets.EmptyScrolling
Library
AnyCPU
diff --git a/Templates/Rulesets/ruleset-scrolling-example/Directory.Build.props b/Templates/Rulesets/ruleset-scrolling-example/Directory.Build.props
new file mode 100644
index 0000000000..74d05ff690
--- /dev/null
+++ b/Templates/Rulesets/ruleset-scrolling-example/Directory.Build.props
@@ -0,0 +1,10 @@
+
+
+
+ $(MSBuildThisFileDirectory)app.manifest
+
+
+ true
+ $(NoWarn);CS1591
+
+
diff --git a/Templates/Rulesets/ruleset-scrolling-example/app.manifest b/Templates/Rulesets/ruleset-scrolling-example/app.manifest
new file mode 100644
index 0000000000..1c1e5f540c
--- /dev/null
+++ b/Templates/Rulesets/ruleset-scrolling-example/app.manifest
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
index 5d64ca832a..7dc8a1336b 100644
--- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
+++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
@@ -18,7 +18,7 @@
WinExe
- net6.0
+ net8.0
osu.Game.Rulesets.Pippidon.Tests
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 9c8867f4ef..165b6b6c6b 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 @@
- net6.0
+ net8.0
osu.Game.Rulesets.Pippidon
Library
AnyCPU
diff --git a/global.json b/global.json
index 5dcd5f425a..789bff3bd0 100644
--- a/global.json
+++ b/global.json
@@ -1,7 +1,7 @@
{
"sdk": {
- "version": "6.0.100",
- "rollForward": "latestFeature"
+ "version": "8.0.100",
+ "rollForward": "latestFeature",
+ "allowPrerelease": false
}
-}
-
+}
\ No newline at end of file
diff --git a/osu.Android.props b/osu.Android.props
index 55ef55ab7d..d7f29beeb3 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -10,7 +10,7 @@
true
-
+
- false
0.0.0
1
$(Version)
@@ -19,4 +16,7 @@
+
+
+
diff --git a/osu.Desktop/NVAPI.cs b/osu.Desktop/NVAPI.cs
index bb3a59cc7f..78a814c585 100644
--- a/osu.Desktop/NVAPI.cs
+++ b/osu.Desktop/NVAPI.cs
@@ -138,7 +138,7 @@ namespace osu.Desktop
return false;
// Make sure that this is a laptop.
- var gpus = new IntPtr[64];
+ IntPtr[] gpus = new IntPtr[64];
if (checkError(EnumPhysicalGPUs(gpus, out int gpuCount)))
return false;
@@ -456,7 +456,7 @@ namespace osu.Desktop
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NVAPI.UNICODE_STRING_MAX)]
public string ProfileName;
- [MarshalAs(UnmanagedType.ByValArray)]
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public uint[] GPUSupport;
public uint IsPredefined;
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index d6a11fa924..cf2ec6e681 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net8.0
WinExe
true
A free-to-win rhythm game. Rhythm is just a *click* away!
diff --git a/osu.Game.Benchmarks/BenchmarkUnstableRate.cs b/osu.Game.Benchmarks/BenchmarkUnstableRate.cs
new file mode 100644
index 0000000000..aa229c7d06
--- /dev/null
+++ b/osu.Game.Benchmarks/BenchmarkUnstableRate.cs
@@ -0,0 +1,31 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using BenchmarkDotNet.Attributes;
+using osu.Framework.Utils;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Scoring;
+
+namespace osu.Game.Benchmarks
+{
+ public class BenchmarkUnstableRate : BenchmarkTest
+ {
+ private List events = null!;
+
+ public override void SetUp()
+ {
+ base.SetUp();
+ events = new List();
+
+ for (int i = 0; i < 1000; i++)
+ events.Add(new HitEvent(RNG.NextDouble(-200.0, 200.0), RNG.NextDouble(1.0, 2.0), HitResult.Great, new HitObject(), null, null));
+ }
+
+ [Benchmark]
+ public void CalculateUnstableRate()
+ {
+ _ = events.CalculateUnstableRate();
+ }
+ }
+}
diff --git a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj
index 47c93fbd02..64da5412a8 100644
--- a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj
+++ b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
Exe
false
diff --git a/osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml b/osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml
index 52b34959b9..b6ab91ed5c 100644
--- a/osu.Game.Rulesets.Catch.Tests.Android/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 4ee3219442..4b2e54be67 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,7 +1,7 @@
- net6.0-android
+ net8.0-android
Exe
osu.Game.Rulesets.Catch.Tests
osu.Game.Rulesets.Catch.Tests.Android
@@ -21,4 +21,4 @@
-
\ No newline at end of file
+
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 acf12bb0ac..9c262a752a 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,7 +1,7 @@
Exe
- net6.0-ios
+ net8.0-ios
13.4
osu.Game.Rulesets.Catch.Tests
osu.Game.Rulesets.Catch.Tests.iOS
diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
index 0a77845343..619081c754 100644
--- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
+++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
@@ -7,7 +7,7 @@
WinExe
- net6.0
+ net8.0
diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj
index ecce7c1b3f..a5138ffb39 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 @@
- net6.0
+ net8.0
Library
true
catch the fruit. to the beat.
diff --git a/osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml b/osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml
index f5a49210ea..df4930419c 100644
--- a/osu.Game.Rulesets.Mania.Tests.Android/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 25335754d2..2866508a02 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,7 +1,7 @@
- net6.0-android
+ net8.0-android
Exe
osu.Game.Rulesets.Mania.Tests
osu.Game.Rulesets.Mania.Tests.Android
@@ -21,4 +21,4 @@
-
\ No newline at end of file
+
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 51e07dd6c1..d51e541e95 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,7 +1,7 @@
Exe
- net6.0-ios
+ net8.0-ios
13.4
osu.Game.Rulesets.Mania.Tests
osu.Game.Rulesets.Mania.Tests.iOS
diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
index 877b9c3ea4..eee06acdb8 100644
--- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
+++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
@@ -7,7 +7,7 @@
WinExe
- net6.0
+ net8.0
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs b/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs
index 050b302bd8..88d6a19822 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaKeyMod.cs
@@ -15,6 +15,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public abstract int KeyCount { get; }
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier
+ public override bool Ranked => UsesDefaultConfiguration;
public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter)
{
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHardRock.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHardRock.cs
index d9de06a811..189c4b3a5f 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModHardRock.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHardRock.cs
@@ -8,5 +8,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModHardRock : ModHardRock
{
public override double ScoreMultiplier => 1;
+ public override bool Ranked => false;
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs
index 31f52610e9..7dd0c499da 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs
@@ -11,5 +11,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Name => "One Key";
public override string Acronym => "1K";
public override LocalisableString Description => @"Play with one key.";
+ public override bool Ranked => false;
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey10.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey10.cs
index 67e65b887a..a6c57d4597 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey10.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey10.cs
@@ -11,5 +11,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Name => "Ten Keys";
public override string Acronym => "10K";
public override LocalisableString Description => @"Play with ten keys.";
+ public override bool Ranked => false;
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs
index 0f8148d252..0d04395a52 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs
@@ -11,5 +11,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Name => "Two Keys";
public override string Acronym => "2K";
public override LocalisableString Description => @"Play with two keys.";
+ public override bool Ranked => false;
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs
index 0f8af7940c..c83b0979ee 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs
@@ -11,5 +11,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Name => "Three Keys";
public override string Acronym => "3K";
public override LocalisableString Description => @"Play with three keys.";
+ public override bool Ranked => false;
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
index f9690b4298..cc7e270dda 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
@@ -14,6 +14,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModMirror : ModMirror, IApplicableToBeatmap
{
public override LocalisableString Description => "Notes are flipped horizontally.";
+ public override bool Ranked => UsesDefaultConfiguration;
public void ApplyToBeatmap(IBeatmap beatmap)
{
diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs
index bea536e4af..decf670c5d 100644
--- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs
+++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs
@@ -1,16 +1,16 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Input;
+using osu.Framework.Threading;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Input.Handlers;
@@ -59,10 +59,9 @@ namespace osu.Game.Rulesets.Mania.UI
// Stores the current speed adjustment active in gameplay.
private readonly Track speedAdjustmentTrack = new TrackVirtual(0);
- [Resolved]
- private ISkinSource skin { get; set; }
+ private ISkinSource currentSkin = null!;
- public DrawableManiaRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null)
+ public DrawableManiaRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList? mods = null)
: base(ruleset, beatmap, mods)
{
BarLines = new BarLineGenerator(Beatmap).BarLines;
@@ -72,8 +71,12 @@ namespace osu.Game.Rulesets.Mania.UI
}
[BackgroundDependencyLoader]
- private void load()
+ private void load(ISkinSource source)
{
+ currentSkin = source;
+ currentSkin.SourceChanged += onSkinChange;
+ skinChanged();
+
foreach (var mod in Mods.OfType())
mod.ApplyToTrack(speedAdjustmentTrack);
@@ -109,12 +112,28 @@ namespace osu.Game.Rulesets.Mania.UI
updateTimeRange();
}
+ private ScheduledDelegate? pendingSkinChange;
+ private float hitPosition;
+
+ private void onSkinChange()
+ {
+ // schedule required to avoid calls after disposed.
+ // note that this has the side-effect of components only performing a skin change when they are alive.
+ pendingSkinChange?.Cancel();
+ pendingSkinChange = Scheduler.Add(skinChanged);
+ }
+
+ private void skinChanged()
+ {
+ hitPosition = currentSkin.GetConfig(
+ new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.HitPosition))?.Value
+ ?? Stage.HIT_TARGET_POSITION;
+
+ pendingSkinChange = null;
+ }
+
private void updateTimeRange()
{
- float hitPosition = skin.GetConfig(
- new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.HitPosition))?.Value
- ?? Stage.HIT_TARGET_POSITION;
-
const float length_to_default_hit_position = 768 - LegacyManiaSkinConfiguration.DEFAULT_HIT_POSITION;
float lengthToHitPosition = 768 - hitPosition;
@@ -139,10 +158,18 @@ namespace osu.Game.Rulesets.Mania.UI
protected override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant);
- public override DrawableHitObject CreateDrawableRepresentation(ManiaHitObject h) => null;
+ public override DrawableHitObject? CreateDrawableRepresentation(ManiaHitObject h) => null;
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
protected override ReplayRecorder CreateReplayRecorder(Score score) => new ManiaReplayRecorder(score);
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+
+ if (currentSkin.IsNotNull())
+ currentSkin.SourceChanged -= onSkinChange;
+ }
}
}
diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj
index 72f172188e..3bca938450 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 @@
- net6.0
+ net8.0
Library
true
smash the keys. to the beat.
diff --git a/osu.Game.Rulesets.Osu.Tests.Android/AndroidManifest.xml b/osu.Game.Rulesets.Osu.Tests.Android/AndroidManifest.xml
index ed4725dd94..d0c3484cfd 100644
--- a/osu.Game.Rulesets.Osu.Tests.Android/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 e8a46a9828..b79de6d40b 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,7 +1,7 @@
- net6.0-android
+ net8.0-android
Exe
osu.Game.Rulesets.Osu.Tests
osu.Game.Rulesets.Osu.Tests.Android
@@ -24,4 +24,4 @@
-
\ No newline at end of file
+
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 7d50deb8ba..cc0233d7fd 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,7 +1,7 @@
Exe
- net6.0-ios
+ net8.0-ios
13.4
Exe
osu.Game.Rulesets.Osu.Tests
diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs
index 8234381283..2b53554ed1 100644
--- a/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs
@@ -206,7 +206,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
{
AddStep($"click context menu item \"{contextMenuText}\"", () =>
{
- MenuItem item = visualiser.ContextMenuItems.FirstOrDefault(menuItem => menuItem.Text.Value == "Curve type")?.Items.FirstOrDefault(menuItem => menuItem.Text.Value == contextMenuText);
+ MenuItem item = visualiser.ContextMenuItems!.FirstOrDefault(menuItem => menuItem.Text.Value == "Curve type")?.Items.FirstOrDefault(menuItem => menuItem.Text.Value == contextMenuText);
item?.Action.Value?.Invoke();
});
diff --git a/osu.Game.Rulesets.Osu.Tests/OsuHitObjectGenerationUtilsTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuHitObjectGenerationUtilsTest.cs
index d78c32aa6a..77ef4627cb 100644
--- a/osu.Game.Rulesets.Osu.Tests/OsuHitObjectGenerationUtilsTest.cs
+++ b/osu.Game.Rulesets.Osu.Tests/OsuHitObjectGenerationUtilsTest.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Tests
new PathControlPoint(new Vector2(-128, 0), PathType.LINEAR) // absolute position: (0, 128)
}
},
- RepeatCount = 1
+ RepeatCount = 2
};
slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
return slider;
@@ -45,7 +45,9 @@ namespace osu.Game.Rulesets.Osu.Tests
OsuHitObjectGenerationUtils.ReflectHorizontallyAlongPlayfield(slider);
Assert.That(slider.Position, Is.EqualTo(new Vector2(OsuPlayfield.BASE_SIZE.X - 128, 128)));
- Assert.That(slider.NestedHitObjects.OfType().Single().Position, Is.EqualTo(new Vector2(OsuPlayfield.BASE_SIZE.X - 0, 128)));
+ Assert.That(slider.NestedHitObjects.OfType().Single().Position, Is.EqualTo(new Vector2(OsuPlayfield.BASE_SIZE.X - 128, 128)));
+ Assert.That(slider.NestedHitObjects.OfType().First().Position, Is.EqualTo(new Vector2(OsuPlayfield.BASE_SIZE.X - 0, 128)));
+ Assert.That(slider.NestedHitObjects.OfType().Single().Position, Is.EqualTo(new Vector2(OsuPlayfield.BASE_SIZE.X, 128)));
Assert.That(slider.Path.ControlPoints.Select(point => point.Position), Is.EquivalentTo(new[]
{
new Vector2(),
@@ -62,7 +64,9 @@ namespace osu.Game.Rulesets.Osu.Tests
OsuHitObjectGenerationUtils.ReflectVerticallyAlongPlayfield(slider);
Assert.That(slider.Position, Is.EqualTo(new Vector2(128, OsuPlayfield.BASE_SIZE.Y - 128)));
- Assert.That(slider.NestedHitObjects.OfType().Single().Position, Is.EqualTo(new Vector2(0, OsuPlayfield.BASE_SIZE.Y - 128)));
+ Assert.That(slider.NestedHitObjects.OfType().Single().Position, Is.EqualTo(new Vector2(128, OsuPlayfield.BASE_SIZE.Y - 128)));
+ Assert.That(slider.NestedHitObjects.OfType().First().Position, Is.EqualTo(new Vector2(0, OsuPlayfield.BASE_SIZE.Y - 128)));
+ Assert.That(slider.NestedHitObjects.OfType().Single().Position, Is.EqualTo(new Vector2(0, OsuPlayfield.BASE_SIZE.Y - 128)));
Assert.That(slider.Path.ControlPoints.Select(point => point.Position), Is.EquivalentTo(new[]
{
new Vector2(),
@@ -79,7 +83,9 @@ namespace osu.Game.Rulesets.Osu.Tests
OsuHitObjectGenerationUtils.FlipSliderInPlaceHorizontally(slider);
Assert.That(slider.Position, Is.EqualTo(new Vector2(128, 128)));
- Assert.That(slider.NestedHitObjects.OfType().Single().Position, Is.EqualTo(new Vector2(256, 128)));
+ Assert.That(slider.NestedHitObjects.OfType().Single().Position, Is.EqualTo(new Vector2(128, 128)));
+ Assert.That(slider.NestedHitObjects.OfType().First().Position, Is.EqualTo(new Vector2(256, 128)));
+ Assert.That(slider.NestedHitObjects.OfType().Single().Position, Is.EqualTo(new Vector2(256, 128)));
Assert.That(slider.Path.ControlPoints.Select(point => point.Position), Is.EquivalentTo(new[]
{
new Vector2(),
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs
index eefaa3cae3..28c9d71139 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs
@@ -183,7 +183,7 @@ namespace osu.Game.Rulesets.Osu.Tests
break;
}
- hitObjectContainer.Add(drawableObject);
+ hitObjectContainer.Add(drawableObject!);
followPointRenderer.AddFollowPoints(objects[i]);
}
});
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs
index 09b906cb10..c624fbbe73 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs
@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using JetBrains.Annotations;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
@@ -173,6 +174,7 @@ namespace osu.Game.Rulesets.Osu.Tests
public IEnumerable AllSources => new[] { this };
+ [CanBeNull]
public event Action SourceChanged;
private bool enabled = true;
diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
index 9c248abd66..ea54c8d313 100644
--- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
+++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
@@ -8,7 +8,7 @@
WinExe
- net6.0
+ net8.0
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs
index f691731afe..df9544b71e 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs
@@ -22,6 +22,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override LocalisableString Description => @"Spinners will be automatically completed.";
public override double ScoreMultiplier => 0.9;
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot), typeof(OsuModTargetPractice) };
+ public override bool Ranked => UsesDefaultConfiguration;
public void ApplyToDrawableHitObject(DrawableHitObject hitObject)
{
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
index f1468d414e..917685cdad 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs
@@ -10,5 +10,6 @@ namespace osu.Game.Rulesets.Osu.Mods
public class OsuModTouchDevice : ModTouchDevice
{
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
+ public override bool Ranked => UsesDefaultConfiguration;
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs
index 032f105ded..506145568e 100644
--- a/osu.Game.Rulesets.Osu/Objects/Slider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs
@@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Osu.Objects
set
{
repeatCount = value;
- endPositionCache.Invalidate();
+ updateNestedPositions();
}
}
@@ -165,7 +165,7 @@ namespace osu.Game.Rulesets.Osu.Objects
public Slider()
{
SamplesBindable.CollectionChanged += (_, _) => UpdateNestedSamples();
- Path.Version.ValueChanged += _ => endPositionCache.Invalidate();
+ Path.Version.ValueChanged += _ => updateNestedPositions();
}
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs
index ceee513412..ee2490439f 100644
--- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs
+++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs
@@ -30,7 +30,6 @@ namespace osu.Game.Rulesets.Osu.Objects
public class TailJudgement : SliderEndJudgement
{
public override HitResult MaxResult => HitResult.SliderTailHit;
- public override HitResult MinResult => HitResult.IgnoreMiss;
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPieceSliderTickMiss.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPieceSliderTickMiss.cs
index 878e8dbfc2..bd883d6e4c 100644
--- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPieceSliderTickMiss.cs
+++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPieceSliderTickMiss.cs
@@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
this.ScaleTo(1.4f);
this.ScaleTo(1f, 150, Easing.Out);
- this.FadeOutFromOne(400);
+ this.FadeOutFromOne(600);
}
public Drawable? GetAboveHitObjectsProxiedContent() => piece.CreateProxy();
diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultJudgementPieceSliderTickMiss.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultJudgementPieceSliderTickMiss.cs
index 9fc71852ba..04c15a1433 100644
--- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultJudgementPieceSliderTickMiss.cs
+++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultJudgementPieceSliderTickMiss.cs
@@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
this.ScaleTo(1.4f);
this.ScaleTo(1f, 150, Easing.Out);
- this.FadeOutFromOne(400);
+ this.FadeOutFromOne(600);
}
public Drawable? GetAboveHitObjectsProxiedContent() => piece.CreateProxy();
diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj
index 75656e2976..518ab362ca 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 @@
- net6.0
+ net8.0
Library
true
click the circles. to the beat.
diff --git a/osu.Game.Rulesets.Taiko.Tests.Android/AndroidManifest.xml b/osu.Game.Rulesets.Taiko.Tests.Android/AndroidManifest.xml
index cc88d3080a..0ae9ee43ad 100644
--- a/osu.Game.Rulesets.Taiko.Tests.Android/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 a639326ebd..ee973e8544 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,7 +1,7 @@
- net6.0-android
+ net8.0-android
Exe
osu.Game.Rulesets.Taiko.Tests
osu.Game.Rulesets.Taiko.Tests.Android
@@ -21,4 +21,4 @@
-
\ No newline at end of file
+
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 e648a11299..ee2d4d703e 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,7 +1,7 @@
Exe
- net6.0-ios
+ net8.0-ios
13.4
osu.Game.Rulesets.Taiko.Tests
osu.Game.Rulesets.Taiko.Tests.iOS
diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
index 4eb6b0ab3d..26afd42445 100644
--- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
+++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
@@ -7,7 +7,7 @@
WinExe
- net6.0
+ net8.0
diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs
index 29ccd96675..0b7f6f621a 100644
--- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs
+++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs
@@ -179,10 +179,9 @@ namespace osu.Game.Rulesets.Taiko.UI
TaikoAction taikoAction = getTaikoActionFromPosition(position);
// Not too sure how this can happen, but let's avoid throwing.
- if (trackedActions.ContainsKey(source))
+ if (!trackedActions.TryAdd(source, taikoAction))
return;
- trackedActions.Add(source, taikoAction);
keyBindingContainer.TriggerPressed(taikoAction);
}
diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj
index f0e1cb8e8f..cacba55c2a 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 @@
- net6.0
+ net8.0
Library
true
bash the drum. to the beat.
diff --git a/osu.Game.Tests.Android/AndroidManifest.xml b/osu.Game.Tests.Android/AndroidManifest.xml
index 6f91fb928c..71793af977 100644
--- a/osu.Game.Tests.Android/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/osu.Game.Tests.Android.csproj b/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj
index b745d91980..889f0a3583 100644
--- a/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj
+++ b/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj
@@ -1,7 +1,7 @@
- net6.0-android
+ net8.0-android
Exe
osu.Game.Tests
osu.Game.Tests.Android
diff --git a/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj b/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj
index 79771fcd50..e4b9d2ba94 100644
--- a/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj
+++ b/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj
@@ -1,7 +1,7 @@
Exe
- net6.0-ios
+ net8.0-ios
13.4
osu.Game.Tests
osu.Game.Tests.iOS
diff --git a/osu.Game.Tests/Beatmaps/WorkingBeatmapTest.cs b/osu.Game.Tests/Beatmaps/WorkingBeatmapTest.cs
index f4b1028c0e..3c26f8e39a 100644
--- a/osu.Game.Tests/Beatmaps/WorkingBeatmapTest.cs
+++ b/osu.Game.Tests/Beatmaps/WorkingBeatmapTest.cs
@@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using JetBrains.Annotations;
using Moq;
using NUnit.Framework;
using osu.Game.Beatmaps;
@@ -98,9 +99,10 @@ namespace osu.Game.Tests.Beatmaps
Beatmap = beatmap;
}
+#pragma warning disable CS0067
+ [CanBeNull]
public event Action> ObjectConverted;
-
- protected virtual void OnObjectConverted(HitObject arg1, IEnumerable arg2) => ObjectConverted?.Invoke(arg1, arg2);
+#pragma warning restore CS0067
public IBeatmap Beatmap { get; }
diff --git a/osu.Game.Tests/Database/RulesetStoreTests.cs b/osu.Game.Tests/Database/RulesetStoreTests.cs
index 8b4c6e2411..ddf207342a 100644
--- a/osu.Game.Tests/Database/RulesetStoreTests.cs
+++ b/osu.Game.Tests/Database/RulesetStoreTests.cs
@@ -79,7 +79,7 @@ namespace osu.Game.Tests.Database
Assert.That(realm.Run(r => r.Find(rulesetShortName)!.Available), Is.True);
// Availability is updated on construction of a RealmRulesetStore
- var _ = new RealmRulesetStore(realm, storage);
+ _ = new RealmRulesetStore(realm, storage);
Assert.That(realm.Run(r => r.Find(rulesetShortName)!.Available), Is.False);
});
@@ -104,13 +104,13 @@ namespace osu.Game.Tests.Database
Assert.That(realm.Run(r => r.Find(rulesetShortName)!.Available), Is.True);
// Availability is updated on construction of a RealmRulesetStore
- var _ = new RealmRulesetStore(realm, storage);
+ _ = new RealmRulesetStore(realm, storage);
Assert.That(realm.Run(r => r.Find(rulesetShortName)!.Available), Is.False);
// Simulate the ruleset getting updated
LoadTestRuleset.Version = Ruleset.CURRENT_RULESET_API_VERSION;
- var __ = new RealmRulesetStore(realm, storage);
+ _ = new RealmRulesetStore(realm, storage);
Assert.That(realm.Run(r => r.Find(rulesetShortName)!.Available), Is.True);
});
diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
index 4fb9db845b..61161f3206 100644
--- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
+++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
@@ -203,9 +203,9 @@ namespace osu.Game.Tests.Gameplay
public IRenderer Renderer => host.Renderer;
public AudioManager AudioManager => Audio;
- public IResourceStore Files => null;
+ public IResourceStore Files => null!;
public new IResourceStore Resources => base.Resources;
- public RealmAccess RealmAccess => null;
+ public RealmAccess RealmAccess => null!;
public IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => null;
#endregion
diff --git a/osu.Game.Tests/NonVisual/TaskChainTest.cs b/osu.Game.Tests/NonVisual/TaskChainTest.cs
index ad1a3fd63f..2ac89efb69 100644
--- a/osu.Game.Tests/NonVisual/TaskChainTest.cs
+++ b/osu.Game.Tests/NonVisual/TaskChainTest.cs
@@ -58,7 +58,7 @@ namespace osu.Game.Tests.NonVisual
var task3 = addTask();
// Cancel task2, allow task3 to complete.
- task2.cancellation.Cancel();
+ await task2.cancellation.CancelAsync();
task2.mutex.Set();
task3.mutex.Set();
diff --git a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs
index 73465fae08..a3f91fffba 100644
--- a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs
+++ b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
@@ -31,8 +29,8 @@ namespace osu.Game.Tests.Rulesets.Scoring
{
public partial class ScoreProcessorTest
{
- private ScoreProcessor scoreProcessor;
- private IBeatmap beatmap;
+ private ScoreProcessor scoreProcessor = null!;
+ private IBeatmap beatmap = null!;
[SetUp]
public void SetUp()
@@ -86,7 +84,7 @@ namespace osu.Game.Tests.Rulesets.Scoring
[TestCase(ScoringMode.Standardised, HitResult.SmallTickHit, HitResult.SmallTickHit, 493_652)]
[TestCase(ScoringMode.Standardised, HitResult.LargeTickMiss, HitResult.LargeTickHit, 0)]
[TestCase(ScoringMode.Standardised, HitResult.LargeTickHit, HitResult.LargeTickHit, 326_963)]
- [TestCase(ScoringMode.Standardised, HitResult.SliderTailHit, HitResult.SliderTailHit, 326_963)]
+ [TestCase(ScoringMode.Standardised, HitResult.SliderTailHit, HitResult.SliderTailHit, 371_627)]
[TestCase(ScoringMode.Standardised, HitResult.SmallBonus, HitResult.SmallBonus, 1_000_030)]
[TestCase(ScoringMode.Standardised, HitResult.LargeBonus, HitResult.LargeBonus, 1_000_150)]
[TestCase(ScoringMode.Classic, HitResult.Miss, HitResult.Great, 0)]
@@ -99,7 +97,7 @@ namespace osu.Game.Tests.Rulesets.Scoring
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, HitResult.SmallTickHit, 49_365)]
[TestCase(ScoringMode.Classic, HitResult.LargeTickMiss, HitResult.LargeTickHit, 0)]
[TestCase(ScoringMode.Classic, HitResult.LargeTickHit, HitResult.LargeTickHit, 32_696)]
- [TestCase(ScoringMode.Classic, HitResult.SliderTailHit, HitResult.SliderTailHit, 32_696)]
+ [TestCase(ScoringMode.Classic, HitResult.SliderTailHit, HitResult.SliderTailHit, 37_163)]
[TestCase(ScoringMode.Classic, HitResult.SmallBonus, HitResult.SmallBonus, 100_003)]
[TestCase(ScoringMode.Classic, HitResult.LargeBonus, HitResult.LargeBonus, 100_015)]
public void TestFourVariousResultsOneMiss(ScoringMode scoringMode, HitResult hitResult, HitResult maxResult, int expectedScore)
@@ -171,7 +169,7 @@ namespace osu.Game.Tests.Rulesets.Scoring
[TestCase(HitResult.Perfect, HitResult.Miss)]
[TestCase(HitResult.SmallTickHit, HitResult.SmallTickMiss)]
[TestCase(HitResult.LargeTickHit, HitResult.LargeTickMiss)]
- [TestCase(HitResult.SliderTailHit, HitResult.LargeTickMiss)]
+ [TestCase(HitResult.SliderTailHit, HitResult.IgnoreMiss)]
[TestCase(HitResult.SmallBonus, HitResult.IgnoreMiss)]
[TestCase(HitResult.LargeBonus, HitResult.IgnoreMiss)]
public void TestMinResults(HitResult hitResult, HitResult expectedMinResult)
@@ -476,7 +474,7 @@ namespace osu.Game.Tests.Rulesets.Scoring
public override IEnumerable GetModsFor(ModType type) => throw new NotImplementedException();
- public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => throw new NotImplementedException();
+ public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList? mods = null) => throw new NotImplementedException();
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
diff --git a/osu.Game.Tests/Rulesets/TestSceneBrokenRulesetHandling.cs b/osu.Game.Tests/Rulesets/TestSceneBrokenRulesetHandling.cs
index dac6beea65..b378704e80 100644
--- a/osu.Game.Tests/Rulesets/TestSceneBrokenRulesetHandling.cs
+++ b/osu.Game.Tests/Rulesets/TestSceneBrokenRulesetHandling.cs
@@ -56,9 +56,9 @@ namespace osu.Game.Tests.Rulesets
public override IEnumerable GetModsFor(ModType type) => new Mod[] { null };
- public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => null;
- public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => null;
- public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => null;
+ public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => null!;
+ public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => null!;
+ public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => null!;
}
private class TestAPIIncompatibleRuleset : Ruleset
@@ -69,9 +69,9 @@ namespace osu.Game.Tests.Rulesets
// simulate API incompatibility by throwing similar exceptions.
public override IEnumerable GetModsFor(ModType type) => throw new MissingMethodException();
- public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => null;
- public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => null;
- public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => null;
+ public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => null!;
+ public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => null!;
+ public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => null!;
}
}
}
diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
index bbd7123f20..ca5e89c8ed 100644
--- a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
+++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs
@@ -142,7 +142,7 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("dismiss prompt", () =>
{
- var button = DialogOverlay.CurrentDialog.Buttons.Last();
+ var button = DialogOverlay.CurrentDialog!.Buttons.Last();
InputManager.MoveMouseTo(button);
InputManager.Click(MouseButton.Left);
});
@@ -167,7 +167,7 @@ namespace osu.Game.Tests.Visual.Editing
});
AddUntilStep("save prompt shown", () => DialogOverlay.CurrentDialog is SaveRequiredPopupDialog);
- AddStep("save changes", () => DialogOverlay.CurrentDialog.PerformOkAction());
+ AddStep("save changes", () => DialogOverlay.CurrentDialog!.PerformOkAction());
EditorPlayer editorPlayer = null;
AddUntilStep("player pushed", () => (editorPlayer = Stack.CurrentScreen as EditorPlayer) != null);
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
index c51883b221..a7ab021884 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
@@ -120,7 +120,7 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override void Update()
{
base.Update();
- playbackManager?.ReplayInputHandler.SetFrameFromTime(Time.Current - 100);
+ playbackManager?.ReplayInputHandler?.SetFrameFromTime(Time.Current - 100);
}
[TearDownSteps]
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs
index 3a5b3864af..dd5bbf70b4 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs
@@ -198,7 +198,7 @@ namespace osu.Game.Tests.Visual.Gameplay
foreach (var legacyFrame in frames.Frames)
{
var frame = new TestReplayFrame();
- frame.FromLegacy(legacyFrame, null);
+ frame.FromLegacy(legacyFrame, null!);
playbackReplay.Frames.Add(frame);
}
diff --git a/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs b/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs
index ce9f80a84f..12d7dde11b 100644
--- a/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs
+++ b/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs
@@ -250,7 +250,7 @@ namespace osu.Game.Tests.Visual.Menus
{
}
- public virtual IBindable UnreadCount => null;
+ public virtual IBindable UnreadCount { get; } = new Bindable();
public IEnumerable AllNotifications => Enumerable.Empty();
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs
index d99d764449..b938e59d63 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs
@@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
.SkipWhile(r => r.Room.Category.Value == RoomCategory.Spotlight)
.All(r => r.Room.Category.Value == RoomCategory.Normal));
- AddStep("remove first room", () => RoomManager.RemoveRoom(RoomManager.Rooms.FirstOrDefault(r => r.RoomID.Value == 0)));
+ AddStep("remove first room", () => RoomManager.RemoveRoom(RoomManager.Rooms.First(r => r.RoomID.Value == 0)));
AddAssert("has 4 rooms", () => container.Rooms.Count == 4);
AddAssert("first room removed", () => container.Rooms.All(r => r.Room.RoomID.Value != 0));
diff --git a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs
index 79fb063ea9..b9d7312233 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs
@@ -10,6 +10,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
+using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
@@ -67,5 +68,34 @@ namespace osu.Game.Tests.Visual.Online
});
AddUntilStep("overlay is hidden", () => accountCreation.State.Value == Visibility.Hidden);
}
+
+ [Test]
+ public void TestFullFlow()
+ {
+ AddStep("log out", () => API.Logout());
+
+ AddStep("show manually", () => accountCreation.Show());
+ AddUntilStep("overlay is visible", () => accountCreation.State.Value == Visibility.Visible);
+
+ AddStep("click button", () => accountCreation.ChildrenOfType().Single().TriggerClick());
+ AddUntilStep("warning screen is present", () => accountCreation.ChildrenOfType().SingleOrDefault()?.IsPresent == true);
+
+ AddStep("proceed", () => accountCreation.ChildrenOfType().Single().TriggerClick());
+ AddUntilStep("entry screen is present", () => accountCreation.ChildrenOfType().SingleOrDefault()?.IsPresent == true);
+
+ AddStep("input details", () =>
+ {
+ var entryScreen = accountCreation.ChildrenOfType().Single();
+ entryScreen.ChildrenOfType().ElementAt(0).Text = "new_user";
+ entryScreen.ChildrenOfType().ElementAt(1).Text = "new.user@fake.mail";
+ entryScreen.ChildrenOfType().ElementAt(2).Text = "password";
+ });
+ AddStep("click button", () => accountCreation.ChildrenOfType().Single()
+ .ChildrenOfType().Single().TriggerClick());
+ AddUntilStep("verification screen is present", () => accountCreation.ChildrenOfType().SingleOrDefault()?.IsPresent == true);
+
+ AddStep("verify", () => ((DummyAPIAccess)API).AuthenticateSecondFactor("abcdefgh"));
+ AddUntilStep("overlay is hidden", () => accountCreation.State.Value == Visibility.Hidden);
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneDashboardOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneDashboardOverlay.cs
index 9407941da6..b6a300322f 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneDashboardOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneDashboardOverlay.cs
@@ -2,14 +2,15 @@
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Game.Online.API;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
namespace osu.Game.Tests.Visual.Online
{
public partial class TestSceneDashboardOverlay : OsuTestScene
{
- protected override bool UseOnlineAPI => true;
-
private readonly DashboardOverlay overlay;
public TestSceneDashboardOverlay()
@@ -17,6 +18,30 @@ namespace osu.Game.Tests.Visual.Online
Add(overlay = new DashboardOverlay());
}
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ int supportLevel = 0;
+
+ for (int i = 0; i < 1000; i++)
+ {
+ supportLevel++;
+
+ if (supportLevel > 3)
+ supportLevel = 0;
+
+ ((DummyAPIAccess)API).Friends.Add(new APIUser
+ {
+ Username = @"peppy",
+ Id = 2,
+ Colour = "99EB47",
+ CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
+ IsSupporter = supportLevel > 0,
+ SupportLevel = supportLevel
+ });
+ }
+ }
+
[Test]
public void TestShow()
{
diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs
index 1053789b27..9f7b20ad43 100644
--- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs
+++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs
@@ -179,7 +179,7 @@ namespace osu.Game.Tests.Visual.Playlists
public IBindable InitialRoomsReceived { get; } = new Bindable(true);
- public IBindableList Rooms => null;
+ public IBindableList Rooms => null!;
public void AddOrUpdateRoom(Room room) => throw new NotImplementedException();
diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
index 2f66309f04..1636a3d4b8 100644
--- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
+++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
@@ -52,11 +52,11 @@ namespace osu.Game.Tests.Visual.Playlists
[SetUpSteps]
public void SetupSteps()
{
- AddStep("set room", () => SelectedRoom.Value = new Room());
+ AddStep("set room", () => SelectedRoom!.Value = new Room());
importBeatmap();
- AddStep("load match", () => LoadScreen(match = new TestPlaylistsRoomSubScreen(SelectedRoom.Value)));
+ AddStep("load match", () => LoadScreen(match = new TestPlaylistsRoomSubScreen(SelectedRoom!.Value)));
AddUntilStep("wait for load", () => match.IsCurrentScreen());
}
@@ -115,7 +115,7 @@ namespace osu.Game.Tests.Visual.Playlists
});
});
- AddAssert("first playlist item selected", () => match.SelectedItem.Value == SelectedRoom.Value.Playlist[0]);
+ AddAssert("first playlist item selected", () => match.SelectedItem.Value == SelectedRoom!.Value.Playlist[0]);
}
[Test]
@@ -201,7 +201,7 @@ namespace osu.Game.Tests.Visual.Playlists
private void setupAndCreateRoom(Action room)
{
- AddStep("setup room", () => room(SelectedRoom.Value));
+ AddStep("setup room", () => room(SelectedRoom!.Value));
AddStep("click create button", () =>
{
diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs
index 5671cbebd7..cf4bec54ff 100644
--- a/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs
+++ b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs
@@ -26,8 +26,10 @@ using osu.Game.Scoring;
using osu.Game.Screens;
using osu.Game.Screens.Play;
using osu.Game.Screens.Ranking;
+using osu.Game.Screens.Ranking.Expanded.Accuracy;
using osu.Game.Screens.Ranking.Expanded.Statistics;
using osu.Game.Screens.Ranking.Statistics;
+using osu.Game.Skinning;
using osu.Game.Tests.Resources;
using osuTK;
using osuTK.Input;
@@ -44,6 +46,9 @@ namespace osu.Game.Tests.Visual.Ranking
[Resolved]
private RealmAccess realm { get; set; }
+ [Resolved]
+ private SkinManager skins { get; set; }
+
protected override void LoadComplete()
{
base.LoadComplete();
@@ -57,8 +62,17 @@ namespace osu.Game.Tests.Visual.Ranking
if (beatmapInfo != null)
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo);
});
+
+ AddToggleStep("toggle legacy classic skin", v =>
+ {
+ if (skins != null)
+ skins.CurrentSkinInfo.Value = v ? skins.DefaultClassicSkin.SkinInfo : skins.CurrentSkinInfo.Default;
+ });
}
+ [SetUp]
+ public void SetUp() => Schedule(() => skins.CurrentSkinInfo.SetDefault());
+
[Test]
public void TestScaling()
{
@@ -132,6 +146,46 @@ namespace osu.Game.Tests.Visual.Ranking
AddAssert("retry overlay present", () => screen.RetryOverlay != null);
}
+ [Test]
+ public void TestResultsWithFailingRank()
+ {
+ TestResultsScreen screen = null;
+
+ loadResultsScreen(() =>
+ {
+ var score = TestResources.CreateTestScoreInfo();
+
+ score.OnlineID = onlineScoreID++;
+ score.HitEvents = TestSceneStatisticsPanel.CreatePositionDistributedHitEvents();
+ score.Rank = ScoreRank.F;
+ return screen = createResultsScreen(score);
+ });
+ AddUntilStep("wait for loaded", () => screen.IsLoaded);
+ AddAssert("retry overlay present", () => screen.RetryOverlay != null);
+ AddAssert("no badges displayed", () => this.ChildrenOfType().All(b => !b.IsPresent));
+ }
+
+ [Test]
+ public void TestResultsWithFailingRankOnLegacySkin()
+ {
+ TestResultsScreen screen = null;
+
+ AddStep("set legacy skin", () => skins.CurrentSkinInfo.Value = skins.DefaultClassicSkin.SkinInfo);
+
+ loadResultsScreen(() =>
+ {
+ var score = TestResources.CreateTestScoreInfo();
+
+ score.OnlineID = onlineScoreID++;
+ score.HitEvents = TestSceneStatisticsPanel.CreatePositionDistributedHitEvents();
+ score.Rank = ScoreRank.F;
+ return screen = createResultsScreen(score);
+ });
+ AddUntilStep("wait for loaded", () => screen.IsLoaded);
+ AddAssert("retry overlay present", () => screen.RetryOverlay != null);
+ AddAssert("no badges displayed", () => this.ChildrenOfType().All(b => !b.IsPresent));
+ }
+
[Test]
public void TestShowHideStatisticsViaOutsideClick()
{
@@ -432,7 +486,7 @@ namespace osu.Game.Tests.Visual.Ranking
private class RulesetWithNoPerformanceCalculator : OsuRuleset
{
- public override PerformanceCalculator CreatePerformanceCalculator() => null;
+ public override PerformanceCalculator CreatePerformanceCalculator() => null!;
}
}
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs
index 9275f9755f..51da4d8755 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs
@@ -213,7 +213,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{
}
- public virtual IBindable UnreadCount => null;
+ public virtual IBindable UnreadCount { get; } = new Bindable();
public IEnumerable AllNotifications => Enumerable.Empty();
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs
index a95bb2c9e3..b79ce6c75f 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
+using osu.Framework.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
@@ -67,6 +68,15 @@ namespace osu.Game.Tests.Visual.UserInterface
AddAssert(@"Check empty multiplier", () => assertModsMultiplier(Array.Empty()));
}
+ [Test]
+ public void TestUnrankedBadge()
+ {
+ AddStep(@"Add unranked mod", () => changeMods(new[] { new OsuModDeflate() }));
+ AddAssert("Unranked badge shown", () => footerButtonMods.UnrankedBadge.Alpha == 1);
+ AddStep(@"Clear selected mod", () => changeMods(Array.Empty()));
+ AddAssert("Unranked badge not shown", () => footerButtonMods.UnrankedBadge.Alpha == 0);
+ }
+
private void changeMods(IReadOnlyList mods)
{
footerButtonMods.Current.Value = mods;
@@ -83,6 +93,7 @@ namespace osu.Game.Tests.Visual.UserInterface
private partial class TestFooterButtonMods : FooterButtonMods
{
public new OsuSpriteText MultiplierText => base.MultiplierText;
+ public new Drawable UnrankedBadge => base.UnrankedBadge;
}
}
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
index 046954db47..99a5897dff 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
@@ -119,7 +119,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddAssert("mod multiplier correct", () =>
{
double multiplier = SelectedMods.Value.Aggregate(1d, (m, mod) => m * mod.ScoreMultiplier);
- return Precision.AlmostEquals(multiplier, modSelectOverlay.ChildrenOfType().Single().Current.Value);
+ return Precision.AlmostEquals(multiplier, modSelectOverlay.ChildrenOfType().Single().ModMultiplier.Value);
});
assertCustomisationToggleState(disabled: false, active: false);
AddAssert("setting items created", () => modSelectOverlay.ChildrenOfType().Any());
@@ -134,7 +134,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddAssert("mod multiplier correct", () =>
{
double multiplier = SelectedMods.Value.Aggregate(1d, (m, mod) => m * mod.ScoreMultiplier);
- return Precision.AlmostEquals(multiplier, modSelectOverlay.ChildrenOfType().Single().Current.Value);
+ return Precision.AlmostEquals(multiplier, modSelectOverlay.ChildrenOfType().Single().ModMultiplier.Value);
});
assertCustomisationToggleState(disabled: false, active: false);
AddAssert("setting items created", () => modSelectOverlay.ChildrenOfType().Any());
@@ -846,7 +846,7 @@ namespace osu.Game.Tests.Visual.UserInterface
InputManager.Click(MouseButton.Left);
});
AddAssert("difficulty multiplier display shows correct value",
- () => modSelectOverlay.ChildrenOfType().Single().Current.Value, () => Is.EqualTo(0.1).Within(Precision.DOUBLE_EPSILON));
+ () => modSelectOverlay.ChildrenOfType().Single().ModMultiplier.Value, () => Is.EqualTo(0.1).Within(Precision.DOUBLE_EPSILON));
// this is highly unorthodox in a test, but because the `ModSettingChangeTracker` machinery heavily leans on events and object disposal and re-creation,
// it is instrumental in the reproduction of the failure scenario that this test is supposed to cover.
@@ -856,7 +856,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("reset half time speed to default", () => modSelectOverlay.ChildrenOfType().Single()
.ChildrenOfType>().Single().TriggerClick());
AddUntilStep("difficulty multiplier display shows correct value",
- () => modSelectOverlay.ChildrenOfType().Single().Current.Value, () => Is.EqualTo(0.3).Within(Precision.DOUBLE_EPSILON));
+ () => modSelectOverlay.ChildrenOfType().Single().ModMultiplier.Value, () => Is.EqualTo(0.3).Within(Precision.DOUBLE_EPSILON));
}
private void waitForColumnLoad() => AddUntilStep("all column content loaded", () =>
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneScoreMultiplierDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneRankingInformationDisplay.cs
similarity index 50%
rename from osu.Game.Tests/Visual/UserInterface/TestSceneScoreMultiplierDisplay.cs
rename to osu.Game.Tests/Visual/UserInterface/TestSceneRankingInformationDisplay.cs
index c2ddd814b7..42f243cc21 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneScoreMultiplierDisplay.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneRankingInformationDisplay.cs
@@ -11,7 +11,7 @@ using osu.Game.Overlays.Mods;
namespace osu.Game.Tests.Visual.UserInterface
{
[TestFixture]
- public partial class TestSceneScoreMultiplierDisplay : OsuTestScene
+ public partial class TestSceneRankingInformationDisplay : OsuTestScene
{
[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
@@ -19,22 +19,24 @@ namespace osu.Game.Tests.Visual.UserInterface
[Test]
public void TestBasic()
{
- ScoreMultiplierDisplay multiplierDisplay = null!;
+ RankingInformationDisplay onlinePropertiesDisplay = null!;
- AddStep("create content", () => Child = multiplierDisplay = new ScoreMultiplierDisplay
+ AddStep("create content", () => Child = onlinePropertiesDisplay = new RankingInformationDisplay
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
});
- AddStep("set multiplier below 1", () => multiplierDisplay.Current.Value = 0.5);
- AddStep("set multiplier to 1", () => multiplierDisplay.Current.Value = 1);
- AddStep("set multiplier above 1", () => multiplierDisplay.Current.Value = 1.5);
+ AddToggleStep("toggle ranked", ranked => onlinePropertiesDisplay.Ranked.Value = ranked);
+
+ AddStep("set multiplier below 1", () => onlinePropertiesDisplay.ModMultiplier.Value = 0.5);
+ AddStep("set multiplier to 1", () => onlinePropertiesDisplay.ModMultiplier.Value = 1);
+ AddStep("set multiplier above 1", () => onlinePropertiesDisplay.ModMultiplier.Value = 1.5);
AddSliderStep("set multiplier", 0, 2, 1d, multiplier =>
{
- if (multiplierDisplay.IsNotNull())
- multiplierDisplay.Current.Value = multiplier;
+ if (onlinePropertiesDisplay.IsNotNull())
+ onlinePropertiesDisplay.ModMultiplier.Value = multiplier;
});
}
}
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index 7b08524240..c0bbdfb4ed 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -10,7 +10,7 @@
WinExe
- net6.0
+ net8.0
tests.ruleset
diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
index 3b00f103c4..8f1d7114b1 100644
--- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
+++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
@@ -10,7 +10,7 @@
WinExe
- net6.0
+ net8.0
diff --git a/osu.Game.Tournament/osu.Game.Tournament.csproj b/osu.Game.Tournament/osu.Game.Tournament.csproj
index ab67e490cd..c8578ac464 100644
--- a/osu.Game.Tournament/osu.Game.Tournament.csproj
+++ b/osu.Game.Tournament/osu.Game.Tournament.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net8.0
Library
true
tools for tournaments.
diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
index 1ee4670ae2..386dada328 100644
--- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
@@ -567,10 +567,9 @@ namespace osu.Game.Beatmaps.Formats
for (int i = pendingControlPoints.Count - 1; i >= 0; i--)
{
var type = pendingControlPoints[i].GetType();
- if (pendingControlPointTypes.Contains(type))
+ if (!pendingControlPointTypes.Add(type))
continue;
- pendingControlPointTypes.Add(type);
beatmap.ControlPointInfo.Add(pendingControlPointsTime, pendingControlPoints[i]);
}
diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs
index 2c500146c5..74a85cde7c 100644
--- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs
@@ -116,7 +116,7 @@ namespace osu.Game.Beatmaps
ITrackStore IBeatmapResourceProvider.Tracks => trackStore;
IRenderer IStorageResourceProvider.Renderer => host?.Renderer ?? new DummyRenderer();
AudioManager IStorageResourceProvider.AudioManager => audioManager;
- RealmAccess IStorageResourceProvider.RealmAccess => null;
+ RealmAccess IStorageResourceProvider.RealmAccess => null!;
IResourceStore IStorageResourceProvider.Files => files;
IResourceStore IStorageResourceProvider.Resources => resources;
IResourceStore IStorageResourceProvider.CreateTextureLoaderStore(IResourceStore underlyingStore) => host?.CreateTextureLoaderStore(underlyingStore);
diff --git a/osu.Game/Graphics/Containers/SelectionCycleFillFlowContainer.cs b/osu.Game/Graphics/Containers/SelectionCycleFillFlowContainer.cs
index 62544c6111..098fd7b1ab 100644
--- a/osu.Game/Graphics/Containers/SelectionCycleFillFlowContainer.cs
+++ b/osu.Game/Graphics/Containers/SelectionCycleFillFlowContainer.cs
@@ -52,10 +52,10 @@ namespace osu.Game.Graphics.Containers
public override void Add(T drawable)
{
- base.Add(drawable);
-
Debug.Assert(drawable != null);
+ base.Add(drawable);
+
drawable.StateChanged += state => selectionChanged(drawable, state);
}
diff --git a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs
index af4b3849af..4af6ce7498 100644
--- a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs
+++ b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs
@@ -10,6 +10,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
using System.Linq;
+using JetBrains.Annotations;
using osu.Framework.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
@@ -48,6 +49,7 @@ namespace osu.Game.Graphics.UserInterface
{
protected virtual float ChevronSize => 10;
+ [CanBeNull]
public event Action StateChanged;
public readonly SpriteIcon Chevron;
diff --git a/osu.Game/IO/HardLinkHelper.cs b/osu.Game/IO/HardLinkHelper.cs
index 619bfdad6e..ad57f87d10 100644
--- a/osu.Game/IO/HardLinkHelper.cs
+++ b/osu.Game/IO/HardLinkHelper.cs
@@ -153,12 +153,12 @@ namespace osu.Game.IO
public static extern int link(string oldpath, string newpath);
[DllImport("libc", SetLastError = true)]
- private static extern int stat(string pathname, out struct_stat statbuf);
+ private static extern int stat(string pathname, out Stat statbuf);
// ReSharper disable once InconsistentNaming
// Struct layout is likely non-portable across unices. Tread with caution.
[StructLayout(LayoutKind.Sequential)]
- private struct struct_stat
+ private struct Stat
{
public readonly long st_dev;
public readonly long st_ino;
@@ -170,14 +170,14 @@ namespace osu.Game.IO
public readonly long st_size;
public readonly long st_blksize;
public readonly long st_blocks;
- public readonly timespec st_atim;
- public readonly timespec st_mtim;
- public readonly timespec st_ctim;
+ public readonly Timespec st_atim;
+ public readonly Timespec st_mtim;
+ public readonly Timespec st_ctim;
}
// ReSharper disable once InconsistentNaming
[StructLayout(LayoutKind.Sequential)]
- private struct timespec
+ private struct Timespec
{
public readonly long tv_sec;
public readonly long tv_nsec;
diff --git a/osu.Game/IO/IStorageResourceProvider.cs b/osu.Game/IO/IStorageResourceProvider.cs
index 08982a8b5f..91760971e8 100644
--- a/osu.Game/IO/IStorageResourceProvider.cs
+++ b/osu.Game/IO/IStorageResourceProvider.cs
@@ -41,6 +41,6 @@ namespace osu.Game.IO
///
/// The underlying provider of texture data (in arbitrary image formats).
/// A texture loader store.
- IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore);
+ IResourceStore? CreateTextureLoaderStore(IResourceStore underlyingStore);
}
}
diff --git a/osu.Game/Localisation/ModSelectOverlayStrings.cs b/osu.Game/Localisation/ModSelectOverlayStrings.cs
index 86ebebd293..9513eacf02 100644
--- a/osu.Game/Localisation/ModSelectOverlayStrings.cs
+++ b/osu.Game/Localisation/ModSelectOverlayStrings.cs
@@ -49,6 +49,26 @@ namespace osu.Game.Localisation
///
public static LocalisableString ScoreMultiplier => new TranslatableString(getKey(@"score_multiplier"), @"Score Multiplier");
+ ///
+ /// "Ranked"
+ ///
+ public static LocalisableString Ranked => new TranslatableString(getKey(@"ranked"), @"Ranked");
+
+ ///
+ /// "Performance points can be granted for the active mods."
+ ///
+ public static LocalisableString RankedExplanation => new TranslatableString(getKey(@"ranked_explanation"), @"Performance points can be granted for the active mods.");
+
+ ///
+ /// "Unranked"
+ ///
+ public static LocalisableString Unranked => new TranslatableString(getKey(@"unranked"), @"Unranked");
+
+ ///
+ /// "Performance points will not be granted due to active mods."
+ ///
+ public static LocalisableString UnrankedExplanation => new TranslatableString(getKey(@"ranked_explanation"), @"Performance points will not be granted due to active mods.");
+
private static string getKey(string key) => $@"{prefix}:{key}";
}
}
diff --git a/osu.Game/Localisation/ToolbarStrings.cs b/osu.Game/Localisation/ToolbarStrings.cs
index e71a3fff9b..5822f76e02 100644
--- a/osu.Game/Localisation/ToolbarStrings.cs
+++ b/osu.Game/Localisation/ToolbarStrings.cs
@@ -19,6 +19,11 @@ namespace osu.Game.Localisation
///
public static LocalisableString Connecting => new TranslatableString(getKey(@"connecting"), @"Connecting...");
+ ///
+ /// "Verification required"
+ ///
+ public static LocalisableString VerificationRequired => new TranslatableString(getKey(@"verification_required"), @"Verification required");
+
///
/// "home"
///
diff --git a/osu.Game/Online/API/OAuth.cs b/osu.Game/Online/API/OAuth.cs
index 485274f349..4829310870 100644
--- a/osu.Game/Online/API/OAuth.cs
+++ b/osu.Game/Online/API/OAuth.cs
@@ -128,19 +128,12 @@ namespace osu.Game.Online.API
// if we already have a valid access token, let's use it.
if (accessTokenValid) return true;
- // we want to ensure only a single authentication update is happening at once.
- lock (access_token_retrieval_lock)
- {
- // re-check if valid, in case another request completed and revalidated our access.
- if (accessTokenValid) return true;
+ // if not, let's try using our refresh token to request a new access token.
+ if (!string.IsNullOrEmpty(Token.Value?.RefreshToken))
+ // ReSharper disable once PossibleNullReferenceException
+ AuthenticateWithRefresh(Token.Value.RefreshToken);
- // if not, let's try using our refresh token to request a new access token.
- if (!string.IsNullOrEmpty(Token.Value?.RefreshToken))
- // ReSharper disable once PossibleNullReferenceException
- AuthenticateWithRefresh(Token.Value.RefreshToken);
-
- return accessTokenValid;
- }
+ return accessTokenValid;
}
private bool accessTokenValid => Token.Value?.IsValid ?? false;
@@ -149,14 +142,18 @@ namespace osu.Game.Online.API
internal string RequestAccessToken()
{
- if (!ensureAccessToken()) return null;
+ lock (access_token_retrieval_lock)
+ {
+ if (!ensureAccessToken()) return null;
- return Token.Value.AccessToken;
+ return Token.Value.AccessToken;
+ }
}
internal void Clear()
{
- Token.Value = null;
+ lock (access_token_retrieval_lock)
+ Token.Value = null;
}
private class AccessTokenRequestRefresh : AccessTokenRequest
diff --git a/osu.Game/Online/API/Requests/GetSystemTitleRequest.cs b/osu.Game/Online/API/Requests/GetSystemTitleRequest.cs
index 659e46bb11..52ca0c11eb 100644
--- a/osu.Game/Online/API/Requests/GetSystemTitleRequest.cs
+++ b/osu.Game/Online/API/Requests/GetSystemTitleRequest.cs
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
@@ -9,7 +8,7 @@ namespace osu.Game.Online.API.Requests
public class GetSystemTitleRequest : OsuJsonWebRequest
{
public GetSystemTitleRequest()
- : base($@"https://assets.ppy.sh/lazer-status.json?{DateTimeOffset.UtcNow.ToUnixTimeSeconds() / 1800}")
+ : base(@"https://assets.ppy.sh/lazer-status.json")
{
}
}
diff --git a/osu.Game/Online/Chat/WebSocketChatClient.cs b/osu.Game/Online/Chat/WebSocketChatClient.cs
index b74f8bec4b..8e1b501b25 100644
--- a/osu.Game/Online/Chat/WebSocketChatClient.cs
+++ b/osu.Game/Online/Chat/WebSocketChatClient.cs
@@ -61,7 +61,7 @@ namespace osu.Game.Online.Chat
{
await client.SendAsync(new StartChatRequest()).ConfigureAwait(false);
Logger.Log(@"Now listening to websocket chat messages.", LoggingTarget.Network);
- chatStartCancellationSource.Cancel();
+ await chatStartCancellationSource.CancelAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs
index 73fe29d441..596322d377 100644
--- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs
+++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs
@@ -29,14 +29,11 @@ namespace osu.Game.Online.Notifications.WebSocket
protected override async Task BuildConnectionAsync(CancellationToken cancellationToken)
{
- var tcs = new TaskCompletionSource();
-
var req = new GetNotificationsRequest();
- req.Success += bundle => tcs.SetResult(bundle.Endpoint);
- req.Failure += ex => tcs.SetException(ex);
- api.Queue(req);
-
- string endpoint = await tcs.Task.ConfigureAwait(false);
+ // must use `PerformAsync()`, since we may not be fully online yet
+ // (see `APIState.RequiresSecondFactorAuth` - in this state queued requests will not execute).
+ await api.PerformAsync(req).ConfigureAwait(false);
+ string endpoint = req.Response!.Endpoint;
ClientWebSocket socket = new ClientWebSocket();
socket.Options.SetRequestHeader(@"Authorization", @$"Bearer {api.AccessToken}");
diff --git a/osu.Game/Online/PersistentEndpointClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs
index 8c1b58a750..024a0fea73 100644
--- a/osu.Game/Online/PersistentEndpointClientConnector.cs
+++ b/osu.Game/Online/PersistentEndpointClientConnector.cs
@@ -69,6 +69,7 @@ namespace osu.Game.Online
break;
case APIState.Online:
+ case APIState.RequiresSecondFactorAuth:
await connect().ConfigureAwait(true);
break;
}
@@ -83,7 +84,7 @@ namespace osu.Game.Online
try
{
- while (apiState.Value == APIState.Online)
+ while (apiState.Value == APIState.RequiresSecondFactorAuth || apiState.Value == APIState.Online)
{
// ensure any previous connection was disposed.
// this will also create a new cancellation token source.
diff --git a/osu.Game/Online/Spectator/SpectatorClient.cs b/osu.Game/Online/Spectator/SpectatorClient.cs
index 7911701853..07ee9115d6 100644
--- a/osu.Game/Online/Spectator/SpectatorClient.cs
+++ b/osu.Game/Online/Spectator/SpectatorClient.cs
@@ -264,13 +264,12 @@ namespace osu.Game.Online.Spectator
{
Debug.Assert(ThreadSafety.IsUpdateThread);
- if (watchedUsersRefCounts.ContainsKey(userId))
+ if (!watchedUsersRefCounts.TryAdd(userId, 1))
{
watchedUsersRefCounts[userId]++;
return;
}
- watchedUsersRefCounts.Add(userId, 1);
WatchUserInternal(userId);
}
diff --git a/osu.Game/Overlays/AccountCreation/ScreenEmailVerification.cs b/osu.Game/Overlays/AccountCreation/ScreenEmailVerification.cs
new file mode 100644
index 0000000000..f3b42117ea
--- /dev/null
+++ b/osu.Game/Overlays/AccountCreation/ScreenEmailVerification.cs
@@ -0,0 +1,24 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Game.Overlays.Login;
+
+namespace osu.Game.Overlays.AccountCreation
+{
+ public partial class ScreenEmailVerification : AccountCreationScreen
+ {
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ InternalChild = new SecondFactorAuthForm
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding(20),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ };
+ }
+ }
+}
diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
index 9ad507d82a..f57c7d22a2 100644
--- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
+++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
@@ -1,12 +1,11 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
+using osu.Framework.Bindables;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -28,28 +27,30 @@ namespace osu.Game.Overlays.AccountCreation
{
public partial class ScreenEntry : AccountCreationScreen
{
- private ErrorTextFlowContainer usernameDescription;
- private ErrorTextFlowContainer emailAddressDescription;
- private ErrorTextFlowContainer passwordDescription;
+ private ErrorTextFlowContainer usernameDescription = null!;
+ private ErrorTextFlowContainer emailAddressDescription = null!;
+ private ErrorTextFlowContainer passwordDescription = null!;
- private OsuTextBox usernameTextBox;
- private OsuTextBox emailTextBox;
- private OsuPasswordTextBox passwordTextBox;
+ private OsuTextBox usernameTextBox = null!;
+ private OsuTextBox emailTextBox = null!;
+ private OsuPasswordTextBox passwordTextBox = null!;
[Resolved]
- private IAPIProvider api { get; set; }
+ private IAPIProvider api { get; set; } = null!;
- private ShakeContainer registerShake;
- private ITextPart characterCheckText;
+ private IBindable apiState = null!;
- private OsuTextBox[] textboxes;
- private LoadingLayer loadingLayer;
+ private ShakeContainer registerShake = null!;
+ private ITextPart characterCheckText = null!;
+
+ private OsuTextBox[] textboxes = null!;
+ private LoadingLayer loadingLayer = null!;
[Resolved]
- private GameHost host { get; set; }
+ private GameHost? host { get; set; }
[Resolved]
- private OsuGame game { get; set; }
+ private OsuGame? game { get; set; }
[BackgroundDependencyLoader]
private void load()
@@ -144,6 +145,8 @@ namespace osu.Game.Overlays.AccountCreation
passwordTextBox.Current.BindValueChanged(_ => updateCharacterCheckTextColour(), true);
characterCheckText.DrawablePartsRecreated += _ => updateCharacterCheckTextColour();
+
+ apiState = api.State.GetBoundCopy();
}
private void updateCharacterCheckTextColour()
@@ -180,7 +183,7 @@ namespace osu.Game.Overlays.AccountCreation
Task.Run(() =>
{
bool success;
- RegistrationRequest.RegistrationRequestErrors errors = null;
+ RegistrationRequest.RegistrationRequestErrors? errors = null;
try
{
@@ -210,7 +213,7 @@ namespace osu.Game.Overlays.AccountCreation
if (!string.IsNullOrEmpty(errors.Message))
passwordDescription.AddErrors(new[] { errors.Message });
- game.OpenUrlExternally($"{errors.Redirect}?username={usernameTextBox.Text}&email={emailTextBox.Text}", true);
+ game?.OpenUrlExternally($"{errors.Redirect}?username={usernameTextBox.Text}&email={emailTextBox.Text}", true);
}
}
else
@@ -223,6 +226,12 @@ namespace osu.Game.Overlays.AccountCreation
return;
}
+ apiState.BindValueChanged(state =>
+ {
+ if (state.NewValue == APIState.RequiresSecondFactorAuth)
+ this.Push(new ScreenEmailVerification());
+ });
+
api.Login(usernameTextBox.Text, passwordTextBox.Text);
});
});
@@ -241,6 +250,6 @@ namespace osu.Game.Overlays.AccountCreation
return false;
}
- private OsuTextBox nextUnfilledTextBox() => textboxes.FirstOrDefault(t => string.IsNullOrEmpty(t.Text));
+ private OsuTextBox? nextUnfilledTextBox() => textboxes.FirstOrDefault(t => string.IsNullOrEmpty(t.Text));
}
}
diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs
index 0fbf6ba59e..c24bd32bb4 100644
--- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs
+++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -23,14 +21,14 @@ namespace osu.Game.Overlays.AccountCreation
{
public partial class ScreenWarning : AccountCreationScreen
{
- private OsuTextFlowContainer multiAccountExplanationText;
- private LinkFlowContainer furtherAssistance;
+ private OsuTextFlowContainer multiAccountExplanationText = null!;
+ private LinkFlowContainer furtherAssistance = null!;
- [Resolved(canBeNull: true)]
- private IAPIProvider api { get; set; }
+ [Resolved]
+ private IAPIProvider? api { get; set; }
- [Resolved(canBeNull: true)]
- private OsuGame game { get; set; }
+ [Resolved]
+ private OsuGame? game { get; set; }
private const string help_centre_url = "/help/wiki/Help_Centre#login";
diff --git a/osu.Game/Overlays/AccountCreationOverlay.cs b/osu.Game/Overlays/AccountCreationOverlay.cs
index 576ee92b48..82fc5508f1 100644
--- a/osu.Game/Overlays/AccountCreationOverlay.cs
+++ b/osu.Game/Overlays/AccountCreationOverlay.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -25,7 +23,9 @@ namespace osu.Game.Overlays
{
private const float transition_time = 400;
- private ScreenWelcome welcomeScreen;
+ private ScreenWelcome welcomeScreen = null!;
+
+ private ScheduledDelegate? scheduledHide;
public AccountCreationOverlay()
{
@@ -108,8 +108,6 @@ namespace osu.Game.Overlays
this.FadeOut(100);
}
- private ScheduledDelegate scheduledHide;
-
private void apiStateChanged(ValueChangedEvent state)
{
switch (state.NewValue)
diff --git a/osu.Game/Overlays/Comments/VotePill.cs b/osu.Game/Overlays/Comments/VotePill.cs
index dd418a9e58..8c5aaa062f 100644
--- a/osu.Game/Overlays/Comments/VotePill.cs
+++ b/osu.Game/Overlays/Comments/VotePill.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Overlays.Comments
public Color4 AccentColour { get; set; }
- protected override IEnumerable EffectTargets => null;
+ protected override IEnumerable EffectTargets => Enumerable.Empty();
[Resolved]
private IAPIProvider api { get; set; }
diff --git a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs
index a25147b69f..f4f6fd2bc1 100644
--- a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs
+++ b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs
@@ -4,6 +4,7 @@
#nullable disable
using System;
+using JetBrains.Annotations;
using osu.Framework;
using osuTK;
using osu.Framework.Allocation;
@@ -24,6 +25,7 @@ namespace osu.Game.Overlays.MedalSplash
private const float scale_when_unlocked = 0.76f;
private const float scale_when_full = 0.6f;
+ [CanBeNull]
public event Action StateChanged;
private readonly Medal medal;
diff --git a/osu.Game/Overlays/Mods/EditPresetPopover.cs b/osu.Game/Overlays/Mods/EditPresetPopover.cs
index 8bce57c96a..9554ba8ce2 100644
--- a/osu.Game/Overlays/Mods/EditPresetPopover.cs
+++ b/osu.Game/Overlays/Mods/EditPresetPopover.cs
@@ -92,7 +92,7 @@ namespace osu.Game.Overlays.Mods
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
- Direction = FillDirection.Horizontal,
+ RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(7),
Children = new Drawable[]
diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs
index 7271c53e7a..ddf96c1cb3 100644
--- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs
+++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs
@@ -125,7 +125,7 @@ namespace osu.Game.Overlays.Mods
private DeselectAllModsButton deselectAllModsButton = null!;
private Container aboveColumnsContent = null!;
- private ScoreMultiplierDisplay? multiplierDisplay;
+ private RankingInformationDisplay? rankingInformationDisplay;
private BeatmapAttributesDisplay? beatmapAttributesDisplay;
protected ShearedButton BackButton { get; private set; } = null!;
@@ -185,7 +185,7 @@ namespace osu.Game.Overlays.Mods
aboveColumnsContent = new Container
{
RelativeSizeAxes = Axes.X,
- Height = ScoreMultiplierDisplay.HEIGHT,
+ Height = RankingInformationDisplay.HEIGHT,
Padding = new MarginPadding { Horizontal = 100 },
Child = SearchTextBox = new ShearedSearchTextBox
{
@@ -200,7 +200,7 @@ namespace osu.Game.Overlays.Mods
{
Padding = new MarginPadding
{
- Top = ScoreMultiplierDisplay.HEIGHT + PADDING,
+ Top = RankingInformationDisplay.HEIGHT + PADDING,
Bottom = PADDING
},
RelativeSizeAxes = Axes.Both,
@@ -269,7 +269,7 @@ namespace osu.Game.Overlays.Mods
},
Children = new Drawable[]
{
- multiplierDisplay = new ScoreMultiplierDisplay
+ rankingInformationDisplay = new RankingInformationDisplay
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight
@@ -315,7 +315,7 @@ namespace osu.Game.Overlays.Mods
SelectedMods.BindValueChanged(_ =>
{
- updateMultiplier();
+ updateRankingInformation();
updateFromExternalSelection();
updateCustomisation();
@@ -328,7 +328,7 @@ namespace osu.Game.Overlays.Mods
//
// See https://github.com/ppy/osu/pull/23284#issuecomment-1529056988
modSettingChangeTracker = new ModSettingChangeTracker(SelectedMods.Value);
- modSettingChangeTracker.SettingChanged += _ => updateMultiplier();
+ modSettingChangeTracker.SettingChanged += _ => updateRankingInformation();
}
}, true);
@@ -450,9 +450,9 @@ namespace osu.Game.Overlays.Mods
modState.ValidForSelection.Value = modState.Mod.Type != ModType.System && modState.Mod.HasImplementation && IsValidMod.Invoke(modState.Mod);
}
- private void updateMultiplier()
+ private void updateRankingInformation()
{
- if (multiplierDisplay == null)
+ if (rankingInformationDisplay == null)
return;
double multiplier = 1.0;
@@ -460,7 +460,8 @@ namespace osu.Game.Overlays.Mods
foreach (var mod in SelectedMods.Value)
multiplier *= mod.ScoreMultiplier;
- multiplierDisplay.Current.Value = multiplier;
+ rankingInformationDisplay.ModMultiplier.Value = multiplier;
+ rankingInformationDisplay.Ranked.Value = SelectedMods.Value.All(m => m.Ranked);
}
private void updateCustomisation()
diff --git a/osu.Game/Overlays/Mods/ScoreMultiplierDisplay.cs b/osu.Game/Overlays/Mods/RankingInformationDisplay.cs
similarity index 60%
rename from osu.Game/Overlays/Mods/ScoreMultiplierDisplay.cs
rename to osu.Game/Overlays/Mods/RankingInformationDisplay.cs
index a86eba81e4..494f8a377f 100644
--- a/osu.Game/Overlays/Mods/ScoreMultiplierDisplay.cs
+++ b/osu.Game/Overlays/Mods/RankingInformationDisplay.cs
@@ -6,8 +6,8 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
-using osu.Framework.Graphics.UserInterface;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
@@ -22,15 +22,13 @@ namespace osu.Game.Overlays.Mods
///
/// On the mod select overlay, this provides a local updating view of the aggregate score multiplier coming from mods.
///
- public partial class ScoreMultiplierDisplay : ModFooterInformationDisplay, IHasCurrentValue
+ public partial class RankingInformationDisplay : ModFooterInformationDisplay
{
public const float HEIGHT = 42;
- public Bindable Current
- {
- get => current.Current;
- set => current.Current = value;
- }
+ public Bindable ModMultiplier = new BindableDouble(1);
+
+ public Bindable Ranked { get; } = new BindableBool(true);
private readonly BindableWithCurrent current = new BindableWithCurrent();
@@ -39,16 +37,11 @@ namespace osu.Game.Overlays.Mods
private RollingCounter counter = null!;
private Box flashLayer = null!;
+ private TextWithTooltip rankedText = null!;
[Resolved]
private OsuColour colours { get; set; } = null!;
- public ScoreMultiplierDisplay()
- {
- Current.Default = 1d;
- Current.Value = 1d;
- }
-
[BackgroundDependencyLoader]
private void load()
{
@@ -75,13 +68,20 @@ namespace osu.Game.Overlays.Mods
LeftContent.AddRange(new Drawable[]
{
- new OsuSpriteText
+ new Container
{
+ Width = 50,
+ RelativeSizeAxes = Axes.Y,
+ Margin = new MarginPadding(10),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0),
- Text = ModSelectOverlayStrings.ScoreMultiplier,
- Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold)
+ Child = rankedText = new TextWithTooltip
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0),
+ Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold)
+ }
}
});
@@ -97,7 +97,7 @@ namespace osu.Game.Overlays.Mods
Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- Current = { BindTarget = Current }
+ Current = { BindTarget = ModMultiplier }
}
});
}
@@ -106,30 +106,22 @@ namespace osu.Game.Overlays.Mods
{
base.LoadComplete();
- Current.BindValueChanged(e =>
+ ModMultiplier.BindValueChanged(e =>
{
- if (e.NewValue > Current.Default)
+ if (e.NewValue > ModMultiplier.Default)
{
- MainBackground
- .FadeColour(colours.ForModType(ModType.DifficultyIncrease), transition_duration, Easing.OutQuint);
- counter.FadeColour(ColourProvider.Background5, transition_duration, Easing.OutQuint);
+ counter.FadeColour(colours.ForModType(ModType.DifficultyIncrease), transition_duration, Easing.OutQuint);
}
- else if (e.NewValue < Current.Default)
+ else if (e.NewValue < ModMultiplier.Default)
{
- MainBackground
- .FadeColour(colours.ForModType(ModType.DifficultyReduction), transition_duration, Easing.OutQuint);
- counter.FadeColour(ColourProvider.Background5, transition_duration, Easing.OutQuint);
+ counter.FadeColour(colours.ForModType(ModType.DifficultyReduction), transition_duration, Easing.OutQuint);
}
else
{
- MainBackground.FadeColour(ColourProvider.Background4, transition_duration, Easing.OutQuint);
counter.FadeColour(Colour4.White, transition_duration, Easing.OutQuint);
}
- flashLayer
- .FadeOutFromOne()
- .FadeTo(0.15f, 60, Easing.OutQuint)
- .Then().FadeOut(500, Easing.OutQuint);
+ flash();
const float move_amount = 4;
if (e.NewValue > e.OldValue)
@@ -140,10 +132,43 @@ namespace osu.Game.Overlays.Mods
// required to prevent the counter initially rolling up from 0 to 1
// due to `Current.Value` having a nonstandard default value of 1.
- counter.SetCountWithoutRolling(Current.Value);
+ counter.SetCountWithoutRolling(ModMultiplier.Value);
+
+ Ranked.BindValueChanged(e =>
+ {
+ flash();
+
+ if (e.NewValue)
+ {
+ rankedText.Text = ModSelectOverlayStrings.Ranked;
+ rankedText.TooltipText = ModSelectOverlayStrings.RankedExplanation;
+ rankedText.FadeColour(Colour4.White, transition_duration, Easing.OutQuint);
+ FrontBackground.FadeColour(ColourProvider.Background3, transition_duration, Easing.OutQuint);
+ }
+ else
+ {
+ rankedText.Text = ModSelectOverlayStrings.Unranked;
+ rankedText.TooltipText = ModSelectOverlayStrings.UnrankedExplanation;
+ rankedText.FadeColour(ColourProvider.Background5, transition_duration, Easing.OutQuint);
+ FrontBackground.FadeColour(colours.Orange1, transition_duration, Easing.OutQuint);
+ }
+ }, true);
}
- private partial class EffectCounter : RollingCounter
+ private void flash()
+ {
+ flashLayer
+ .FadeOutFromOne()
+ .FadeTo(0.15f, 60, Easing.OutQuint)
+ .Then().FadeOut(500, Easing.OutQuint);
+ }
+
+ private partial class TextWithTooltip : OsuSpriteText, IHasTooltip
+ {
+ public LocalisableString TooltipText { get; set; }
+ }
+
+ private partial class EffectCounter : RollingCounter, IHasTooltip
{
protected override double RollingDuration => 250;
@@ -155,6 +180,8 @@ namespace osu.Game.Overlays.Mods
Origin = Anchor.Centre,
Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold)
};
+
+ public LocalisableString TooltipText => ModSelectOverlayStrings.ScoreMultiplier;
}
}
}
diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs
index 28521e3331..2620e850c8 100644
--- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs
+++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs
@@ -95,11 +95,10 @@ namespace osu.Game.Overlays.Toolbar
private void onlineStateChanged(ValueChangedEvent state) => Schedule(() =>
{
- failingIcon.FadeTo(state.NewValue == APIState.Failing ? 1 : 0, 200, Easing.OutQuint);
+ failingIcon.FadeTo(state.NewValue == APIState.Failing || state.NewValue == APIState.RequiresSecondFactorAuth ? 1 : 0, 200, Easing.OutQuint);
switch (state.NewValue)
{
- case APIState.RequiresSecondFactorAuth:
case APIState.Connecting:
TooltipText = ToolbarStrings.Connecting;
spinner.Show();
@@ -108,6 +107,13 @@ namespace osu.Game.Overlays.Toolbar
case APIState.Failing:
TooltipText = ToolbarStrings.AttemptingToReconnect;
spinner.Show();
+ failingIcon.Icon = FontAwesome.Solid.ExclamationTriangle;
+ break;
+
+ case APIState.RequiresSecondFactorAuth:
+ TooltipText = ToolbarStrings.VerificationRequired;
+ spinner.Show();
+ failingIcon.Icon = FontAwesome.Solid.Key;
break;
case APIState.Offline:
diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs
index 9ca4c25ab9..6ec4971f06 100644
--- a/osu.Game/Overlays/Volume/VolumeMeter.cs
+++ b/osu.Game/Overlays/Volume/VolumeMeter.cs
@@ -5,6 +5,7 @@
using System;
using System.Globalization;
+using JetBrains.Annotations;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
@@ -48,6 +49,7 @@ namespace osu.Game.Overlays.Volume
private Sample notchSample;
private double sampleLastPlaybackTime;
+ [CanBeNull]
public event Action StateChanged;
private SelectionState state;
diff --git a/osu.Game/Rulesets/Judgements/Judgement.cs b/osu.Game/Rulesets/Judgements/Judgement.cs
index 93386de483..d4d06167f1 100644
--- a/osu.Game/Rulesets/Judgements/Judgement.cs
+++ b/osu.Game/Rulesets/Judgements/Judgement.cs
@@ -73,9 +73,11 @@ namespace osu.Game.Rulesets.Judgements
return HitResult.SmallTickMiss;
case HitResult.LargeTickHit:
- case HitResult.SliderTailHit:
return HitResult.LargeTickMiss;
+ case HitResult.SliderTailHit:
+ return HitResult.IgnoreMiss;
+
default:
return HitResult.Miss;
}
diff --git a/osu.Game/Rulesets/Mods/IMod.cs b/osu.Game/Rulesets/Mods/IMod.cs
index 744d02a4fa..3a33d14835 100644
--- a/osu.Game/Rulesets/Mods/IMod.cs
+++ b/osu.Game/Rulesets/Mods/IMod.cs
@@ -66,6 +66,11 @@ namespace osu.Game.Rulesets.Mods
///
bool AlwaysValidForSubmission { get; }
+ ///
+ /// Whether scores with this mod active can give performance points.
+ ///
+ bool Ranked { get; }
+
///
/// Create a fresh instance based on this mod.
///
diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs
index 0500b49513..50c867f41b 100644
--- a/osu.Game/Rulesets/Mods/Mod.cs
+++ b/osu.Game/Rulesets/Mods/Mod.cs
@@ -167,6 +167,12 @@ namespace osu.Game.Rulesets.Mods
[JsonIgnore]
public virtual bool RequiresConfiguration => false;
+ ///
+ /// Whether scores with this mod active can give performance points.
+ ///
+ [JsonIgnore]
+ public virtual bool Ranked => false;
+
///
/// The mods this mod cannot be enabled with.
///
diff --git a/osu.Game/Rulesets/Mods/ModDaycore.cs b/osu.Game/Rulesets/Mods/ModDaycore.cs
index 09b35c249e..359f8a950c 100644
--- a/osu.Game/Rulesets/Mods/ModDaycore.cs
+++ b/osu.Game/Rulesets/Mods/ModDaycore.cs
@@ -17,6 +17,7 @@ namespace osu.Game.Rulesets.Mods
public override IconUsage? Icon => null;
public override ModType Type => ModType.DifficultyReduction;
public override LocalisableString Description => "Whoaaaaa...";
+ public override bool Ranked => UsesDefaultConfiguration;
[SettingSource("Speed decrease", "The actual decrease to apply", SettingControlType = typeof(MultiplierSettingsSlider))]
public override BindableNumber SpeedChange { get; } = new BindableDouble(0.75)
diff --git a/osu.Game/Rulesets/Mods/ModDoubleTime.cs b/osu.Game/Rulesets/Mods/ModDoubleTime.cs
index 789291772d..8e430da368 100644
--- a/osu.Game/Rulesets/Mods/ModDoubleTime.cs
+++ b/osu.Game/Rulesets/Mods/ModDoubleTime.cs
@@ -18,6 +18,7 @@ namespace osu.Game.Rulesets.Mods
public override IconUsage? Icon => OsuIcon.ModDoubleTime;
public override ModType Type => ModType.DifficultyIncrease;
public override LocalisableString Description => "Zoooooooooom...";
+ public override bool Ranked => UsesDefaultConfiguration;
[SettingSource("Speed increase", "The actual increase to apply", SettingControlType = typeof(MultiplierSettingsSlider))]
public override BindableNumber SpeedChange { get; } = new BindableDouble(1.5)
diff --git a/osu.Game/Rulesets/Mods/ModEasy.cs b/osu.Game/Rulesets/Mods/ModEasy.cs
index 0f51e2a6d5..da43a6b294 100644
--- a/osu.Game/Rulesets/Mods/ModEasy.cs
+++ b/osu.Game/Rulesets/Mods/ModEasy.cs
@@ -16,6 +16,7 @@ namespace osu.Game.Rulesets.Mods
public override ModType Type => ModType.DifficultyReduction;
public override double ScoreMultiplier => 0.5;
public override Type[] IncompatibleMods => new[] { typeof(ModHardRock), typeof(ModDifficultyAdjust) };
+ public override bool Ranked => UsesDefaultConfiguration;
public virtual void ReadFromDifficulty(BeatmapDifficulty difficulty)
{
diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs
index dc2ad6f47e..9227af64b8 100644
--- a/osu.Game/Rulesets/Mods/ModFlashlight.cs
+++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs
@@ -33,6 +33,7 @@ namespace osu.Game.Rulesets.Mods
public override IconUsage? Icon => OsuIcon.ModFlashlight;
public override ModType Type => ModType.DifficultyIncrease;
public override LocalisableString Description => "Restricted view area.";
+ public override bool Ranked => UsesDefaultConfiguration;
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
public abstract BindableFloat SizeMultiplier { get; }
diff --git a/osu.Game/Rulesets/Mods/ModHalfTime.cs b/osu.Game/Rulesets/Mods/ModHalfTime.cs
index 8b5dd39584..59e40ee9cc 100644
--- a/osu.Game/Rulesets/Mods/ModHalfTime.cs
+++ b/osu.Game/Rulesets/Mods/ModHalfTime.cs
@@ -18,6 +18,7 @@ namespace osu.Game.Rulesets.Mods
public override IconUsage? Icon => OsuIcon.ModHalftime;
public override ModType Type => ModType.DifficultyReduction;
public override LocalisableString Description => "Less zoom...";
+ public override bool Ranked => UsesDefaultConfiguration;
[SettingSource("Speed decrease", "The actual decrease to apply", SettingControlType = typeof(MultiplierSettingsSlider))]
public override BindableNumber SpeedChange { get; } = new BindableDouble(0.75)
diff --git a/osu.Game/Rulesets/Mods/ModHardRock.cs b/osu.Game/Rulesets/Mods/ModHardRock.cs
index 4b2d1d050e..1e99891b99 100644
--- a/osu.Game/Rulesets/Mods/ModHardRock.cs
+++ b/osu.Game/Rulesets/Mods/ModHardRock.cs
@@ -17,6 +17,7 @@ namespace osu.Game.Rulesets.Mods
public override ModType Type => ModType.DifficultyIncrease;
public override LocalisableString Description => "Everything just got a bit harder...";
public override Type[] IncompatibleMods => new[] { typeof(ModEasy), typeof(ModDifficultyAdjust) };
+ public override bool Ranked => UsesDefaultConfiguration;
protected const float ADJUST_RATIO = 1.4f;
diff --git a/osu.Game/Rulesets/Mods/ModHidden.cs b/osu.Game/Rulesets/Mods/ModHidden.cs
index 8b25768575..5a1abf115f 100644
--- a/osu.Game/Rulesets/Mods/ModHidden.cs
+++ b/osu.Game/Rulesets/Mods/ModHidden.cs
@@ -14,6 +14,7 @@ namespace osu.Game.Rulesets.Mods
public override string Acronym => "HD";
public override IconUsage? Icon => OsuIcon.ModHidden;
public override ModType Type => ModType.DifficultyIncrease;
+ public override bool Ranked => UsesDefaultConfiguration;
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
{
diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs
index 131f501630..3ecd9aa6a1 100644
--- a/osu.Game/Rulesets/Mods/ModMuted.cs
+++ b/osu.Game/Rulesets/Mods/ModMuted.cs
@@ -25,6 +25,7 @@ namespace osu.Game.Rulesets.Mods
public override LocalisableString Description => "Can you still feel the rhythm without music?";
public override ModType Type => ModType.Fun;
public override double ScoreMultiplier => 1;
+ public override bool Ranked => UsesDefaultConfiguration;
}
public abstract class ModMuted : ModMuted, IApplicableToDrawableRuleset, IApplicableToTrack, IApplicableToScoreProcessor
diff --git a/osu.Game/Rulesets/Mods/ModNightcore.cs b/osu.Game/Rulesets/Mods/ModNightcore.cs
index b42927256c..bb18940f8c 100644
--- a/osu.Game/Rulesets/Mods/ModNightcore.cs
+++ b/osu.Game/Rulesets/Mods/ModNightcore.cs
@@ -28,6 +28,7 @@ namespace osu.Game.Rulesets.Mods
public override IconUsage? Icon => OsuIcon.ModNightcore;
public override ModType Type => ModType.DifficultyIncrease;
public override LocalisableString Description => "Uguuuuuuuu...";
+ public override bool Ranked => UsesDefaultConfiguration;
[SettingSource("Speed increase", "The actual increase to apply", SettingControlType = typeof(MultiplierSettingsSlider))]
public override BindableNumber SpeedChange { get; } = new BindableDouble(1.5)
diff --git a/osu.Game/Rulesets/Mods/ModNoFail.cs b/osu.Game/Rulesets/Mods/ModNoFail.cs
index cc451772b2..1aaef8eac4 100644
--- a/osu.Game/Rulesets/Mods/ModNoFail.cs
+++ b/osu.Game/Rulesets/Mods/ModNoFail.cs
@@ -20,6 +20,7 @@ namespace osu.Game.Rulesets.Mods
public override LocalisableString Description => "You can't fail, no matter what.";
public override double ScoreMultiplier => 0.5;
public override Type[] IncompatibleMods => new[] { typeof(ModFailCondition), typeof(ModCinema) };
+ public override bool Ranked => UsesDefaultConfiguration;
private readonly Bindable showHealthBar = new Bindable();
diff --git a/osu.Game/Rulesets/Mods/ModPerfect.cs b/osu.Game/Rulesets/Mods/ModPerfect.cs
index 0ba40ba070..f8f498ceb5 100644
--- a/osu.Game/Rulesets/Mods/ModPerfect.cs
+++ b/osu.Game/Rulesets/Mods/ModPerfect.cs
@@ -19,6 +19,7 @@ namespace osu.Game.Rulesets.Mods
public override ModType Type => ModType.DifficultyIncrease;
public override double ScoreMultiplier => 1;
public override LocalisableString Description => "SS or quit.";
+ public override bool Ranked => UsesDefaultConfiguration;
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(ModSuddenDeath), typeof(ModAccuracyChallenge) }).ToArray();
diff --git a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs
index 4e4e8662e8..62579a168c 100644
--- a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs
+++ b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs
@@ -19,6 +19,7 @@ namespace osu.Game.Rulesets.Mods
public override ModType Type => ModType.DifficultyIncrease;
public override LocalisableString Description => "Miss and fail.";
public override double ScoreMultiplier => 1;
+ public override bool Ranked => UsesDefaultConfiguration;
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModPerfect)).ToArray();
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index 5662fb2293..161537200a 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -11,6 +11,7 @@ using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Extensions.TypeExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
@@ -139,7 +140,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
protected override bool RequiresChildrenUpdate => true;
- public override bool IsPresent => base.IsPresent || (State.Value == ArmedState.Idle && Clock?.CurrentTime >= LifetimeStart);
+ public override bool IsPresent => base.IsPresent || (State.Value == ArmedState.Idle && Clock.IsNotNull() && Clock.CurrentTime >= LifetimeStart);
private readonly Bindable state = new Bindable();
diff --git a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs
index fabf4fc444..7977166cb2 100644
--- a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs
+++ b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs
@@ -47,12 +47,9 @@ namespace osu.Game.Rulesets.Objects.Pooling
{
HitObject hitObject = entry.HitObject;
- if (entryMap.ContainsKey(hitObject))
+ if (!entryMap.TryAdd(hitObject, entry))
throw new InvalidOperationException($@"The {nameof(HitObjectLifetimeEntry)} is already added to this {nameof(HitObjectEntryManager)}.");
- // Add the entry.
- entryMap[hitObject] = entry;
-
// If the entry has a parent, set it and add the entry to the parent's children.
if (parent != null)
{
diff --git a/osu.Game/Rulesets/Scoring/HitEventExtensions.cs b/osu.Game/Rulesets/Scoring/HitEventExtensions.cs
index 9fb61c6cd9..6e2852676a 100644
--- a/osu.Game/Rulesets/Scoring/HitEventExtensions.cs
+++ b/osu.Game/Rulesets/Scoring/HitEventExtensions.cs
@@ -13,6 +13,9 @@ namespace osu.Game.Rulesets.Scoring
///
/// Calculates the "unstable rate" for a sequence of s.
///
+ ///
+ /// Uses Welford's online algorithm.
+ ///
///
/// A non-null value if unstable rate could be calculated,
/// and if unstable rate cannot be calculated due to being empty.
@@ -21,9 +24,28 @@ namespace osu.Game.Rulesets.Scoring
{
Debug.Assert(hitEvents.All(ev => ev.GameplayRate != null));
- // Division by gameplay rate is to account for TimeOffset scaling with gameplay rate.
- double[] timeOffsets = hitEvents.Where(affectsUnstableRate).Select(ev => ev.TimeOffset / ev.GameplayRate!.Value).ToArray();
- return 10 * standardDeviation(timeOffsets);
+ int count = 0;
+ double mean = 0;
+ double sumOfSquares = 0;
+
+ foreach (var e in hitEvents)
+ {
+ if (!affectsUnstableRate(e))
+ continue;
+
+ count++;
+
+ // Division by gameplay rate is to account for TimeOffset scaling with gameplay rate.
+ double currentValue = e.TimeOffset / e.GameplayRate!.Value;
+ double nextMean = mean + (currentValue - mean) / count;
+ sumOfSquares += (currentValue - mean) * (currentValue - nextMean);
+ mean = nextMean;
+ }
+
+ if (count == 0)
+ return null;
+
+ return 10.0 * Math.Sqrt(sumOfSquares / count);
}
///
@@ -44,15 +66,5 @@ namespace osu.Game.Rulesets.Scoring
}
private static bool affectsUnstableRate(HitEvent e) => !(e.HitObject.HitWindows is HitWindows.EmptyHitWindows) && e.Result.IsHit();
-
- private static double? standardDeviation(double[] timeOffsets)
- {
- if (timeOffsets.Length == 0)
- return null;
-
- double mean = timeOffsets.Average();
- double squares = timeOffsets.Select(offset => Math.Pow(offset - mean, 2)).Sum();
- return Math.Sqrt(squares / timeOffsets.Length);
- }
}
}
diff --git a/osu.Game/Rulesets/Scoring/HitResult.cs b/osu.Game/Rulesets/Scoring/HitResult.cs
index 20ec3c4946..b6cfca58db 100644
--- a/osu.Game/Rulesets/Scoring/HitResult.cs
+++ b/osu.Game/Rulesets/Scoring/HitResult.cs
@@ -138,7 +138,8 @@ namespace osu.Game.Rulesets.Scoring
ComboBreak,
///
- /// A special judgement similar to that's used to increase the valuation of the final tick of a slider.
+ /// A special tick judgement to increase the valuation of the final tick of a slider.
+ /// The default minimum result is , but may be overridden to .
///
[EnumMember(Value = "slider_tail_hit")]
[Order(8)]
diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs
index e9c35555c8..90a2f63faa 100644
--- a/osu.Game/Rulesets/UI/Playfield.cs
+++ b/osu.Game/Rulesets/UI/Playfield.cs
@@ -247,10 +247,14 @@ namespace osu.Game.Rulesets.UI
nestedPlayfields.Add(otherPlayfield);
}
+ private Mod[] mods;
+
protected override void LoadComplete()
{
base.LoadComplete();
+ mods = Mods?.ToArray();
+
// in the case a consumer forgets to add the HitObjectContainer, we will add it here.
if (HitObjectContainer.Parent == null)
AddInternal(HitObjectContainer);
@@ -260,9 +264,9 @@ namespace osu.Game.Rulesets.UI
{
base.Update();
- if (!IsNested && Mods != null)
+ if (!IsNested && mods != null)
{
- foreach (var mod in Mods)
+ foreach (Mod mod in mods)
{
if (mod is IUpdatableByPlayfield updatable)
updatable.Update(this);
@@ -403,10 +407,13 @@ namespace osu.Game.Rulesets.UI
// If this is the first time this DHO is being used, then apply the DHO mods.
// This is done before Apply() so that the state is updated once when the hitobject is applied.
- if (Mods != null)
+ if (mods != null)
{
- foreach (var m in Mods.OfType())
- m.ApplyToDrawableHitObject(dho);
+ foreach (Mod mod in mods)
+ {
+ if (mod is IApplicableToDrawableHitObject applicable)
+ applicable.ApplyToDrawableHitObject(dho);
+ }
}
}
diff --git a/osu.Game/Screens/Edit/Compose/Components/DragBox.cs b/osu.Game/Screens/Edit/Compose/Components/DragBox.cs
index 4d1f81228e..b83e565e89 100644
--- a/osu.Game/Screens/Edit/Compose/Components/DragBox.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/DragBox.cs
@@ -4,6 +4,7 @@
#nullable disable
using System;
+using JetBrains.Annotations;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
@@ -69,6 +70,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
public override void Show() => State = Visibility.Visible;
+ [CanBeNull]
public event Action StateChanged;
public partial class BoxWithBorders : CompositeDrawable
diff --git a/osu.Game/Screens/Menu/ButtonArea.cs b/osu.Game/Screens/Menu/ButtonArea.cs
index 69ba68442f..4eb91c526f 100644
--- a/osu.Game/Screens/Menu/ButtonArea.cs
+++ b/osu.Game/Screens/Menu/ButtonArea.cs
@@ -4,6 +4,7 @@
#nullable disable
using System;
+using JetBrains.Annotations;
using osu.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -88,6 +89,7 @@ namespace osu.Game.Screens.Menu
public override void Show() => State = Visibility.Visible;
+ [CanBeNull]
public event Action StateChanged;
private partial class ButtonAreaBackground : Box, IStateful
@@ -146,6 +148,7 @@ namespace osu.Game.Screens.Menu
}
}
+ [CanBeNull]
public event Action StateChanged;
}
diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs
index a75edd1cff..decb901c32 100644
--- a/osu.Game/Screens/Menu/MainMenu.cs
+++ b/osu.Game/Screens/Menu/MainMenu.cs
@@ -280,7 +280,7 @@ namespace osu.Game.Screens.Menu
sideFlashes.Delay(FADE_IN_DURATION).FadeIn(64, Easing.InQuint);
}
- else if (!api.IsLoggedIn)
+ else if (!api.IsLoggedIn || api.State.Value == APIState.RequiresSecondFactorAuth)
{
// copy out old action to avoid accidentally capturing logo.Action in closure, causing a self-reference loop.
var previousAction = logo.Action;
diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs
index e892f9280f..cb27d1ee61 100644
--- a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs
+++ b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs
@@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Development;
@@ -19,6 +20,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
{
public partial class RoomManager : Component, IRoomManager
{
+ [CanBeNull]
public event Action RoomsUpdated;
private readonly BindableList rooms = new BindableList();
diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs
index ac6403bb34..bff1a8c64c 100644
--- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs
+++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs
@@ -126,7 +126,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
case NotifyCollectionChangedAction.Remove:
Debug.Assert(args.OldItems != null);
- removeRooms(args.OldItems.Cast());
+ // clear operations have a separate path that benefits from async disposal,
+ // since disposing is quite expensive when performed on a high number of drawables synchronously.
+ if (args.OldItems.Count == roomFlow.Count)
+ clearRooms();
+ else
+ removeRooms(args.OldItems.Cast());
+
break;
}
}
@@ -151,6 +157,15 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
}
}
+ private void clearRooms()
+ {
+ roomFlow.Clear();
+
+ // selection may have a lease due to being in a sub screen.
+ if (!SelectedRoom.Disabled)
+ SelectedRoom.Value = null;
+ }
+
private void updateSorting()
{
foreach (var room in roomFlow)
diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs
index f35b205bc4..4c0219eff5 100644
--- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs
@@ -509,7 +509,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
private void cancelTrackLooping()
{
- var track = Beatmap?.Value?.Track;
+ var track = Beatmap.Value?.Track;
if (track != null)
track.Looping = false;
diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs
index 1cf3d25dad..a260156595 100644
--- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs
+++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs
@@ -109,7 +109,7 @@ namespace osu.Game.Screens.Play.HUD
protected override bool OnMouseMove(MouseMoveEvent e)
{
- positionalAdjust = Vector2.Distance(e.MousePosition, button.ToSpaceOfOtherDrawable(button.DrawRectangle.Centre, Parent)) / 100;
+ positionalAdjust = Vector2.Distance(e.MousePosition, button.ToSpaceOfOtherDrawable(button.DrawRectangle.Centre, Parent!)) / 100;
return base.OnMouseMove(e);
}
diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs
index 171ceea84f..c8e84f1961 100644
--- a/osu.Game/Screens/Play/SubmittingPlayer.cs
+++ b/osu.Game/Screens/Play/SubmittingPlayer.cs
@@ -132,7 +132,18 @@ namespace osu.Game.Screens.Play
if (string.IsNullOrEmpty(exception.Message))
Logger.Error(exception, "Failed to retrieve a score submission token.");
else
- Logger.Log($"You are not able to submit a score: {exception.Message}", level: LogLevel.Important);
+ {
+ switch (exception.Message)
+ {
+ case "expired token":
+ Logger.Log("Score submission failed because your system clock is set incorrectly. Please check your system time, date and timezone.", level: LogLevel.Important);
+ break;
+
+ default:
+ Logger.Log($"You are not able to submit a score: {exception.Message}", level: LogLevel.Important);
+ break;
+ }
+ }
Schedule(() =>
{
diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs
index 0aff98df2b..d209c305fa 100644
--- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs
+++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs
@@ -4,6 +4,7 @@
#nullable disable
using System;
+using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Audio;
@@ -259,10 +260,15 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
if (isFailedSDueToMisses)
AddInternal(failedSRankText = new RankText(ScoreRank.S));
+ var applauseSamples = new List { applauseSampleName };
+ if (score.Rank >= ScoreRank.B)
+ // when rank is B or higher, play legacy applause sample on legacy skins.
+ applauseSamples.Insert(0, @"applause");
+
AddRangeInternal(new Drawable[]
{
rankImpactSound = new PoolableSkinnableSample(new SampleInfo(impactSampleName)),
- rankApplauseSound = new PoolableSkinnableSample(new SampleInfo(@"applause", applauseSampleName)),
+ rankApplauseSound = new PoolableSkinnableSample(new SampleInfo(applauseSamples.ToArray())),
scoreTickSound = new PoolableSkinnableSample(new SampleInfo(@"Results/score-tick")),
badgeTickSound = new PoolableSkinnableSample(new SampleInfo(@"Results/badge-dink")),
badgeMaxSound = new PoolableSkinnableSample(new SampleInfo(@"Results/badge-dink-max")),
@@ -351,24 +357,28 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
int badgeNum = 0;
- foreach (var badge in badges)
+ if (score.Rank != ScoreRank.F)
{
- if (badge.Accuracy > score.Accuracy)
- continue;
-
- using (BeginDelayedSequence(inverseEasing(ACCURACY_TRANSFORM_EASING, Math.Min(accuracyX - virtual_ss_percentage, badge.Accuracy) / targetAccuracy) * ACCURACY_TRANSFORM_DURATION))
+ foreach (var badge in badges)
{
- badge.Appear();
+ if (badge.Accuracy > score.Accuracy)
+ continue;
- if (withFlair)
+ using (BeginDelayedSequence(
+ inverseEasing(ACCURACY_TRANSFORM_EASING, Math.Min(accuracyX - virtual_ss_percentage, badge.Accuracy) / targetAccuracy) * ACCURACY_TRANSFORM_DURATION))
{
- Schedule(() =>
- {
- var dink = badgeNum < badges.Count - 1 ? badgeTickSound : badgeMaxSound;
+ badge.Appear();
- dink.FrequencyTo(1 + badgeNum++ * 0.05);
- dink.Play();
- });
+ if (withFlair)
+ {
+ Schedule(() =>
+ {
+ var dink = badgeNum < badges.Count - 1 ? badgeTickSound : badgeMaxSound;
+
+ dink.FrequencyTo(1 + badgeNum++ * 0.05);
+ dink.Play();
+ });
+ }
}
}
}
diff --git a/osu.Game/Screens/Select/FooterButtonMods.cs b/osu.Game/Screens/Select/FooterButtonMods.cs
index 69782c25bb..5685910c0a 100644
--- a/osu.Game/Screens/Select/FooterButtonMods.cs
+++ b/osu.Game/Screens/Select/FooterButtonMods.cs
@@ -1,17 +1,17 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Screens.Play.HUD;
using osu.Game.Rulesets.Mods;
using System.Collections.Generic;
using System.Linq;
-using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Extensions.LocalisationExtensions;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Configuration;
using osu.Game.Graphics;
@@ -19,6 +19,7 @@ using osu.Game.Graphics.Sprites;
using osuTK;
using osuTK.Graphics;
using osu.Game.Input.Bindings;
+using osu.Game.Localisation;
using osu.Game.Utils;
namespace osu.Game.Screens.Select
@@ -31,26 +32,26 @@ namespace osu.Game.Screens.Select
set => modDisplay.Current = value;
}
- protected readonly OsuSpriteText MultiplierText;
+ protected OsuSpriteText MultiplierText { get; private set; } = null!;
+ protected Container UnrankedBadge { get; private set; } = null!;
+
private readonly ModDisplay modDisplay;
+
+ private ModSettingChangeTracker? modSettingChangeTracker;
+
private Color4 lowMultiplierColour;
private Color4 highMultiplierColour;
public FooterButtonMods()
{
- ButtonContentContainer.Add(modDisplay = new ModDisplay
+ // must be created in ctor for correct operation of `Current`.
+ modDisplay = new ModDisplay
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Scale = new Vector2(0.8f),
ExpansionMode = ExpansionMode.AlwaysContracted,
- });
- ButtonContentContainer.Add(MultiplierText = new OsuSpriteText
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Font = OsuFont.GetFont(weight: FontWeight.Bold),
- });
+ };
}
[BackgroundDependencyLoader]
@@ -62,10 +63,43 @@ namespace osu.Game.Screens.Select
highMultiplierColour = colours.Green;
Text = @"mods";
Hotkey = GlobalAction.ToggleModSelection;
- }
- [CanBeNull]
- private ModSettingChangeTracker modSettingChangeTracker;
+ ButtonContentContainer.AddRange(new Drawable[]
+ {
+ modDisplay,
+ MultiplierText = new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Font = OsuFont.GetFont(weight: FontWeight.Bold),
+ },
+ UnrankedBadge = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ AutoSizeAxes = Axes.Both,
+ Children = new Drawable[]
+ {
+ new Circle
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Colour = colours.Yellow,
+ RelativeSizeAxes = Axes.Both,
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Colour = colours.Gray2,
+ Padding = new MarginPadding(5),
+ UseFullGlyphHeight = false,
+ Text = ModSelectOverlayStrings.Unranked.ToLower()
+ }
+ }
+ },
+ });
+ }
protected override void LoadComplete()
{
@@ -101,6 +135,9 @@ namespace osu.Game.Screens.Select
modDisplay.FadeIn();
else
modDisplay.FadeOut();
+
+ bool anyUnrankedMods = Current.Value?.Any(m => !m.Ranked) == true;
+ UnrankedBadge.FadeTo(anyUnrankedMods ? 1 : 0);
});
}
}
diff --git a/osu.Game/Skinning/LegacyJudgementPieceOld.cs b/osu.Game/Skinning/LegacyJudgementPieceOld.cs
index 068707ba4f..c8630b54a6 100644
--- a/osu.Game/Skinning/LegacyJudgementPieceOld.cs
+++ b/osu.Game/Skinning/LegacyJudgementPieceOld.cs
@@ -62,7 +62,7 @@ namespace osu.Game.Skinning
this.ScaleTo(1.2f);
this.ScaleTo(1f, 100, Easing.In);
- this.FadeOutFromOne(400);
+ this.Delay(fade_out_delay / 2).FadeOut(fade_out_length);
}
else
{
diff --git a/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs
index 93c6e72aa2..80c69db8b1 100644
--- a/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs
+++ b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs
@@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
public TestMultiplayerClient MultiplayerClient => OnlinePlayDependencies.MultiplayerClient;
public new TestMultiplayerRoomManager RoomManager => OnlinePlayDependencies.RoomManager;
- public TestSpectatorClient SpectatorClient => OnlinePlayDependencies?.SpectatorClient;
+ public TestSpectatorClient SpectatorClient => OnlinePlayDependencies.SpectatorClient;
protected new MultiplayerTestSceneDependencies OnlinePlayDependencies => (MultiplayerTestSceneDependencies)base.OnlinePlayDependencies;
diff --git a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs
index 87488710a7..eebc3503bc 100644
--- a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs
+++ b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -22,23 +20,23 @@ namespace osu.Game.Tests.Visual.OnlinePlay
///
public abstract partial class OnlinePlayTestScene : ScreenTestScene, IOnlinePlayTestSceneDependencies
{
- public Bindable SelectedRoom => OnlinePlayDependencies?.SelectedRoom;
- public IRoomManager RoomManager => OnlinePlayDependencies?.RoomManager;
- public OngoingOperationTracker OngoingOperationTracker => OnlinePlayDependencies?.OngoingOperationTracker;
- public OnlinePlayBeatmapAvailabilityTracker AvailabilityTracker => OnlinePlayDependencies?.AvailabilityTracker;
- public TestUserLookupCache UserLookupCache => OnlinePlayDependencies?.UserLookupCache;
- public BeatmapLookupCache BeatmapLookupCache => OnlinePlayDependencies?.BeatmapLookupCache;
+ public Bindable SelectedRoom => OnlinePlayDependencies.SelectedRoom;
+ public IRoomManager RoomManager => OnlinePlayDependencies.RoomManager;
+ public OngoingOperationTracker OngoingOperationTracker => OnlinePlayDependencies.OngoingOperationTracker;
+ public OnlinePlayBeatmapAvailabilityTracker AvailabilityTracker => OnlinePlayDependencies.AvailabilityTracker;
+ public TestUserLookupCache UserLookupCache => OnlinePlayDependencies.UserLookupCache;
+ public BeatmapLookupCache BeatmapLookupCache => OnlinePlayDependencies.BeatmapLookupCache;
///
/// All dependencies required for online play components and screens.
///
- protected OnlinePlayTestSceneDependencies OnlinePlayDependencies => dependencies?.OnlinePlayDependencies;
+ protected OnlinePlayTestSceneDependencies OnlinePlayDependencies => dependencies.OnlinePlayDependencies!;
protected override Container Content => content;
private readonly Container content;
private readonly Container drawableDependenciesContainer;
- private DelegatedDependencyContainer dependencies;
+ private DelegatedDependencyContainer dependencies = null!;
protected OnlinePlayTestScene()
{
@@ -50,10 +48,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay
}
protected sealed override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
- {
- dependencies = new DelegatedDependencyContainer(base.CreateChildDependencies(parent));
- return dependencies;
- }
+ => dependencies = new DelegatedDependencyContainer(base.CreateChildDependencies(parent));
public override void SetUpSteps()
{
@@ -62,9 +57,9 @@ namespace osu.Game.Tests.Visual.OnlinePlay
AddStep("setup dependencies", () =>
{
// Reset the room dependencies to a fresh state.
- drawableDependenciesContainer.Clear();
dependencies.OnlinePlayDependencies = CreateOnlinePlayDependencies();
- drawableDependenciesContainer.AddRange(OnlinePlayDependencies.DrawableComponents);
+ drawableDependenciesContainer.Clear();
+ drawableDependenciesContainer.AddRange(dependencies.OnlinePlayDependencies.DrawableComponents);
var handler = OnlinePlayDependencies.RequestsHandler;
@@ -106,7 +101,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay
///
/// The online play dependencies.
///
- public OnlinePlayTestSceneDependencies OnlinePlayDependencies { get; set; }
+ public OnlinePlayTestSceneDependencies? OnlinePlayDependencies { get; set; }
private readonly IReadOnlyDependencyContainer parent;
private readonly DependencyContainer injectableDependencies;
diff --git a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs
index 975423d19b..64bd27b871 100644
--- a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs
+++ b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs
@@ -56,10 +56,10 @@ namespace osu.Game.Tests.Visual.OnlinePlay
CacheAs(BeatmapLookupCache);
}
- public object Get(Type type)
+ public object? Get(Type type)
=> dependencies.Get(type);
- public object Get(Type type, CacheInfo info)
+ public object? Get(Type type, CacheInfo info)
=> dependencies.Get(type, info);
public void Inject(T instance)
diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs
index f371cf721f..c9acfa0ee5 100644
--- a/osu.Game/Tests/Visual/SkinnableTestScene.cs
+++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs
@@ -171,10 +171,10 @@ namespace osu.Game.Tests.Visual
public IRenderer Renderer => host.Renderer;
public AudioManager AudioManager => Audio;
- public IResourceStore Files => null;
+ public IResourceStore Files => null!;
public new IResourceStore Resources => base.Resources;
public IResourceStore CreateTextureLoaderStore(IResourceStore underlyingStore) => host.CreateTextureLoaderStore(underlyingStore);
- RealmAccess IStorageResourceProvider.RealmAccess => null;
+ RealmAccess IStorageResourceProvider.RealmAccess => null!;
#endregion
diff --git a/osu.Game/Users/UserGridPanel.cs b/osu.Game/Users/UserGridPanel.cs
index fe3435c248..fce543415d 100644
--- a/osu.Game/Users/UserGridPanel.cs
+++ b/osu.Game/Users/UserGridPanel.cs
@@ -35,98 +35,84 @@ namespace osu.Game.Users
{
FillFlowContainer details;
- var layout = new Container
+ var layout = new GridContainer
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(margin),
- Child = new GridContainer
+ ColumnDimensions = new[]
{
- RelativeSizeAxes = Axes.Both,
- ColumnDimensions = new[]
+ new Dimension(GridSizeMode.AutoSize),
+ new Dimension()
+ },
+ RowDimensions = new[]
+ {
+ new Dimension(GridSizeMode.AutoSize),
+ new Dimension()
+ },
+ Content = new[]
+ {
+ new Drawable[]
{
- new Dimension(GridSizeMode.AutoSize),
- new Dimension()
- },
- RowDimensions = new[]
- {
- new Dimension(GridSizeMode.AutoSize),
- new Dimension(GridSizeMode.Absolute, margin),
- new Dimension()
- },
- Content = new[]
- {
- new Drawable[]
+ CreateAvatar().With(avatar =>
{
- CreateAvatar().With(avatar =>
+ avatar.Size = new Vector2(60);
+ avatar.Masking = true;
+ avatar.CornerRadius = 6;
+ avatar.Margin = new MarginPadding { Bottom = margin };
+ }),
+ new GridContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding { Left = margin, Bottom = margin },
+ ColumnDimensions = new[]
{
- avatar.Size = new Vector2(60);
- avatar.Masking = true;
- avatar.CornerRadius = 6;
- }),
- new Container
+ new Dimension()
+ },
+ RowDimensions = new[]
{
- RelativeSizeAxes = Axes.Both,
- Padding = new MarginPadding { Left = margin },
- Child = new GridContainer
+ new Dimension(GridSizeMode.AutoSize),
+ new Dimension()
+ },
+ Content = new[]
+ {
+ new Drawable[]
{
- RelativeSizeAxes = Axes.Both,
- ColumnDimensions = new[]
+ details = new FillFlowContainer
{
- new Dimension()
- },
- RowDimensions = new[]
- {
- new Dimension(GridSizeMode.AutoSize),
- new Dimension()
- },
- Content = new[]
- {
- new Drawable[]
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(6),
+ Children = new Drawable[]
{
- details = new FillFlowContainer
- {
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Horizontal,
- Spacing = new Vector2(6),
- Children = new Drawable[]
- {
- CreateFlag(),
- // supporter icon is being added later
- }
- }
- },
- new Drawable[]
- {
- CreateUsername().With(username =>
- {
- username.Anchor = Anchor.CentreLeft;
- username.Origin = Anchor.CentreLeft;
- })
+ CreateFlag(),
+ // supporter icon is being added later
}
}
+ },
+ new Drawable[]
+ {
+ CreateUsername().With(username =>
+ {
+ username.Anchor = Anchor.CentreLeft;
+ username.Origin = Anchor.CentreLeft;
+ })
}
}
- },
- new[]
- {
- // padding
- Empty(),
- Empty()
- },
- new Drawable[]
- {
- CreateStatusIcon().With(icon =>
- {
- icon.Anchor = Anchor.Centre;
- icon.Origin = Anchor.Centre;
- }),
- CreateStatusMessage(false).With(message =>
- {
- message.Anchor = Anchor.CentreLeft;
- message.Origin = Anchor.CentreLeft;
- message.Margin = new MarginPadding { Left = margin };
- })
}
+ },
+ new Drawable[]
+ {
+ CreateStatusIcon().With(icon =>
+ {
+ icon.Anchor = Anchor.Centre;
+ icon.Origin = Anchor.Centre;
+ }),
+ CreateStatusMessage(false).With(message =>
+ {
+ message.Anchor = Anchor.CentreLeft;
+ message.Origin = Anchor.CentreLeft;
+ message.Margin = new MarginPadding { Left = margin };
+ })
}
}
};
diff --git a/osu.Game/Users/UserRankPanel.cs b/osu.Game/Users/UserRankPanel.cs
index a38962dfc7..84ff3114fc 100644
--- a/osu.Game/Users/UserRankPanel.cs
+++ b/osu.Game/Users/UserRankPanel.cs
@@ -81,117 +81,95 @@ namespace osu.Game.Users
},
new GridContainer
{
- AutoSizeAxes = Axes.Y,
- RelativeSizeAxes = Axes.X,
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding(padding),
ColumnDimensions = new[]
{
- new Dimension(GridSizeMode.Absolute, padding),
new Dimension(GridSizeMode.AutoSize),
new Dimension(),
- new Dimension(GridSizeMode.Absolute, padding),
},
RowDimensions = new[]
{
- new Dimension(GridSizeMode.Absolute, padding),
- new Dimension(GridSizeMode.AutoSize),
+ new Dimension()
},
Content = new[]
{
- new[]
+ new Drawable[]
{
- // padding
- Empty(),
- Empty(),
- Empty(),
- Empty()
- },
- new[]
- {
- Empty(), // padding
CreateAvatar().With(avatar =>
{
avatar.Size = new Vector2(60);
avatar.Masking = true;
avatar.CornerRadius = 6;
}),
- new Container
+ new GridContainer
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = padding },
- Child = new GridContainer
+ ColumnDimensions = new[]
{
- RelativeSizeAxes = Axes.Both,
- ColumnDimensions = new[]
+ new Dimension()
+ },
+ RowDimensions = new[]
+ {
+ new Dimension(GridSizeMode.AutoSize),
+ new Dimension()
+ },
+ Content = new[]
+ {
+ new Drawable[]
{
- new Dimension()
- },
- RowDimensions = new[]
- {
- new Dimension(GridSizeMode.AutoSize),
- new Dimension()
- },
- Content = new[]
- {
- new Drawable[]
+ details = new FillFlowContainer
{
- details = new FillFlowContainer
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(6),
+ Children = new Drawable[]
{
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Horizontal,
- Spacing = new Vector2(6),
- Children = new Drawable[]
- {
- CreateFlag(),
- // supporter icon is being added later
- }
+ CreateFlag(),
+ // supporter icon is being added later
}
- },
- new Drawable[]
- {
- CreateUsername().With(username =>
- {
- username.Anchor = Anchor.CentreLeft;
- username.Origin = Anchor.CentreLeft;
- })
}
+ },
+ new Drawable[]
+ {
+ CreateUsername().With(username =>
+ {
+ username.Anchor = Anchor.CentreLeft;
+ username.Origin = Anchor.CentreLeft;
+ })
}
}
- },
- Empty() // padding
+ }
}
}
}
}
},
- new Container
+ new GridContainer
{
Name = "Bottom content",
Margin = new MarginPadding { Top = main_content_height },
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Left = 80, Vertical = padding },
- Child = new GridContainer
+ ColumnDimensions = new[]
{
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- ColumnDimensions = new[]
+ new Dimension(),
+ new Dimension()
+ },
+ RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
+ Content = new[]
+ {
+ new Drawable[]
{
- new Dimension(),
- new Dimension()
- },
- RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
- Content = new[]
- {
- new Drawable[]
+ globalRankDisplay = new ProfileValueDisplay(true)
{
- globalRankDisplay = new ProfileValueDisplay(true)
- {
- Title = UsersStrings.ShowRankGlobalSimple,
- },
- countryRankDisplay = new ProfileValueDisplay(true)
- {
- Title = UsersStrings.ShowRankCountrySimple,
- }
+ Title = UsersStrings.ShowRankGlobalSimple,
+ },
+ countryRankDisplay = new ProfileValueDisplay(true)
+ {
+ Title = UsersStrings.ShowRankCountrySimple,
}
}
}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 2d261c851f..935b759e4d 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -1,6 +1,6 @@
- net6.0
+ net8.0
Library
true
10
@@ -36,7 +36,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 5b99319499..a4cd26a372 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -23,6 +23,6 @@
iossimulator-x64
-
+
diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj
index 2d61b73125..19c0c610b5 100644
--- a/osu.iOS/osu.iOS.csproj
+++ b/osu.iOS/osu.iOS.csproj
@@ -1,9 +1,8 @@
- net6.0-ios
+ net8.0-ios
13.4
Exe
- true
0.1.0
$(Version)
$(Version)
@@ -16,4 +15,7 @@
+
+
+
diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings
index c8c5d6745c..ef557cbbfc 100644
--- a/osu.sln.DotSettings
+++ b/osu.sln.DotSettings
@@ -66,6 +66,7 @@
HINT
WARNING
DO_NOT_SHOW
+ HINT
WARNING
WARNING
WARNING
@@ -81,6 +82,7 @@
WARNING
WARNING
HINT
+ HINT
WARNING
HINT
DO_NOT_SHOW
@@ -165,6 +167,7 @@
WARNING
WARNING
WARNING
+ HINT
WARNING
WARNING
WARNING
@@ -251,6 +254,7 @@
HINT
DO_NOT_SHOW
WARNING
+ HINT
WARNING
WARNING
WARNING
@@ -263,6 +267,7 @@
WARNING
WARNING
WARNING
+ HINT
WARNING
HINT
HINT
@@ -1036,4 +1041,5 @@ private void load()
True
True
True
+ True
True