1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-15 18:37:52 +08:00

Merge branch 'master' into no-combo-scaling

This commit is contained in:
apollo 2022-03-03 14:55:41 +00:00 committed by GitHub
commit 580e43b5ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
289 changed files with 6464 additions and 2365 deletions

View File

@ -20,10 +20,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Install .NET 5.0.x
- name: Install .NET 6.0.x
uses: actions/setup-dotnet@v1
with:
dotnet-version: "5.0.x"
dotnet-version: "6.0.x"
# FIXME: libavformat is not included in Ubuntu. Let's fix that.
# https://github.com/ppy/osu-framework/issues/4349
@ -65,10 +65,10 @@ jobs:
run: |
$VM_ASSETS/select-xamarin-sdk-v2.sh --mono=6.12 --android=11.2
- name: Install .NET 5.0.x
- name: Install .NET 6.0.x
uses: actions/setup-dotnet@v1
with:
dotnet-version: "5.0.x"
dotnet-version: "6.0.x"
# Contrary to seemingly any other msbuild, msbuild running on macOS/Mono
# cannot accept .sln(f) files as arguments.
@ -84,10 +84,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Install .NET 5.0.x
- name: Install .NET 6.0.x
uses: actions/setup-dotnet@v1
with:
dotnet-version: "5.0.x"
dotnet-version: "6.0.x"
# Contrary to seemingly any other msbuild, msbuild running on macOS/Mono
# cannot accept .sln(f) files as arguments.
@ -102,17 +102,17 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
# FIXME: Tools won't run in .NET 5.0 unless you install 3.1.x LTS side by side.
# 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
uses: actions/setup-dotnet@v1
with:
dotnet-version: "3.1.x"
- name: Install .NET 5.0.x
- name: Install .NET 6.0.x
uses: actions/setup-dotnet@v1
with:
dotnet-version: "5.0.x"
dotnet-version: "6.0.x"
- name: Restore Tools
run: dotnet tool restore

View File

@ -1,8 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Benchmarks" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Benchmarks/bin/Debug/net5.0/osu.Game.Benchmarks.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Benchmarks/bin/Debug/net6.0/osu.Game.Benchmarks.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Benchmarks/bin/Debug/net5.0" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Benchmarks/bin/Debug/net6.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
@ -12,7 +12,7 @@
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net5.0" />
<option name="PROJECT_TFM" value="net6.0" />
<method v="2">
<option name="Build" />
</method>

View File

@ -1,8 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="CatchRuleset (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Ruleset" activateToolWindowBeforeRun="false">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/net5.0/osu.Game.Rulesets.Catch.Tests.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/net6.0/osu.Game.Rulesets.Catch.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/net5.0" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/net6.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
@ -12,7 +12,7 @@
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net5.0" />
<option name="PROJECT_TFM" value="net6.0" />
<browser url="http://localhost:5000" />
<method v="2">
<option name="Build" />

View File

@ -1,8 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="ManiaRuleset (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Ruleset" activateToolWindowBeforeRun="false">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/net5.0/osu.Game.Rulesets.Mania.Tests.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/net6.0/osu.Game.Rulesets.Mania.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/net5.0" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/net6.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
@ -12,7 +12,7 @@
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net5.0" />
<option name="PROJECT_TFM" value="net6.0" />
<browser url="http://localhost:5000" />
<method v="2">
<option name="Build" />

View File

@ -1,8 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="OsuRuleset (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Ruleset" activateToolWindowBeforeRun="false">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/net5.0/osu.Game.Rulesets.Osu.Tests.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/net6.0/osu.Game.Rulesets.Osu.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/net5.0" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/net6.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
@ -12,7 +12,7 @@
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net5.0" />
<option name="PROJECT_TFM" value="net6.0" />
<browser url="http://localhost:5000" />
<method v="2">
<option name="Build" />

View File

@ -1,8 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="TaikoRuleset (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Ruleset" activateToolWindowBeforeRun="false">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/net5.0/osu.Game.Rulesets.Taiko.Tests.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/net6.0/osu.Game.Rulesets.Taiko.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/net5.0" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/net6.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
@ -12,7 +12,7 @@
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net5.0" />
<option name="PROJECT_TFM" value="net6.0" />
<browser url="http://localhost:5000" />
<method v="2">
<option name="Build" />

View File

@ -1,8 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Tournament" type="DotNetProject" factoryName=".NET Project" folderName="Tournament" activateToolWindowBeforeRun="false">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0/osu!.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net6.0/osu!.dll" />
<option name="PROGRAM_PARAMETERS" value="--tournament" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net6.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
@ -12,7 +12,7 @@
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net5.0" />
<option name="PROJECT_TFM" value="net6.0" />
<method v="2">
<option name="Build" />
</method>

View File

@ -1,8 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Tournament (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Tournament" activateToolWindowBeforeRun="false">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tournament.Tests/bin/Debug/net5.0/osu.Game.Tournament.Tests.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tournament.Tests/bin/Debug/net6.0/osu.Game.Tournament.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tournament.Tests/bin/Debug/net5.0" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tournament.Tests/bin/Debug/net6.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
@ -12,7 +12,7 @@
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net5.0" />
<option name="PROJECT_TFM" value="net6.0" />
<browser url="http://localhost:5000" />
<method v="2">
<option name="Build" />

View File

@ -1,8 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="osu!" type="DotNetProject" factoryName=".NET Project" folderName="osu!" activateToolWindowBeforeRun="false">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0/osu!.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net6.0/osu!.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net6.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
@ -12,7 +12,7 @@
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net5.0" />
<option name="PROJECT_TFM" value="net6.0" />
<method v="2">
<option name="Build" />
</method>

View File

@ -1,8 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="osu! (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="osu!" activateToolWindowBeforeRun="false">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/net5.0/osu.Game.Tests.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/net6.0/osu.Game.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/net5.0" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/net6.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
@ -12,7 +12,7 @@
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net5.0" />
<option name="PROJECT_TFM" value="net6.0" />
<method v="2">
<option name="Build" />
</method>

View File

@ -1,8 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="osu! (Second Client)" type="DotNetProject" factoryName=".NET Project" folderName="osu!" activateToolWindowBeforeRun="false">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0/osu!.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net6.0/osu!.dll" />
<option name="PROGRAM_PARAMETERS" value="--debug-client-id=1" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net6.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
@ -12,9 +12,9 @@
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net5.0" />
<option name="PROJECT_TFM" value="net6.0" />
<method v="2">
<option name="Build" />
</method>
</configuration>
</component>
</component>

18
.vscode/launch.json vendored
View File

@ -7,7 +7,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Debug/net5.0/osu!.dll"
"${workspaceRoot}/osu.Desktop/bin/Debug/net6.0/osu!.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Debug)",
@ -19,7 +19,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Release/net5.0/osu!.dll"
"${workspaceRoot}/osu.Desktop/bin/Release/net6.0/osu!.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Release)",
@ -31,7 +31,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Game.Tests/bin/Debug/net5.0/osu.Game.Tests.dll"
"${workspaceRoot}/osu.Game.Tests/bin/Debug/net6.0/osu.Game.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build tests (Debug)",
@ -43,7 +43,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Game.Tests/bin/Release/net5.0/osu.Game.Tests.dll"
"${workspaceRoot}/osu.Game.Tests/bin/Release/net6.0/osu.Game.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build tests (Release)",
@ -55,7 +55,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Debug/net5.0/osu!.dll",
"${workspaceRoot}/osu.Desktop/bin/Debug/net6.0/osu!.dll",
"--tournament"
],
"cwd": "${workspaceRoot}",
@ -68,7 +68,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Release/net5.0/osu!.dll",
"${workspaceRoot}/osu.Desktop/bin/Release/net6.0/osu!.dll",
"--tournament"
],
"cwd": "${workspaceRoot}",
@ -81,7 +81,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/net5.0/osu.Game.Tournament.Tests.dll",
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/net6.0/osu.Game.Tournament.Tests.dll",
"--tournament"
],
"cwd": "${workspaceRoot}",
@ -94,7 +94,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/net5.0/osu.Game.Tournament.Tests.dll",
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/net6.0/osu.Game.Tournament.Tests.dll",
"--tournament"
],
"cwd": "${workspaceRoot}",
@ -105,7 +105,7 @@
"name": "Benchmark",
"type": "coreclr",
"request": "launch",
"program": "${workspaceRoot}/osu.Game.Benchmarks/bin/Release/net5.0/osu.Game.Benchmarks.dll",
"program": "${workspaceRoot}/osu.Game.Benchmarks/bin/Release/net6.0/osu.Game.Benchmarks.dll",
"args": [
"--filter",
"*"

View File

@ -18,7 +18,6 @@
<ItemGroup Label="Code Analysis">
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.3" PrivateAssets="All" />
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\BannedSymbols.txt" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3" PrivateAssets="All" />
</ItemGroup>
<PropertyGroup Label="Code Analysis">
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)CodeAnalysis\osu.ruleset</CodeAnalysisRuleSet>
@ -32,13 +31,8 @@
NU1701:
DeepEqual is not netstandard-compatible. This is fine since we run tests with .NET Framework anyway.
This is required due to https://github.com/NuGet/Home/issues/5740
CA9998:
Microsoft.CodeAnalysis.FxCopAnalyzers has been deprecated.
The entire package will be able to be removed after migrating to .NET 5,
as analysers are shipped as part of the .NET 5 SDK anyway.
-->
<NoWarn>$(NoWarn);NU1701;CA9998</NoWarn>
<NoWarn>$(NoWarn);NU1701</NoWarn>
</PropertyGroup>
<PropertyGroup Label="Nuget">
<IsPackable>false</IsPackable>

View File

@ -48,7 +48,7 @@ You can see some examples of custom rulesets by visiting the [custom ruleset dir
Please make sure you have the following prerequisites:
- A desktop platform with the [.NET 5.0 SDK](https://dotnet.microsoft.com/download) installed.
- A desktop platform with the [.NET 6.0 SDK](https://dotnet.microsoft.com/download) installed.
- When developing with mobile, [Xamarin](https://docs.microsoft.com/en-us/xamarin/) is required, which is shipped together with Visual Studio or [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/).
- When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as [Visual Studio 2019+](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
- When running on Linux, please have a system-wide FFmpeg installation available to support video decoding.

View File

@ -7,7 +7,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Debug/net5.0/osu.Game.Rulesets.EmptyFreeformRuleset.Tests.dll"
"${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.EmptyFreeformRuleset.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug)",
@ -20,7 +20,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Release/net5.0/osu.Game.Rulesets.EmptyFreeformRuleset.Tests.dll"
"${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.EmptyFreeformRuleset.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)",

View File

@ -20,7 +20,7 @@
</ItemGroup>
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>osu.Game.Rulesets.EmptyFreeform.Tests</RootNamespace>
</PropertyGroup>
</Project>
</Project>

View File

@ -7,7 +7,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Debug/net5.0/osu.Game.Rulesets.Pippidon.Tests.dll"
"${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.Pippidon.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug)",
@ -20,7 +20,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Release/net5.0/osu.Game.Rulesets.Pippidon.Tests.dll"
"${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.Pippidon.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)",

View File

@ -20,7 +20,7 @@
</ItemGroup>
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>osu.Game.Rulesets.Pippidon.Tests</RootNamespace>
</PropertyGroup>
</Project>
</Project>

View File

@ -7,7 +7,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Debug/net5.0/osu.Game.Rulesets.EmptyScrolling.Tests.dll"
"${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.EmptyScrolling.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug)",
@ -20,7 +20,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Release/net5.0/osu.Game.Rulesets.EmptyScrolling.Tests.dll"
"${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.EmptyScrolling.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)",

View File

@ -20,7 +20,7 @@
</ItemGroup>
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>osu.Game.Rulesets.EmptyScrolling.Tests</RootNamespace>
</PropertyGroup>
</Project>
</Project>

View File

@ -7,7 +7,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Debug/net5.0/osu.Game.Rulesets.Pippidon.Tests.dll"
"${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.Pippidon.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug)",
@ -20,7 +20,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Release/net5.0/osu.Game.Rulesets.Pippidon.Tests.dll"
"${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.Pippidon.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)",

View File

@ -20,7 +20,7 @@
</ItemGroup>
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>osu.Game.Rulesets.Pippidon.Tests</RootNamespace>
</PropertyGroup>
</Project>
</Project>

View File

@ -51,11 +51,11 @@
<Reference Include="Java.Interop" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.210.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.204.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.211.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.223.0" />
</ItemGroup>
<ItemGroup Label="Transitive Dependencies">
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
<PackageReference Include="Realm" Version="10.8.0" />
<PackageReference Include="Realm" Version="10.9.0" />
</ItemGroup>
</Project>

View File

@ -77,10 +77,9 @@ namespace osu.Desktop.LegacyIpc
case LegacyIpcDifficultyCalculationRequest req:
try
{
var ruleset = getLegacyRulesetFromID(req.RulesetId);
WorkingBeatmap beatmap = new FlatFileWorkingBeatmap(req.BeatmapFile);
var ruleset = beatmap.BeatmapInfo.Ruleset.CreateInstance();
Mod[] mods = ruleset.ConvertFromLegacyMods((LegacyMods)req.Mods).ToArray();
WorkingBeatmap beatmap = new FlatFileWorkingBeatmap(req.BeatmapFile, _ => ruleset);
return new LegacyIpcDifficultyCalculationResponse
{

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup Label="Project">
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<OutputType>WinExe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>A free-to-win rhythm game. Rhythm is just a *click* away!</Description>
@ -26,10 +26,13 @@
<ItemGroup Label="Package References">
<PackageReference Include="Microsoft.NETCore.Targets" Version="5.0.0" />
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="System.IO.Packaging" Version="5.0.0" />
<PackageReference Include="System.IO.Packaging" Version="6.0.0" />
<PackageReference Include="ppy.squirrel.windows" Version="1.9.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.14" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.14">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="DiscordRichPresence" Version="1.0.175" />
</ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<OutputType>Exe</OutputType>
<IsPackable>false</IsPackable>
</PropertyGroup>

View File

@ -7,7 +7,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Debug/net5.0/osu.Game.Rulesets.Catch.Tests.dll"
"${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.Catch.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug)",
@ -20,7 +20,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Release/net5.0/osu.Game.Rulesets.Catch.Tests.dll"
"${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.Catch.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)",

View File

@ -9,9 +9,9 @@
</ItemGroup>
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@ -9,6 +9,12 @@ namespace osu.Game.Rulesets.Catch.Difficulty
{
public class CatchDifficultyAttributes : DifficultyAttributes
{
/// <summary>
/// The perceived approach rate inclusive of rate-adjusting mods (DT/HT/etc).
/// </summary>
/// <remarks>
/// Rate-adjusting mods don't directly affect the approach rate difficulty value, but have a perceived effect as a result of adjusting audio timing.
/// </remarks>
[JsonProperty("approach_rate")]
public double ApproachRate { get; set; }

View File

@ -7,7 +7,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Debug/net5.0/osu.Game.Rulesets.Mania.Tests.dll"
"${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.Mania.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug)",
@ -20,7 +20,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Release/net5.0/osu.Game.Rulesets.Mania.Tests.dll"
"${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.Mania.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)",

View File

@ -9,9 +9,9 @@
</ItemGroup>
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@ -9,9 +9,18 @@ namespace osu.Game.Rulesets.Mania.Difficulty
{
public class ManiaDifficultyAttributes : DifficultyAttributes
{
/// <summary>
/// The hit window for a GREAT hit inclusive of rate-adjusting mods (DT/HT/etc).
/// </summary>
/// <remarks>
/// Rate-adjusting mods do not affect the hit window at all in osu-stable.
/// </remarks>
[JsonProperty("great_hit_window")]
public double GreatHitWindow { get; set; }
/// <summary>
/// The score multiplier applied via score-reducing mods.
/// </summary>
[JsonProperty("score_multiplier")]
public double ScoreMultiplier { get; set; }

View File

@ -48,7 +48,9 @@ namespace osu.Game.Rulesets.Mania.Difficulty
{
StarRating = skills[0].DifficultyValue() * star_scaling_factor,
Mods = mods,
GreatHitWindow = Math.Ceiling(getHitWindow300(mods) / clockRate),
// In osu-stable mania, rate-adjustment mods don't affect the hit window.
// This is done the way it is to introduce fractional differences in order to match osu-stable for the time being.
GreatHitWindow = Math.Ceiling((int)(getHitWindow300(mods) * clockRate) / clockRate),
ScoreMultiplier = getScoreMultiplier(mods),
MaxCombo = beatmap.HitObjects.Sum(h => h is HoldNote ? 2 : 1),
};
@ -108,7 +110,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
}
}
private int getHitWindow300(Mod[] mods)
private double getHitWindow300(Mod[] mods)
{
if (isForCurrentRuleset)
{
@ -121,19 +123,14 @@ namespace osu.Game.Rulesets.Mania.Difficulty
return applyModAdjustments(47, mods);
static int applyModAdjustments(double value, Mod[] mods)
static double applyModAdjustments(double value, Mod[] mods)
{
if (mods.Any(m => m is ManiaModHardRock))
value /= 1.4;
else if (mods.Any(m => m is ManiaModEasy))
value *= 1.4;
if (mods.Any(m => m is ManiaModDoubleTime))
value *= 1.5;
else if (mods.Any(m => m is ManiaModHalfTime))
value *= 0.75;
return (int)value;
return value;
}
}

View File

@ -43,14 +43,11 @@ namespace osu.Game.Rulesets.Mania.Difficulty
countMeh = Score.Statistics.GetValueOrDefault(HitResult.Meh);
countMiss = Score.Statistics.GetValueOrDefault(HitResult.Miss);
IEnumerable<Mod> scoreIncreaseMods = Ruleset.GetModsFor(ModType.DifficultyIncrease);
double scoreMultiplier = 1.0;
foreach (var m in mods.Where(m => !scoreIncreaseMods.Contains(m)))
scoreMultiplier *= m.ScoreMultiplier;
// Scale score up, so it's comparable to other keymods
scaledScore *= 1.0 / scoreMultiplier;
if (Attributes.ScoreMultiplier > 0)
{
// Scale score up, so it's comparable to other keymods
scaledScore *= 1.0 / Attributes.ScoreMultiplier;
}
// Arbitrary initial value for scaling pp in order to standardize distributions across game modes.
// The specific number has no intrinsic meaning and can be adjusted as needed.

View File

@ -394,6 +394,7 @@ namespace osu.Game.Rulesets.Mania
{
new StatisticItem(string.Empty, () => new SimpleStatisticTable(3, new SimpleStatisticItem[]
{
new AverageHitError(score.HitEvents),
new UnstableRate(score.HitEvents)
}), true)
}

View File

@ -98,8 +98,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
float rightLineWidth = skin.GetManiaSkinConfig<float>(LegacyManiaSkinConfigurationLookups.RightLineWidth, columnIndex)?.Value ?? 1;
bool hasLeftLine = leftLineWidth > 0;
bool hasRightLine = rightLineWidth > 0 && skin.GetConfig<SkinConfiguration.LegacySetting, decimal>(SkinConfiguration.LegacySetting.Version)?.Value >= 2.4m
|| isLastColumn;
bool hasRightLine = (rightLineWidth > 0 && skin.GetConfig<SkinConfiguration.LegacySetting, decimal>(SkinConfiguration.LegacySetting.Version)?.Value >= 2.4m) || isLastColumn;
Color4 lineColour = skin.GetManiaSkinConfig<Color4>(LegacyManiaSkinConfigurationLookups.ColumnLineColour, columnIndex)?.Value ?? Color4.White;
Color4 backgroundColour = skin.GetManiaSkinConfig<Color4>(LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour, columnIndex)?.Value ?? Color4.Black;

View File

@ -7,7 +7,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Debug/net5.0/osu.Game.Rulesets.Osu.Tests.dll"
"${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.Osu.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug)",
@ -20,7 +20,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Release/net5.0/osu.Game.Rulesets.Osu.Tests.dll"
"${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.Osu.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)",

View File

@ -7,6 +7,7 @@ using osu.Framework.Utils;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Compose.Components;
using osuTK;
using osuTK.Input;
@ -72,7 +73,11 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
EditorClock.Seek(slider.StartTime);
EditorBeatmap.SelectedHitObjects.Add(slider);
});
AddStep("change beat divisor", () => beatDivisor.Value = 3);
AddStep("change beat divisor", () =>
{
beatDivisor.ValidDivisors.Value = BeatDivisorPresetCollection.TRIPLETS;
beatDivisor.Value = 3;
});
convertToStream();

View File

@ -8,12 +8,15 @@ using NUnit.Framework;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Skinning.Default;
using osu.Game.Rulesets.Scoring;
using osuTK;
namespace osu.Game.Rulesets.Osu.Tests.Mods
@ -23,13 +26,37 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
protected override bool AllowFail => true;
[Test]
public void TestSpinnerAutoCompleted() => CreateModTest(new ModTestData
public void TestSpinnerAutoCompleted()
{
Mod = new OsuModSpunOut(),
Autoplay = false,
Beatmap = singleSpinnerBeatmap,
PassCondition = () => Player.ChildrenOfType<DrawableSpinner>().SingleOrDefault()?.Progress >= 1
});
DrawableSpinner spinner = null;
JudgementResult lastResult = null;
CreateModTest(new ModTestData
{
Mod = new OsuModSpunOut(),
Autoplay = false,
Beatmap = singleSpinnerBeatmap,
PassCondition = () =>
{
// Bind to the first spinner's results for further tracking.
if (spinner == null)
{
// We only care about the first spinner we encounter for this test.
var nextSpinner = Player.ChildrenOfType<DrawableSpinner>().SingleOrDefault();
if (nextSpinner == null)
return false;
lastResult = null;
spinner = nextSpinner;
spinner.OnNewResult += (o, result) => lastResult = result;
}
return lastResult?.Type == HitResult.Great;
}
});
}
[TestCase(null)]
[TestCase(typeof(OsuModDoubleTime))]
@ -48,7 +75,57 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
PassCondition = () =>
{
var counter = Player.ChildrenOfType<SpinnerSpmCalculator>().SingleOrDefault();
return counter != null && Precision.AlmostEquals(counter.Result.Value, 286, 1);
var spinner = Player.ChildrenOfType<DrawableSpinner>().FirstOrDefault();
if (counter == null || spinner == null)
return false;
// ignore cases where the spinner hasn't started as these lead to false-positives
if (Precision.AlmostEquals(counter.Result.Value, 0, 1))
return false;
float rotationSpeed = (float)(1.01 * spinner.HitObject.SpinsRequired / spinner.HitObject.Duration);
return Precision.AlmostEquals(counter.Result.Value, rotationSpeed * 1000 * 60, 1);
}
});
}
[Test]
public void TestSpinnerGetsNoBonusScore()
{
DrawableSpinner spinner = null;
List<JudgementResult> results = new List<JudgementResult>();
CreateModTest(new ModTestData
{
Mod = new OsuModSpunOut(),
Autoplay = false,
Beatmap = singleSpinnerBeatmap,
PassCondition = () =>
{
// Bind to the first spinner's results for further tracking.
if (spinner == null)
{
// We only care about the first spinner we encounter for this test.
var nextSpinner = Player.ChildrenOfType<DrawableSpinner>().SingleOrDefault();
if (nextSpinner == null)
return false;
spinner = nextSpinner;
spinner.OnNewResult += (o, result) => results.Add(result);
results.Clear();
}
// we should only be checking the bonus/progress after the spinner has fully completed.
if (results.OfType<OsuSpinnerJudgementResult>().All(r => r.TimeCompleted == null))
return false;
return
results.Any(r => r.Type == HitResult.SmallBonus)
&& results.All(r => r.Type != HitResult.LargeBonus);
}
});
}

View File

@ -10,9 +10,9 @@
</ItemGroup>
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@ -12,15 +12,29 @@ namespace osu.Game.Rulesets.Osu.Difficulty
{
public class OsuDifficultyAttributes : DifficultyAttributes
{
/// <summary>
/// The difficulty corresponding to the aim skill.
/// </summary>
[JsonProperty("aim_difficulty")]
public double AimDifficulty { get; set; }
/// <summary>
/// The difficulty corresponding to the speed skill.
/// </summary>
[JsonProperty("speed_difficulty")]
public double SpeedDifficulty { get; set; }
/// <summary>
/// The difficulty corresponding to the flashlight skill.
/// </summary>
[JsonProperty("flashlight_difficulty")]
public double FlashlightDifficulty { get; set; }
/// <summary>
/// Describes how much of <see cref="AimDifficulty"/> is contributed to by hitcircles or sliders.
/// A value closer to 1.0 indicates most of <see cref="AimDifficulty"/> is contributed by hitcircles.
/// A value closer to 0.0 indicates most of <see cref="AimDifficulty"/> is contributed by sliders.
/// </summary>
[JsonProperty("slider_factor")]
public double SliderFactor { get; set; }
@ -30,18 +44,42 @@ namespace osu.Game.Rulesets.Osu.Difficulty
[JsonProperty("speed_difficult_strain_count")]
public double SpeedDifficultStrainCount { get; set; }
/// <summary>
/// The perceived approach rate inclusive of rate-adjusting mods (DT/HT/etc).
/// </summary>
/// <remarks>
/// Rate-adjusting mods don't directly affect the approach rate difficulty value, but have a perceived effect as a result of adjusting audio timing.
/// </remarks>
[JsonProperty("approach_rate")]
public double ApproachRate { get; set; }
/// <summary>
/// The perceived overall difficulty inclusive of rate-adjusting mods (DT/HT/etc).
/// </summary>
/// <remarks>
/// Rate-adjusting mods don't directly affect the overall difficulty value, but have a perceived effect as a result of adjusting audio timing.
/// </remarks>
[JsonProperty("overall_difficulty")]
public double OverallDifficulty { get; set; }
/// <summary>
/// The beatmap's drain rate. This doesn't scale with rate-adjusting mods.
/// </summary>
public double DrainRate { get; set; }
/// <summary>
/// The number of hitcircles in the beatmap.
/// </summary>
public int HitCircleCount { get; set; }
/// <summary>
/// The number of sliders in the beatmap.
/// </summary>
public int SliderCount { get; set; }
/// <summary>
/// The number of spinners in the beatmap.
/// </summary>
public int SpinnerCount { get; set; }
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()

View File

@ -87,8 +87,8 @@ namespace osu.Game.Rulesets.Osu.Mods
requiresHold |= slider.Ball.IsHovered || h.IsHovered;
break;
case DrawableSpinner _:
requiresHold = true;
case DrawableSpinner spinner:
requiresHold |= spinner.HitObject.SpinsRequired > 0;
break;
}
}

View File

@ -45,7 +45,11 @@ namespace osu.Game.Rulesets.Osu.Mods
// for that reason using ElapsedFrameTime directly leads to fewer SPM with Half Time and more SPM with Double Time.
// for spinners we want the real (wall clock) elapsed time; to achieve that, unapply the clock rate locally here.
double rateIndependentElapsedTime = spinner.Clock.ElapsedFrameTime / spinner.Clock.Rate;
spinner.RotationTracker.AddRotation(MathUtils.RadiansToDegrees((float)rateIndependentElapsedTime * 0.03f));
// multiply the SPM by 1.01 to ensure that the spinner is completed. if the calculation is left exact,
// some spinners may not complete due to very minor decimal loss during calculation
float rotationSpeed = (float)(1.01 * spinner.HitObject.SpinsRequired / spinner.HitObject.Duration);
spinner.RotationTracker.AddRotation(MathUtils.RadiansToDegrees((float)rateIndependentElapsedTime * rotationSpeed * MathF.PI * 2.0f));
}
}
}

View File

@ -314,6 +314,7 @@ namespace osu.Game.Rulesets.Osu
{
new StatisticItem(string.Empty, () => new SimpleStatisticTable(3, new SimpleStatisticItem[]
{
new AverageHitError(timedHitEvents),
new UnstableRate(timedHitEvents)
}), true)
}

View File

@ -7,7 +7,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Debug/net5.0/osu.Game.Rulesets.Taiko.Tests.dll"
"${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.Taiko.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug)",
@ -20,7 +20,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Release/net5.0/osu.Game.Rulesets.Taiko.Tests.dll"
"${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.Taiko.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)",

View File

@ -9,9 +9,9 @@
</ItemGroup>
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
</ItemGroup>
</Project>
</Project>

View File

@ -9,18 +9,39 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
{
public class TaikoDifficultyAttributes : DifficultyAttributes
{
/// <summary>
/// The difficulty corresponding to the stamina skill.
/// </summary>
[JsonProperty("stamina_difficulty")]
public double StaminaDifficulty { get; set; }
/// <summary>
/// The difficulty corresponding to the rhythm skill.
/// </summary>
[JsonProperty("rhythm_difficulty")]
public double RhythmDifficulty { get; set; }
/// <summary>
/// The difficulty corresponding to the colour skill.
/// </summary>
[JsonProperty("colour_difficulty")]
public double ColourDifficulty { get; set; }
/// <summary>
/// The perceived approach rate inclusive of rate-adjusting mods (DT/HT/etc).
/// </summary>
/// <remarks>
/// Rate-adjusting mods don't directly affect the approach rate difficulty value, but have a perceived effect as a result of adjusting audio timing.
/// </remarks>
[JsonProperty("approach_rate")]
public double ApproachRate { get; set; }
/// <summary>
/// The perceived hit window for a GREAT hit inclusive of rate-adjusting mods (DT/HT/etc).
/// </summary>
/// <remarks>
/// Rate-adjusting mods don't directly affect the hit window, but have a perceived effect as a result of adjusting audio timing.
/// </remarks>
[JsonProperty("great_hit_window")]
public double GreatHitWindow { get; set; }

View File

@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
{
get
{
string scrollSpeed = ScrollSpeed.IsDefault ? string.Empty : $"Scroll x{ScrollSpeed.Value:N1}";
string scrollSpeed = ScrollSpeed.IsDefault ? string.Empty : $"Scroll x{ScrollSpeed.Value:N2}";
return string.Join(", ", new[]
{

View File

@ -237,6 +237,7 @@ namespace osu.Game.Rulesets.Taiko
{
new StatisticItem(string.Empty, () => new SimpleStatisticTable(3, new SimpleStatisticItem[]
{
new AverageHitError(timedHitEvents),
new UnstableRate(timedHitEvents)
}), true)
}

View File

@ -409,26 +409,26 @@ namespace osu.Game.Tests.Chat
Assert.AreEqual(result.Content, result.DisplayContent);
Assert.AreEqual(2, result.Links.Count);
Assert.AreEqual("osu://chan/#english", result.Links[0].Url);
Assert.AreEqual("osu://chan/#japanese", result.Links[1].Url);
Assert.AreEqual($"{OsuGameBase.OSU_PROTOCOL}chan/#english", result.Links[0].Url);
Assert.AreEqual($"{OsuGameBase.OSU_PROTOCOL}chan/#japanese", result.Links[1].Url);
}
[Test]
public void TestOsuProtocol()
{
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a custom protocol osu://chan/#english." });
Message result = MessageFormatter.FormatMessage(new Message { Content = $"This is a custom protocol {OsuGameBase.OSU_PROTOCOL}chan/#english." });
Assert.AreEqual(result.Content, result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("osu://chan/#english", result.Links[0].Url);
Assert.AreEqual($"{OsuGameBase.OSU_PROTOCOL}chan/#english", result.Links[0].Url);
Assert.AreEqual(26, result.Links[0].Index);
Assert.AreEqual(19, result.Links[0].Length);
result = MessageFormatter.FormatMessage(new Message { Content = "This is a [custom protocol](osu://chan/#english)." });
result = MessageFormatter.FormatMessage(new Message { Content = $"This is a [custom protocol]({OsuGameBase.OSU_PROTOCOL}chan/#english)." });
Assert.AreEqual("This is a custom protocol.", result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("osu://chan/#english", result.Links[0].Url);
Assert.AreEqual($"{OsuGameBase.OSU_PROTOCOL}chan/#english", result.Links[0].Url);
Assert.AreEqual("#english", result.Links[0].Argument);
Assert.AreEqual(10, result.Links[0].Index);
Assert.AreEqual(15, result.Links[0].Length);

View File

@ -41,7 +41,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using (var importer = new BeatmapModelManager(realm, storage))
using (new RulesetStore(realm, storage))
using (new RealmRulesetStore(realm, storage))
{
Live<BeatmapSetInfo>? beatmapSet;
@ -85,7 +85,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using (var importer = new BeatmapModelManager(realm, storage))
using (new RulesetStore(realm, storage))
using (new RealmRulesetStore(realm, storage))
{
Live<BeatmapSetInfo>? beatmapSet;
@ -142,7 +142,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using (var importer = new BeatmapModelManager(realm, storage))
using (new RulesetStore(realm, storage))
using (new RealmRulesetStore(realm, storage))
{
Live<BeatmapSetInfo>? imported;
@ -171,7 +171,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
await LoadOszIntoStore(importer, realm.Realm);
});
@ -183,7 +183,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
var imported = await LoadOszIntoStore(importer, realm.Realm);
@ -201,7 +201,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
var imported = await LoadOszIntoStore(importer, realm.Realm);
@ -215,7 +215,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
string? tempPath = TestResources.GetTestBeatmapForImport();
@ -245,7 +245,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
var imported = await LoadOszIntoStore(importer, realm.Realm);
var importedSecondTime = await LoadOszIntoStore(importer, realm.Realm);
@ -265,7 +265,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -314,7 +314,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -366,7 +366,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -414,7 +414,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -463,7 +463,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
var imported = await LoadOszIntoStore(importer, realm.Realm);
@ -496,7 +496,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
var progressNotification = new ImportProgressNotification();
@ -532,7 +532,7 @@ namespace osu.Game.Tests.Database
};
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
var imported = await LoadOszIntoStore(importer, realm.Realm);
@ -582,7 +582,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
var imported = await LoadOszIntoStore(importer, realm.Realm);
@ -606,7 +606,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapModelManager(realmFactory, storage);
using var store = new RulesetStore(realmFactory, storage);
using var store = new RealmRulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Realm);
@ -638,7 +638,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new NonOptimisedBeatmapImporter(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
var imported = await LoadOszIntoStore(importer, realm.Realm);
@ -662,7 +662,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
var imported = await LoadOszIntoStore(importer, realm.Realm);
@ -688,7 +688,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealm((realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
var metadata = new BeatmapMetadata
{
@ -734,7 +734,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
using (File.OpenRead(temp))
@ -751,7 +751,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -787,7 +787,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -829,7 +829,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
@ -880,7 +880,7 @@ namespace osu.Game.Tests.Database
RunTestWithRealmAsync(async (realm, storage) =>
{
using var importer = new BeatmapModelManager(realm, storage);
using var store = new RulesetStore(realm, storage);
using var store = new RealmRulesetStore(realm, storage);
string? temp = TestResources.GetTestBeatmapForImport();
await importer.Import(temp);

View File

@ -4,8 +4,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Tests.Resources;
@ -18,6 +20,33 @@ namespace osu.Game.Tests.Database
[TestFixture]
public class RealmSubscriptionRegistrationTests : RealmTest
{
[Test]
public void TestSubscriptionWithAsyncWrite()
{
ChangeSet? lastChanges = null;
RunTestWithRealm((realm, _) =>
{
var registration = realm.RegisterForNotifications(r => r.All<BeatmapSetInfo>(), onChanged);
realm.Run(r => r.Refresh());
// Without forcing the write onto its own thread, realm will internally run the operation synchronously, which can cause a deadlock with `WaitSafely`.
Task.Run(async () =>
{
await realm.WriteAsync(r => r.Add(TestResources.CreateTestBeatmapSetInfo()));
}).WaitSafely();
realm.Run(r => r.Refresh());
Assert.That(lastChanges?.InsertedIndices, Has.One.Items);
registration.Dispose();
});
void onChanged(IRealmCollection<BeatmapSetInfo> sender, ChangeSet? changes, Exception error) => lastChanges = changes;
}
[Test]
public void TestSubscriptionWithContextLoss()
{

View File

@ -14,7 +14,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realm, storage) =>
{
var rulesets = new RulesetStore(realm, storage);
var rulesets = new RealmRulesetStore(realm, storage);
Assert.AreEqual(4, rulesets.AvailableRulesets.Count());
Assert.AreEqual(4, realm.Realm.All<RulesetInfo>().Count());
@ -26,8 +26,8 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realm, storage) =>
{
var rulesets = new RulesetStore(realm, storage);
var rulesets2 = new RulesetStore(realm, storage);
var rulesets = new RealmRulesetStore(realm, storage);
var rulesets2 = new RealmRulesetStore(realm, storage);
Assert.AreEqual(4, rulesets.AvailableRulesets.Count());
Assert.AreEqual(4, rulesets2.AvailableRulesets.Count());
@ -42,7 +42,7 @@ namespace osu.Game.Tests.Database
{
RunTestWithRealm((realm, storage) =>
{
var rulesets = new RulesetStore(realm, storage);
var rulesets = new RealmRulesetStore(realm, storage);
Assert.IsFalse(rulesets.AvailableRulesets.First().IsManaged);
Assert.IsFalse(rulesets.GetRuleset(0)?.IsManaged);

View File

@ -21,8 +21,8 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
{
var user = new APIUser { Id = 33 };
AddRepeatStep("add user multiple times", () => Client.AddUser(user), 3);
AddAssert("room has 2 users", () => Client.Room?.Users.Count == 2);
AddRepeatStep("add user multiple times", () => MultiplayerClient.AddUser(user), 3);
AddAssert("room has 2 users", () => MultiplayerClient.Room?.Users.Count == 2);
}
[Test]
@ -30,11 +30,11 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
{
var user = new APIUser { Id = 44 };
AddStep("add user", () => Client.AddUser(user));
AddAssert("room has 2 users", () => Client.Room?.Users.Count == 2);
AddStep("add user", () => MultiplayerClient.AddUser(user));
AddAssert("room has 2 users", () => MultiplayerClient.Room?.Users.Count == 2);
AddRepeatStep("remove user multiple times", () => Client.RemoveUser(user), 3);
AddAssert("room has 1 user", () => Client.Room?.Users.Count == 1);
AddRepeatStep("remove user multiple times", () => MultiplayerClient.RemoveUser(user), 3);
AddAssert("room has 1 user", () => MultiplayerClient.Room?.Users.Count == 1);
}
[Test]
@ -42,7 +42,7 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
{
int id = 2000;
AddRepeatStep("add some users", () => Client.AddUser(new APIUser { Id = id++ }), 5);
AddRepeatStep("add some users", () => MultiplayerClient.AddUser(new APIUser { Id = id++ }), 5);
checkPlayingUserCount(0);
changeState(3, MultiplayerUserState.WaitingForLoad);
@ -57,17 +57,17 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
changeState(6, MultiplayerUserState.WaitingForLoad);
checkPlayingUserCount(6);
AddStep("another user left", () => Client.RemoveUser((Client.Room?.Users.Last().User).AsNonNull()));
AddStep("another user left", () => MultiplayerClient.RemoveUser((MultiplayerClient.Room?.Users.Last().User).AsNonNull()));
checkPlayingUserCount(5);
AddStep("leave room", () => Client.LeaveRoom());
AddStep("leave room", () => MultiplayerClient.LeaveRoom());
checkPlayingUserCount(0);
}
[Test]
public void TestPlayingUsersUpdatedOnJoin()
{
AddStep("leave room", () => Client.LeaveRoom());
AddStep("leave room", () => MultiplayerClient.LeaveRoom());
AddUntilStep("wait for room part", () => !RoomJoined);
AddStep("create room initially in gameplay", () =>
@ -76,7 +76,7 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
newRoom.CopyFrom(SelectedRoom.Value);
newRoom.RoomID.Value = null;
Client.RoomSetupAction = room =>
MultiplayerClient.RoomSetupAction = room =>
{
room.State = MultiplayerRoomState.Playing;
room.Users.Add(new MultiplayerRoomUser(PLAYER_1_ID)
@ -94,15 +94,15 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
}
private void checkPlayingUserCount(int expectedCount)
=> AddAssert($"{"user".ToQuantity(expectedCount)} playing", () => Client.CurrentMatchPlayingUserIds.Count == expectedCount);
=> AddAssert($"{"user".ToQuantity(expectedCount)} playing", () => MultiplayerClient.CurrentMatchPlayingUserIds.Count == expectedCount);
private void changeState(int userCount, MultiplayerUserState state)
=> AddStep($"{"user".ToQuantity(userCount)} in {state}", () =>
{
for (int i = 0; i < userCount; ++i)
{
int userId = Client.Room?.Users[i].UserID ?? throw new AssertionException("Room cannot be null!");
Client.ChangeUserState(userId, state);
int userId = MultiplayerClient.Room?.Users[i].UserID ?? throw new AssertionException("Room cannot be null!");
MultiplayerClient.ChangeUserState(userId, state);
}
});
}

View File

@ -121,6 +121,17 @@ namespace osu.Game.Tests.Online
Assert.That((deserialised?.Mods[0])?.Settings["speed_change"], Is.EqualTo(2));
}
[Test]
public void TestAPIModDetachedFromSource()
{
var mod = new OsuModDoubleTime { SpeedChange = { Value = 1.01 } };
var apiMod = new APIMod(mod);
mod.SpeedChange.Value = 1.5;
Assert.That(apiMod.Settings["speed_change"], Is.EqualTo(1.01d));
}
private class TestRuleset : Ruleset
{
public override IEnumerable<Mod> GetModsFor(ModType type) => new Mod[]

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
@ -12,6 +13,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Framework.Testing;
@ -21,6 +23,8 @@ using osu.Game.Database;
using osu.Game.IO;
using osu.Game.IO.Archives;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Tests.Resources;
@ -45,7 +49,7 @@ namespace osu.Game.Tests.Online
[BackgroundDependencyLoader]
private void load(AudioManager audio, GameHost host)
{
Dependencies.Cache(rulesets = new RulesetStore(Realm));
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.CacheAs<BeatmapManager>(beatmaps = new TestBeatmapManager(LocalStorage, Realm, rulesets, API, audio, Resources, host, Beatmap.Default));
Dependencies.CacheAs<BeatmapModelDownloader>(beatmapDownloader = new TestBeatmapModelDownloader(beatmaps, API));
}
@ -53,6 +57,25 @@ namespace osu.Game.Tests.Online
[SetUp]
public void SetUp() => Schedule(() =>
{
((DummyAPIAccess)API).HandleRequest = req =>
{
switch (req)
{
case GetBeatmapsRequest beatmapsReq:
var beatmap = CreateAPIBeatmap();
beatmap.OnlineID = testBeatmapInfo.OnlineID;
beatmap.OnlineBeatmapSetID = testBeatmapSet.OnlineID;
beatmap.Checksum = testBeatmapInfo.MD5Hash;
beatmap.BeatmapSet!.OnlineID = testBeatmapSet.OnlineID;
beatmapsReq.TriggerSuccess(new GetBeatmapsResponse { Beatmaps = new List<APIBeatmap> { beatmap } });
return true;
default:
return false;
}
};
beatmaps.AllowImport = new TaskCompletionSource<bool>();
testBeatmapFile = TestResources.GetQuickTestBeatmapForImport();
@ -63,18 +86,35 @@ namespace osu.Game.Tests.Online
Realm.Write(r => r.RemoveAll<BeatmapSetInfo>());
Realm.Write(r => r.RemoveAll<BeatmapInfo>());
selectedItem.Value = new PlaylistItem
selectedItem.Value = new PlaylistItem(testBeatmapInfo)
{
Beatmap = { Value = testBeatmapInfo },
Ruleset = { Value = testBeatmapInfo.Ruleset },
RulesetID = testBeatmapInfo.Ruleset.OnlineID,
};
Child = availabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
{
SelectedItem = { BindTarget = selectedItem, }
};
recreateChildren();
});
private void recreateChildren()
{
var beatmapLookupCache = new BeatmapLookupCache();
Child = new DependencyProvidingContainer
{
CachedDependencies = new[]
{
(typeof(BeatmapLookupCache), (object)beatmapLookupCache)
},
Children = new Drawable[]
{
beatmapLookupCache,
availabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
{
SelectedItem = { BindTarget = selectedItem, }
}
}
};
}
[Test]
public void TestBeatmapDownloadingFlow()
{
@ -123,10 +163,7 @@ namespace osu.Game.Tests.Online
});
addAvailabilityCheckStep("state not downloaded", BeatmapAvailability.NotDownloaded);
AddStep("recreate tracker", () => Child = availabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
{
SelectedItem = { BindTarget = selectedItem }
});
AddStep("recreate tracker", recreateChildren);
addAvailabilityCheckStep("state not downloaded as well", BeatmapAvailability.NotDownloaded);
AddStep("reimport original beatmap", () => beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely());
@ -167,7 +204,8 @@ namespace osu.Game.Tests.Online
public Live<BeatmapSetInfo> CurrentImport { get; private set; }
public TestBeatmapManager(Storage storage, RealmAccess realm, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore<byte[]> resources, GameHost host = null, WorkingBeatmap defaultBeatmap = null)
public TestBeatmapManager(Storage storage, RealmAccess realm, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore<byte[]> resources,
GameHost host = null, WorkingBeatmap defaultBeatmap = null)
: base(storage, realm, rulesets, api, audioManager, resources, host, defaultBeatmap)
{
}

View File

@ -3,6 +3,7 @@
using System;
using NUnit.Framework;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
namespace osu.Game.Tests.OnlinePlay
@ -29,9 +30,9 @@ namespace osu.Game.Tests.OnlinePlay
{
var items = new[]
{
new PlaylistItem { ID = 1, BeatmapID = 1001, PlaylistOrder = 1 },
new PlaylistItem { ID = 2, BeatmapID = 1002, PlaylistOrder = 2 },
new PlaylistItem { ID = 3, BeatmapID = 1003, PlaylistOrder = 3 },
new PlaylistItem(new APIBeatmap { OnlineID = 1001 }) { ID = 1, PlaylistOrder = 1 },
new PlaylistItem(new APIBeatmap { OnlineID = 1002 }) { ID = 2, PlaylistOrder = 2 },
new PlaylistItem(new APIBeatmap { OnlineID = 1003 }) { ID = 3, PlaylistOrder = 3 },
};
Assert.Multiple(() =>
@ -47,9 +48,9 @@ namespace osu.Game.Tests.OnlinePlay
{
var items = new[]
{
new PlaylistItem { ID = 2, BeatmapID = 1002, PlaylistOrder = 2 },
new PlaylistItem { ID = 1, BeatmapID = 1001, PlaylistOrder = 1 },
new PlaylistItem { ID = 3, BeatmapID = 1003, PlaylistOrder = 3 },
new PlaylistItem(new APIBeatmap { OnlineID = 1002 }) { ID = 2, PlaylistOrder = 2 },
new PlaylistItem(new APIBeatmap { OnlineID = 1001 }) { ID = 1, PlaylistOrder = 1 },
new PlaylistItem(new APIBeatmap { OnlineID = 1003 }) { ID = 3, PlaylistOrder = 3 },
};
Assert.Multiple(() =>
@ -65,9 +66,9 @@ namespace osu.Game.Tests.OnlinePlay
{
var items = new[]
{
new PlaylistItem { ID = 1, BeatmapID = 1001, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 55, 0, TimeSpan.Zero) },
new PlaylistItem { ID = 2, BeatmapID = 1002, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 53, 0, TimeSpan.Zero) },
new PlaylistItem { ID = 3, BeatmapID = 1003, PlaylistOrder = 3 },
new PlaylistItem(new APIBeatmap { OnlineID = 1001 }) { ID = 1, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 55, 0, TimeSpan.Zero) },
new PlaylistItem(new APIBeatmap { OnlineID = 1002 }) { ID = 2, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 53, 0, TimeSpan.Zero) },
new PlaylistItem(new APIBeatmap { OnlineID = 1003 }) { ID = 3, PlaylistOrder = 3 },
};
Assert.Multiple(() =>
@ -83,9 +84,9 @@ namespace osu.Game.Tests.OnlinePlay
{
var items = new[]
{
new PlaylistItem { ID = 1, BeatmapID = 1001, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 55, 0, TimeSpan.Zero) },
new PlaylistItem { ID = 2, BeatmapID = 1002, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 53, 0, TimeSpan.Zero) },
new PlaylistItem { ID = 3, BeatmapID = 1002, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 57, 0, TimeSpan.Zero) },
new PlaylistItem(new APIBeatmap { OnlineID = 1001 }) { ID = 1, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 55, 0, TimeSpan.Zero) },
new PlaylistItem(new APIBeatmap { OnlineID = 1002 }) { ID = 2, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 53, 0, TimeSpan.Zero) },
new PlaylistItem(new APIBeatmap { OnlineID = 1002 }) { ID = 3, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 57, 0, TimeSpan.Zero) },
};
Assert.Multiple(() =>

Binary file not shown.

View File

@ -36,9 +36,9 @@ namespace osu.Game.Tests.Rulesets.Scoring
[TestCase(ScoringMode.Standardised, HitResult.Meh, 750_000)]
[TestCase(ScoringMode.Standardised, HitResult.Ok, 800_000)]
[TestCase(ScoringMode.Standardised, HitResult.Great, 1_000_000)]
[TestCase(ScoringMode.Classic, HitResult.Meh, 41)]
[TestCase(ScoringMode.Classic, HitResult.Ok, 46)]
[TestCase(ScoringMode.Classic, HitResult.Great, 72)]
[TestCase(ScoringMode.Classic, HitResult.Meh, 20)]
[TestCase(ScoringMode.Classic, HitResult.Ok, 23)]
[TestCase(ScoringMode.Classic, HitResult.Great, 36)]
public void TestSingleOsuHit(ScoringMode scoringMode, HitResult hitResult, int expectedScore)
{
scoreProcessor.Mode.Value = scoringMode;
@ -86,17 +86,17 @@ namespace osu.Game.Tests.Rulesets.Scoring
[TestCase(ScoringMode.Standardised, HitResult.SmallBonus, HitResult.SmallBonus, 1_000_030)] // 1 * 300_000 + 700_000 (max combo 0) + 3 * 10 (bonus points)
[TestCase(ScoringMode.Standardised, HitResult.LargeBonus, HitResult.LargeBonus, 1_000_150)] // 1 * 300_000 + 700_000 (max combo 0) + 3 * 50 (bonus points)
[TestCase(ScoringMode.Classic, HitResult.Miss, HitResult.Great, 0)]
[TestCase(ScoringMode.Classic, HitResult.Meh, HitResult.Great, 68)]
[TestCase(ScoringMode.Classic, HitResult.Ok, HitResult.Great, 81)]
[TestCase(ScoringMode.Classic, HitResult.Good, HitResult.Perfect, 109)]
[TestCase(ScoringMode.Classic, HitResult.Great, HitResult.Great, 149)]
[TestCase(ScoringMode.Classic, HitResult.Perfect, HitResult.Perfect, 149)]
[TestCase(ScoringMode.Classic, HitResult.SmallTickMiss, HitResult.SmallTickHit, 9)]
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, HitResult.SmallTickHit, 15)]
[TestCase(ScoringMode.Classic, HitResult.Meh, HitResult.Great, 86)]
[TestCase(ScoringMode.Classic, HitResult.Ok, HitResult.Great, 104)]
[TestCase(ScoringMode.Classic, HitResult.Good, HitResult.Perfect, 140)]
[TestCase(ScoringMode.Classic, HitResult.Great, HitResult.Great, 190)]
[TestCase(ScoringMode.Classic, HitResult.Perfect, HitResult.Perfect, 190)]
[TestCase(ScoringMode.Classic, HitResult.SmallTickMiss, HitResult.SmallTickHit, 18)]
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, HitResult.SmallTickHit, 31)]
[TestCase(ScoringMode.Classic, HitResult.LargeTickMiss, HitResult.LargeTickHit, 0)]
[TestCase(ScoringMode.Classic, HitResult.LargeTickHit, HitResult.LargeTickHit, 149)]
[TestCase(ScoringMode.Classic, HitResult.SmallBonus, HitResult.SmallBonus, 18)]
[TestCase(ScoringMode.Classic, HitResult.LargeBonus, HitResult.LargeBonus, 18)]
[TestCase(ScoringMode.Classic, HitResult.LargeTickHit, HitResult.LargeTickHit, 12)]
[TestCase(ScoringMode.Classic, HitResult.SmallBonus, HitResult.SmallBonus, 36)]
[TestCase(ScoringMode.Classic, HitResult.LargeBonus, HitResult.LargeBonus, 36)]
public void TestFourVariousResultsOneMiss(ScoringMode scoringMode, HitResult hitResult, HitResult maxResult, int expectedScore)
{
var minResult = new TestJudgement(hitResult).MinResult;
@ -128,8 +128,8 @@ namespace osu.Game.Tests.Rulesets.Scoring
/// </remarks>
[TestCase(ScoringMode.Standardised, HitResult.SmallTickHit, 978_571)] // (3 * 10 + 100) / (4 * 10 + 100) * 300_000 + (1 / 1) * 700_000
[TestCase(ScoringMode.Standardised, HitResult.SmallTickMiss, 914_286)] // (3 * 0 + 100) / (4 * 10 + 100) * 300_000 + (1 / 1) * 700_000
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, 69)] // (((3 * 10 + 100) / (4 * 10 + 100)) * 1 * 300) * (1 + 0 / 25)
[TestCase(ScoringMode.Classic, HitResult.SmallTickMiss, 60)] // (((3 * 0 + 100) / (4 * 10 + 100)) * 1 * 300) * (1 + 0 / 25)
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, 34)]
[TestCase(ScoringMode.Classic, HitResult.SmallTickMiss, 30)]
public void TestSmallTicksAccuracy(ScoringMode scoringMode, HitResult hitResult, int expectedScore)
{
IEnumerable<HitObject> hitObjects = Enumerable

View File

@ -0,0 +1,132 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using NUnit.Framework;
using osu.Game.Utils;
namespace osu.Game.Tests.Utils
{
[TestFixture]
public class NamingUtilsTest
{
[Test]
public void TestEmptySet()
{
string nextBestName = NamingUtils.GetNextBestName(Enumerable.Empty<string>(), "New Difficulty");
Assert.AreEqual("New Difficulty", nextBestName);
}
[Test]
public void TestNotTaken()
{
string[] existingNames =
{
"Something",
"Entirely",
"Different"
};
string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty");
Assert.AreEqual("New Difficulty", nextBestName);
}
[Test]
public void TestNotTakenButClose()
{
string[] existingNames =
{
"New Difficulty(1)",
"New Difficulty (abcd)",
"New Difficulty but not really"
};
string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty");
Assert.AreEqual("New Difficulty", nextBestName);
}
[Test]
public void TestAlreadyTaken()
{
string[] existingNames =
{
"New Difficulty"
};
string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty");
Assert.AreEqual("New Difficulty (1)", nextBestName);
}
[Test]
public void TestAlreadyTakenWithDifferentCase()
{
string[] existingNames =
{
"new difficulty"
};
string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty");
Assert.AreEqual("New Difficulty (1)", nextBestName);
}
[Test]
public void TestAlreadyTakenWithBrackets()
{
string[] existingNames =
{
"new difficulty (copy)"
};
string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty (copy)");
Assert.AreEqual("New Difficulty (copy) (1)", nextBestName);
}
[Test]
public void TestMultipleAlreadyTaken()
{
string[] existingNames =
{
"New Difficulty",
"New difficulty (1)",
"new Difficulty (2)",
"New DIFFICULTY (3)"
};
string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty");
Assert.AreEqual("New Difficulty (4)", nextBestName);
}
[Test]
public void TestEvenMoreAlreadyTaken()
{
string[] existingNames = Enumerable.Range(1, 30).Select(i => $"New Difficulty ({i})").Append("New Difficulty").ToArray();
string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty");
Assert.AreEqual("New Difficulty (31)", nextBestName);
}
[Test]
public void TestMultipleAlreadyTakenWithGaps()
{
string[] existingNames =
{
"New Difficulty",
"New Difficulty (1)",
"New Difficulty (4)",
"New Difficulty (9)"
};
string nextBestName = NamingUtils.GetNextBestName(existingNames, "New Difficulty");
Assert.AreEqual("New Difficulty (2)", nextBestName);
}
}
}

View File

@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.Background
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(Realm));
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(new OsuConfigManager(LocalStorage));
Dependencies.Cache(Realm);

View File

@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual.Collections
[BackgroundDependencyLoader]
private void load(GameHost host)
{
Dependencies.Cache(rulesets = new RulesetStore(Realm));
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, rulesets, null, Audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);

View File

@ -2,9 +2,11 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Diagnostics;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Testing;
@ -20,30 +22,31 @@ namespace osu.Game.Tests.Visual.Editing
private BeatDivisorControl beatDivisorControl;
private BindableBeatDivisor bindableBeatDivisor;
private SliderBar<int> tickSliderBar;
private EquilateralTriangle tickMarkerHead;
private SliderBar<int> tickSliderBar => beatDivisorControl.ChildrenOfType<SliderBar<int>>().Single();
private EquilateralTriangle tickMarkerHead => tickSliderBar.ChildrenOfType<EquilateralTriangle>().Single();
[SetUp]
public void SetUp() => Schedule(() =>
{
Child = beatDivisorControl = new BeatDivisorControl(bindableBeatDivisor = new BindableBeatDivisor(16))
Child = new PopoverContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(90, 90)
RelativeSizeAxes = Axes.Both,
Child = beatDivisorControl = new BeatDivisorControl(bindableBeatDivisor = new BindableBeatDivisor(16))
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(90, 90)
}
};
tickSliderBar = beatDivisorControl.ChildrenOfType<SliderBar<int>>().Single();
tickMarkerHead = tickSliderBar.ChildrenOfType<EquilateralTriangle>().Single();
});
[Test]
public void TestBindableBeatDivisor()
{
AddRepeatStep("move previous", () => bindableBeatDivisor.Previous(), 4);
AddRepeatStep("move previous", () => bindableBeatDivisor.Previous(), 2);
AddAssert("divisor is 4", () => bindableBeatDivisor.Value == 4);
AddRepeatStep("move next", () => bindableBeatDivisor.Next(), 3);
AddAssert("divisor is 12", () => bindableBeatDivisor.Value == 12);
AddRepeatStep("move next", () => bindableBeatDivisor.Next(), 1);
AddAssert("divisor is 12", () => bindableBeatDivisor.Value == 8);
}
[Test]
@ -79,5 +82,115 @@ namespace osu.Game.Tests.Visual.Editing
sliderDrawQuad.Centre.Y
);
}
[Test]
public void TestBeatChevronNavigation()
{
switchBeatSnap(1);
assertBeatSnap(1);
switchBeatSnap(3);
assertBeatSnap(8);
switchBeatSnap(-1);
assertBeatSnap(4);
switchBeatSnap(-3);
assertBeatSnap(16);
}
[Test]
public void TestBeatPresetNavigation()
{
assertPreset(BeatDivisorType.Common);
switchPresets(1);
assertPreset(BeatDivisorType.Triplets);
switchPresets(1);
assertPreset(BeatDivisorType.Common);
switchPresets(-1);
assertPreset(BeatDivisorType.Triplets);
switchPresets(-1);
assertPreset(BeatDivisorType.Common);
setDivisorViaInput(3);
assertPreset(BeatDivisorType.Triplets);
setDivisorViaInput(8);
assertPreset(BeatDivisorType.Common);
setDivisorViaInput(15);
assertPreset(BeatDivisorType.Custom, 15);
switchBeatSnap(-1);
assertBeatSnap(5);
switchBeatSnap(-1);
assertBeatSnap(3);
setDivisorViaInput(5);
assertPreset(BeatDivisorType.Custom, 15);
switchPresets(1);
assertPreset(BeatDivisorType.Common);
switchPresets(-1);
assertPreset(BeatDivisorType.Triplets);
}
private void switchBeatSnap(int direction) => AddRepeatStep($"move snap {(direction > 0 ? "forward" : "backward")}", () =>
{
int chevronIndex = direction > 0 ? 1 : 0;
var chevronButton = beatDivisorControl.ChildrenOfType<BeatDivisorControl.ChevronButton>().ElementAt(chevronIndex);
InputManager.MoveMouseTo(chevronButton);
InputManager.Click(MouseButton.Left);
}, Math.Abs(direction));
private void assertBeatSnap(int expected) => AddAssert($"beat snap is {expected}",
() => bindableBeatDivisor.Value == expected);
private void switchPresets(int direction) => AddRepeatStep($"move presets {(direction > 0 ? "forward" : "backward")}", () =>
{
int chevronIndex = direction > 0 ? 3 : 2;
var chevronButton = beatDivisorControl.ChildrenOfType<BeatDivisorControl.ChevronButton>().ElementAt(chevronIndex);
InputManager.MoveMouseTo(chevronButton);
InputManager.Click(MouseButton.Left);
}, Math.Abs(direction));
private void assertPreset(BeatDivisorType type, int? maxDivisor = null)
{
AddAssert($"preset is {type}", () => bindableBeatDivisor.ValidDivisors.Value.Type == type);
if (type == BeatDivisorType.Custom)
{
Debug.Assert(maxDivisor != null);
AddAssert($"max divisor is {maxDivisor}", () => bindableBeatDivisor.ValidDivisors.Value.Presets.Max() == maxDivisor.Value);
}
}
private void setDivisorViaInput(int divisor)
{
AddStep("open divisor input popover", () =>
{
var button = beatDivisorControl.ChildrenOfType<BeatDivisorControl.DivisorDisplay>().Single();
InputManager.MoveMouseTo(button);
InputManager.Click(MouseButton.Left);
});
BeatDivisorControl.CustomDivisorPopover popover = null;
AddUntilStep("wait for popover", () => (popover = this.ChildrenOfType<BeatDivisorControl.CustomDivisorPopover>().SingleOrDefault()) != null && popover.IsLoaded);
AddStep($"set divisor to {divisor}", () =>
{
var textBox = popover.ChildrenOfType<TextBox>().Single();
InputManager.MoveMouseTo(textBox);
InputManager.Click(MouseButton.Left);
textBox.Text = divisor.ToString();
InputManager.Key(Key.Enter);
});
AddUntilStep("wait for dismiss", () => !this.ChildrenOfType<BeatDivisorControl.CustomDivisorPopover>().Any());
}
}
}

View File

@ -6,15 +6,23 @@ using System.IO;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Database;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Setup;
using osu.Game.Storyboards;
using osu.Game.Tests.Resources;
using osuTK;
using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
@ -92,12 +100,27 @@ namespace osu.Game.Tests.Visual.Editing
}
[Test]
public void TestCreateNewDifficulty()
public void TestCreateNewDifficulty([Values] bool sameRuleset)
{
string firstDifficultyName = Guid.NewGuid().ToString();
string secondDifficultyName = Guid.NewGuid().ToString();
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = firstDifficultyName);
AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }));
AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[]
{
new HitCircle
{
Position = new Vector2(0),
StartTime = 0
},
new HitCircle
{
Position = OsuPlayfield.BASE_SIZE,
StartTime = 1000
}
}));
AddStep("save beatmap", () => Editor.Save());
AddAssert("new beatmap persisted", () =>
{
@ -111,13 +134,27 @@ namespace osu.Game.Tests.Visual.Editing
});
AddAssert("can save again", () => Editor.Save());
AddStep("create new difficulty", () => Editor.CreateNewDifficulty(new OsuRuleset().RulesetInfo));
AddStep("create new difficulty", () => Editor.CreateNewDifficulty(sameRuleset ? new OsuRuleset().RulesetInfo : new CatchRuleset().RulesetInfo));
if (sameRuleset)
{
AddUntilStep("wait for dialog", () => DialogOverlay.CurrentDialog is CreateNewDifficultyDialog);
AddStep("confirm creation with no objects", () => DialogOverlay.CurrentDialog.PerformOkAction());
}
AddUntilStep("wait for created", () =>
{
string difficultyName = Editor.ChildrenOfType<EditorBeatmap>().SingleOrDefault()?.BeatmapInfo.DifficultyName;
return difficultyName != null && difficultyName != firstDifficultyName;
});
AddAssert("created difficulty has timing point", () =>
{
var timingPoint = EditorBeatmap.ControlPointInfo.TimingPoints.Single();
return timingPoint.Time == 0 && timingPoint.BeatLength == 1000;
});
AddAssert("created difficulty has no objects", () => EditorBeatmap.HitObjects.Count == 0);
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = secondDifficultyName);
AddStep("save beatmap", () => Editor.Save());
AddAssert("new beatmap persisted", () =>
@ -133,11 +170,111 @@ namespace osu.Game.Tests.Visual.Editing
}
[Test]
public void TestCreateNewBeatmapFailsWithBlankNamedDifficulties()
public void TestCopyDifficulty()
{
string originalDifficultyName = Guid.NewGuid().ToString();
string copyDifficultyName = $"{originalDifficultyName} (copy)";
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = originalDifficultyName);
AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }));
AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[]
{
new HitCircle
{
Position = new Vector2(0),
StartTime = 0
},
new HitCircle
{
Position = OsuPlayfield.BASE_SIZE,
StartTime = 1000
}
}));
AddStep("set approach rate", () => EditorBeatmap.Difficulty.ApproachRate = 4);
AddStep("set combo colours", () =>
{
var beatmapSkin = EditorBeatmap.BeatmapSkin.AsNonNull();
beatmapSkin.ComboColours.Clear();
beatmapSkin.ComboColours.AddRange(new[]
{
new Colour4(255, 0, 0, 255),
new Colour4(0, 0, 255, 255)
});
});
AddStep("set status & online ID", () =>
{
EditorBeatmap.BeatmapInfo.OnlineID = 123456;
EditorBeatmap.BeatmapInfo.Status = BeatmapOnlineStatus.WIP;
});
AddStep("save beatmap", () => Editor.Save());
AddAssert("new beatmap persisted", () =>
{
var beatmap = beatmapManager.QueryBeatmap(b => b.DifficultyName == originalDifficultyName);
var set = beatmapManager.QueryBeatmapSet(s => s.ID == EditorBeatmap.BeatmapInfo.BeatmapSet.ID);
return beatmap != null
&& beatmap.DifficultyName == originalDifficultyName
&& set != null
&& set.PerformRead(s => s.Beatmaps.Single().ID == beatmap.ID);
});
AddAssert("can save again", () => Editor.Save());
AddStep("create new difficulty", () => Editor.CreateNewDifficulty(new OsuRuleset().RulesetInfo));
AddUntilStep("wait for dialog", () => DialogOverlay.CurrentDialog is CreateNewDifficultyDialog);
AddStep("confirm creation as a copy", () => DialogOverlay.CurrentDialog.Buttons.ElementAt(1).TriggerClick());
AddUntilStep("wait for created", () =>
{
string difficultyName = Editor.ChildrenOfType<EditorBeatmap>().SingleOrDefault()?.BeatmapInfo.DifficultyName;
return difficultyName != null && difficultyName != originalDifficultyName;
});
AddAssert("created difficulty has copy suffix in name", () => EditorBeatmap.BeatmapInfo.DifficultyName == copyDifficultyName);
AddAssert("created difficulty has timing point", () =>
{
var timingPoint = EditorBeatmap.ControlPointInfo.TimingPoints.Single();
return timingPoint.Time == 0 && timingPoint.BeatLength == 1000;
});
AddAssert("created difficulty has objects", () => EditorBeatmap.HitObjects.Count == 2);
AddAssert("approach rate correctly copied", () => EditorBeatmap.Difficulty.ApproachRate == 4);
AddAssert("combo colours correctly copied", () => EditorBeatmap.BeatmapSkin.AsNonNull().ComboColours.Count == 2);
AddAssert("status not copied", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.None);
AddAssert("online ID not copied", () => EditorBeatmap.BeatmapInfo.OnlineID == -1);
AddStep("save beatmap", () => Editor.Save());
BeatmapInfo refetchedBeatmap = null;
Live<BeatmapSetInfo> refetchedBeatmapSet = null;
AddStep("refetch from database", () =>
{
refetchedBeatmap = beatmapManager.QueryBeatmap(b => b.DifficultyName == copyDifficultyName);
refetchedBeatmapSet = beatmapManager.QueryBeatmapSet(s => s.ID == EditorBeatmap.BeatmapInfo.BeatmapSet.ID);
});
AddAssert("new beatmap persisted", () =>
{
return refetchedBeatmap != null
&& refetchedBeatmap.DifficultyName == copyDifficultyName
&& refetchedBeatmapSet != null
&& refetchedBeatmapSet.PerformRead(s =>
s.Beatmaps.Count == 2
&& s.Beatmaps.Any(b => b.DifficultyName == originalDifficultyName)
&& s.Beatmaps.Any(b => b.DifficultyName == copyDifficultyName));
});
AddAssert("old beatmap file not deleted", () => refetchedBeatmapSet.AsNonNull().PerformRead(s => s.Files.Count == 2));
}
[Test]
public void TestCreateMultipleNewDifficultiesSucceeds()
{
Guid setId = Guid.Empty;
AddStep("retrieve set ID", () => setId = EditorBeatmap.BeatmapInfo.BeatmapSet!.ID);
AddStep("set difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = "New Difficulty");
AddStep("save beatmap", () => Editor.Save());
AddAssert("new beatmap persisted", () =>
{
@ -146,15 +283,24 @@ namespace osu.Game.Tests.Visual.Editing
});
AddStep("try to create new difficulty", () => Editor.CreateNewDifficulty(new OsuRuleset().RulesetInfo));
AddAssert("beatmap set unchanged", () =>
AddUntilStep("wait for dialog", () => DialogOverlay.CurrentDialog is CreateNewDifficultyDialog);
AddStep("confirm creation with no objects", () => DialogOverlay.CurrentDialog.PerformOkAction());
AddUntilStep("wait for created", () =>
{
string difficultyName = Editor.ChildrenOfType<EditorBeatmap>().SingleOrDefault()?.BeatmapInfo.DifficultyName;
return difficultyName != null && difficultyName != "New Difficulty";
});
AddAssert("new difficulty has correct name", () => EditorBeatmap.BeatmapInfo.DifficultyName == "New Difficulty (1)");
AddAssert("new difficulty persisted", () =>
{
var set = beatmapManager.QueryBeatmapSet(s => s.ID == setId);
return set != null && set.PerformRead(s => s.Beatmaps.Count == 1 && s.Files.Count == 1);
return set != null && set.PerformRead(s => s.Beatmaps.Count == 2 && s.Files.Count == 2);
});
}
[Test]
public void TestCreateNewBeatmapFailsWithSameNamedDifficulties()
public void TestSavingBeatmapFailsWithSameNamedDifficulties([Values] bool sameRuleset)
{
Guid setId = Guid.Empty;
const string duplicate_difficulty_name = "duplicate";
@ -168,7 +314,14 @@ namespace osu.Game.Tests.Visual.Editing
return set != null && set.PerformRead(s => s.Beatmaps.Count == 1 && s.Files.Count == 1);
});
AddStep("create new difficulty", () => Editor.CreateNewDifficulty(new OsuRuleset().RulesetInfo));
AddStep("create new difficulty", () => Editor.CreateNewDifficulty(sameRuleset ? new OsuRuleset().RulesetInfo : new CatchRuleset().RulesetInfo));
if (sameRuleset)
{
AddUntilStep("wait for dialog", () => DialogOverlay.CurrentDialog is CreateNewDifficultyDialog);
AddStep("confirm creation with no objects", () => DialogOverlay.CurrentDialog.PerformOkAction());
}
AddUntilStep("wait for created", () =>
{
string difficultyName = Editor.ChildrenOfType<EditorBeatmap>().SingleOrDefault()?.BeatmapInfo.DifficultyName;

View File

@ -49,6 +49,8 @@ namespace osu.Game.Tests.Visual.Editing
double originalTimelineZoom = 0;
double changedTimelineZoom = 0;
AddUntilStep("wait for timeline load", () => Editor.ChildrenOfType<Timeline>().SingleOrDefault()?.IsLoaded == true);
AddStep("Set beat divisor", () => Editor.Dependencies.Get<BindableBeatDivisor>().Value = 16);
AddStep("Set timeline zoom", () =>
{

View File

@ -4,11 +4,9 @@
using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Components.Menus;
namespace osu.Game.Tests.Visual.Editing
{
@ -22,7 +20,7 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("switch between all screens at once", () =>
{
foreach (var screen in Enum.GetValues(typeof(EditorScreenMode)).Cast<EditorScreenMode>())
Editor.ChildrenOfType<EditorMenuBar>().Single().Mode.Value = screen;
Editor.Mode.Value = screen;
});
}
}

View File

@ -0,0 +1,74 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Overlays.Settings;
using osu.Game.Scoring;
using osu.Game.Screens.Play.PlayerSettings;
using osu.Game.Tests.Visual.Ranking;
namespace osu.Game.Tests.Visual.Gameplay
{
public class TestSceneBeatmapOffsetControl : OsuTestScene
{
private BeatmapOffsetControl offsetControl;
[SetUpSteps]
public void SetUpSteps()
{
AddStep("Create control", () =>
{
Child = new PlayerSettingsGroup("Some settings")
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new Drawable[]
{
offsetControl = new BeatmapOffsetControl()
}
};
});
}
[Test]
public void TestTooShortToDisplay()
{
AddStep("Set short reference score", () =>
{
offsetControl.ReferenceScore.Value = new ScoreInfo
{
HitEvents = TestSceneHitEventTimingDistributionGraph.CreateDistributedHitEvents(0, 2)
};
});
AddAssert("No calibration button", () => !offsetControl.ChildrenOfType<SettingsButton>().Any());
}
[Test]
public void TestDisplay()
{
const double average_error = -4.5;
AddAssert("Offset is neutral", () => offsetControl.Current.Value == 0);
AddAssert("No calibration button", () => !offsetControl.ChildrenOfType<SettingsButton>().Any());
AddStep("Set reference score", () =>
{
offsetControl.ReferenceScore.Value = new ScoreInfo
{
HitEvents = TestSceneHitEventTimingDistributionGraph.CreateDistributedHitEvents(average_error)
};
});
AddAssert("Has calibration button", () => offsetControl.ChildrenOfType<SettingsButton>().Any());
AddStep("Press button", () => offsetControl.ChildrenOfType<SettingsButton>().Single().TriggerClick());
AddAssert("Offset is adjusted", () => offsetControl.Current.Value == -average_error);
AddAssert("Button is disabled", () => !offsetControl.ChildrenOfType<SettingsButton>().Single().Enabled.Value);
AddStep("Remove reference score", () => offsetControl.ReferenceScore.Value = null);
AddAssert("No calibration button", () => !offsetControl.ChildrenOfType<SettingsButton>().Any());
}
}
}

View File

@ -131,9 +131,9 @@ namespace osu.Game.Tests.Visual.Gameplay
public double GameplayClockTime => GameplayClockContainer.GameplayClock.CurrentTime;
protected override void Update()
protected override void UpdateAfterChildren()
{
base.Update();
base.UpdateAfterChildren();
if (!FirstFrameClockTime.HasValue)
{

View File

@ -39,7 +39,8 @@ namespace osu.Game.Tests.Visual.Gameplay
[Resolved]
private OsuGameBase game { get; set; }
private TestSpectatorClient spectatorClient;
private TestSpectatorClient spectatorClient => dependenciesScreen.SpectatorClient;
private DependenciesScreen dependenciesScreen;
private SoloSpectator spectatorScreen;
private BeatmapSetInfo importedBeatmap;
@ -48,16 +49,16 @@ namespace osu.Game.Tests.Visual.Gameplay
[SetUpSteps]
public void SetupSteps()
{
DependenciesScreen dependenciesScreen = null;
AddStep("load dependencies", () =>
{
spectatorClient = new TestSpectatorClient();
LoadScreen(dependenciesScreen = new DependenciesScreen());
// The screen gets suspended so it stops receiving updates.
Child = spectatorClient;
LoadScreen(dependenciesScreen = new DependenciesScreen(spectatorClient));
// The dependencies screen gets suspended so it stops receiving updates. So its children are manually added to the test scene instead.
Children = new Drawable[]
{
dependenciesScreen.UserLookupCache,
dependenciesScreen.SpectatorClient,
};
});
AddUntilStep("wait for dependencies to load", () => dependenciesScreen.IsLoaded);
@ -256,7 +257,7 @@ namespace osu.Game.Tests.Visual.Gameplay
sendFrames();
waitForPlayer();
AddStep("send passed", () => spectatorClient.EndPlay(streamingUser.Id, SpectatedUserState.Passed));
AddStep("send passed", () => spectatorClient.SendEndPlay(streamingUser.Id, SpectatedUserState.Passed));
AddUntilStep("state is passed", () => spectatorClient.WatchedUserStates[streamingUser.Id].State == SpectatedUserState.Passed);
start();
@ -274,7 +275,7 @@ namespace osu.Game.Tests.Visual.Gameplay
sendFrames();
waitForPlayer();
AddStep("send quit", () => spectatorClient.EndPlay(streamingUser.Id));
AddStep("send quit", () => spectatorClient.SendEndPlay(streamingUser.Id));
AddUntilStep("state is quit", () => spectatorClient.WatchedUserStates[streamingUser.Id].State == SpectatedUserState.Quit);
start();
@ -292,7 +293,7 @@ namespace osu.Game.Tests.Visual.Gameplay
sendFrames();
waitForPlayer();
AddStep("send failed", () => spectatorClient.EndPlay(streamingUser.Id, SpectatedUserState.Failed));
AddStep("send failed", () => spectatorClient.SendEndPlay(streamingUser.Id, SpectatedUserState.Failed));
AddUntilStep("state is failed", () => spectatorClient.WatchedUserStates[streamingUser.Id].State == SpectatedUserState.Failed);
start();
@ -311,16 +312,16 @@ namespace osu.Game.Tests.Visual.Gameplay
private void waitForPlayer() => AddUntilStep("wait for player", () => (Stack.CurrentScreen as Player)?.IsLoaded == true);
private void start(int? beatmapId = null) => AddStep("start play", () => spectatorClient.StartPlay(streamingUser.Id, beatmapId ?? importedBeatmapId));
private void start(int? beatmapId = null) => AddStep("start play", () => spectatorClient.SendStartPlay(streamingUser.Id, beatmapId ?? importedBeatmapId));
private void finish(SpectatedUserState state = SpectatedUserState.Quit) => AddStep("end play", () => spectatorClient.EndPlay(streamingUser.Id, state));
private void finish(SpectatedUserState state = SpectatedUserState.Quit) => AddStep("end play", () => spectatorClient.SendEndPlay(streamingUser.Id, state));
private void checkPaused(bool state) =>
AddUntilStep($"game is {(state ? "paused" : "playing")}", () => player.ChildrenOfType<DrawableRuleset>().First().IsPaused.Value == state);
private void sendFrames(int count = 10)
{
AddStep("send frames", () => spectatorClient.SendFrames(streamingUser.Id, count));
AddStep("send frames", () => spectatorClient.SendFramesFromUser(streamingUser.Id, count));
}
private void loadSpectatingScreen()
@ -335,12 +336,10 @@ namespace osu.Game.Tests.Visual.Gameplay
private class DependenciesScreen : OsuScreen
{
[Cached(typeof(SpectatorClient))]
public readonly TestSpectatorClient Client;
public readonly TestSpectatorClient SpectatorClient = new TestSpectatorClient();
public DependenciesScreen(TestSpectatorClient client)
{
Client = client;
}
[Cached(typeof(UserLookupCache))]
public readonly TestUserLookupCache UserLookupCache = new TestUserLookupCache();
}
}
}

View File

@ -41,8 +41,12 @@ namespace osu.Game.Tests.Visual.Gameplay
private Replay replay;
private TestSpectatorClient spectatorClient;
private ManualClock manualClock;
private TestReplayRecorder recorder;
private OsuSpriteText latencyDisplay;
private TestFramedReplayInputHandler replayHandler;
@ -54,7 +58,6 @@ namespace osu.Game.Tests.Visual.Gameplay
{
replay = new Replay();
manualClock = new ManualClock();
SpectatorClient spectatorClient;
Child = new DependencyProvidingContainer
{
@ -76,7 +79,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
recordingManager = new TestRulesetInputManager(TestSceneModSettings.CreateTestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
{
Recorder = new TestReplayRecorder
Recorder = recorder = new TestReplayRecorder
{
ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos),
},
@ -143,22 +146,52 @@ namespace osu.Game.Tests.Visual.Gameplay
});
}
[Test]
public void TestBasic()
{
AddUntilStep("received frames", () => replay.Frames.Count > 50);
AddStep("stop sending frames", () => recorder.Expire());
AddUntilStep("wait for all frames received", () => replay.Frames.Count == recorder.SentFrames.Count);
}
[Test]
public void TestWithSendFailure()
{
AddUntilStep("received frames", () => replay.Frames.Count > 50);
int framesReceivedSoFar = 0;
int frameSendAttemptsSoFar = 0;
AddStep("start failing sends", () =>
{
spectatorClient.ShouldFailSendingFrames = true;
framesReceivedSoFar = replay.Frames.Count;
frameSendAttemptsSoFar = spectatorClient.FrameSendAttempts;
});
AddUntilStep("wait for send attempts", () => spectatorClient.FrameSendAttempts > frameSendAttemptsSoFar + 5);
AddAssert("frames did not increase", () => framesReceivedSoFar == replay.Frames.Count);
AddStep("stop failing sends", () => spectatorClient.ShouldFailSendingFrames = false);
AddUntilStep("wait for next frames", () => framesReceivedSoFar < replay.Frames.Count);
AddStep("stop sending frames", () => recorder.Expire());
AddUntilStep("wait for all frames received", () => replay.Frames.Count == recorder.SentFrames.Count);
AddAssert("ensure frames were received in the correct sequence", () => replay.Frames.Select(f => f.Time).SequenceEqual(recorder.SentFrames.Select(f => f.Time)));
}
private void onNewFrames(int userId, FrameDataBundle frames)
{
Logger.Log($"Received {frames.Frames.Count} new frames ({string.Join(',', frames.Frames.Select(f => ((int)f.Time).ToString()))})");
foreach (var legacyFrame in frames.Frames)
{
var frame = new TestReplayFrame();
frame.FromLegacy(legacyFrame, null);
replay.Frames.Add(frame);
}
}
[Test]
public void TestBasic()
{
AddStep("Wait for user input", () => { });
Logger.Log($"Received {frames.Frames.Count} new frames (total {replay.Frames.Count} of {recorder.SentFrames.Count})");
}
private double latency = SpectatorClient.TIME_BETWEEN_SENDS;
@ -318,6 +351,8 @@ namespace osu.Game.Tests.Visual.Gameplay
internal class TestReplayRecorder : ReplayRecorder<TestAction>
{
public List<ReplayFrame> SentFrames = new List<ReplayFrame>();
public TestReplayRecorder()
: base(new Score
{
@ -332,7 +367,9 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override ReplayFrame HandleFrame(Vector2 mousePosition, List<TestAction> actions, ReplayFrame previousFrame)
{
return new TestReplayFrame(Time.Current, mousePosition, actions.ToArray());
var testReplayFrame = new TestReplayFrame(Time.Current, mousePosition, actions.ToArray());
SentFrames.Add(testReplayFrame);
return testReplayFrame;
}
}
}

View File

@ -19,6 +19,10 @@ namespace osu.Game.Tests.Visual.Menus
base.SetUpSteps();
AddAssert("no screen offset applied", () => Game.ScreenOffsetContainer.X == 0f);
// avoids mouse interacting with settings overlay.
AddStep("move mouse to centre", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.Centre));
AddUntilStep("wait for overlays", () => Game.Settings.IsLoaded && Game.Notifications.IsLoaded);
}

View File

@ -10,7 +10,6 @@ using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
@ -39,15 +38,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
private TestMultiplayerComponents multiplayerComponents;
protected TestMultiplayerClient Client => multiplayerComponents.Client;
[Cached(typeof(UserLookupCache))]
private UserLookupCache lookupCache = new TestUserLookupCache();
protected TestMultiplayerClient MultiplayerClient => multiplayerComponents.MultiplayerClient;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(Realm));
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
}
@ -75,10 +71,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
QueueMode = { Value = Mode },
Playlist =
{
new PlaylistItem
new PlaylistItem(InitialBeatmap)
{
Beatmap = { Value = InitialBeatmap },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
}));
@ -88,21 +83,21 @@ namespace osu.Game.Tests.Visual.Multiplayer
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
AddUntilStep("wait for join", () => Client.RoomJoined);
AddUntilStep("wait for join", () => MultiplayerClient.RoomJoined);
}
[Test]
public void TestCreatedWithCorrectMode()
{
AddAssert("room created with correct mode", () => Client.APIRoom?.QueueMode.Value == Mode);
AddAssert("room created with correct mode", () => MultiplayerClient.APIRoom?.QueueMode.Value == Mode);
}
protected void RunGameplay()
{
AddUntilStep("wait for idle", () => Client.LocalUser?.State == MultiplayerUserState.Idle);
AddUntilStep("wait for idle", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Idle);
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddUntilStep("wait for ready", () => Client.LocalUser?.State == MultiplayerUserState.Ready);
AddUntilStep("wait for ready", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Ready);
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddUntilStep("wait for player", () => multiplayerComponents.CurrentScreen is Player player && player.IsLoaded);

View File

@ -31,19 +31,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestFirstItemSelectedByDefault()
{
AddAssert("first item selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[0].ID);
AddAssert("first item selected", () => MultiplayerClient.Room?.Settings.PlaylistItemId == MultiplayerClient.APIRoom?.Playlist[0].ID);
}
[Test]
public void TestItemAddedToTheEndOfQueue()
{
addItem(() => OtherBeatmap);
AddAssert("playlist has 2 items", () => Client.APIRoom?.Playlist.Count == 2);
AddAssert("playlist has 2 items", () => MultiplayerClient.APIRoom?.Playlist.Count == 2);
addItem(() => InitialBeatmap);
AddAssert("playlist has 3 items", () => Client.APIRoom?.Playlist.Count == 3);
AddAssert("playlist has 3 items", () => MultiplayerClient.APIRoom?.Playlist.Count == 3);
AddAssert("first item still selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[0].ID);
AddAssert("first item still selected", () => MultiplayerClient.Room?.Settings.PlaylistItemId == MultiplayerClient.APIRoom?.Playlist[0].ID);
}
[Test]
@ -51,9 +51,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
RunGameplay();
AddAssert("playlist has only one item", () => Client.APIRoom?.Playlist.Count == 1);
AddAssert("playlist item is expired", () => Client.APIRoom?.Playlist[0].Expired == true);
AddAssert("last item selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[0].ID);
AddAssert("playlist has only one item", () => MultiplayerClient.APIRoom?.Playlist.Count == 1);
AddAssert("playlist item is expired", () => MultiplayerClient.APIRoom?.Playlist[0].Expired == true);
AddAssert("last item selected", () => MultiplayerClient.Room?.Settings.PlaylistItemId == MultiplayerClient.APIRoom?.Playlist[0].ID);
}
[Test]
@ -64,13 +64,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
RunGameplay();
AddAssert("first item expired", () => Client.APIRoom?.Playlist[0].Expired == true);
AddAssert("next item selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[1].ID);
AddAssert("first item expired", () => MultiplayerClient.APIRoom?.Playlist[0].Expired == true);
AddAssert("next item selected", () => MultiplayerClient.Room?.Settings.PlaylistItemId == MultiplayerClient.APIRoom?.Playlist[1].ID);
RunGameplay();
AddAssert("second item expired", () => Client.APIRoom?.Playlist[1].Expired == true);
AddAssert("next item selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[2].ID);
AddAssert("second item expired", () => MultiplayerClient.APIRoom?.Playlist[1].Expired == true);
AddAssert("next item selected", () => MultiplayerClient.Room?.Settings.PlaylistItemId == MultiplayerClient.APIRoom?.Playlist[2].ID);
}
[Test]
@ -82,10 +82,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
// Move to the "other" beatmap.
RunGameplay();
AddStep("change queue mode", () => Client.ChangeSettings(queueMode: QueueMode.HostOnly));
AddAssert("playlist has 3 items", () => Client.APIRoom?.Playlist.Count == 3);
AddAssert("item 2 is not expired", () => Client.APIRoom?.Playlist[1].Expired == false);
AddAssert("current item is the other beatmap", () => Client.Room?.Settings.PlaylistItemId == 2);
AddStep("change queue mode", () => MultiplayerClient.ChangeSettings(queueMode: QueueMode.HostOnly));
AddAssert("playlist has 3 items", () => MultiplayerClient.APIRoom?.Playlist.Count == 3);
AddAssert("item 2 is not expired", () => MultiplayerClient.APIRoom?.Playlist[1].Expired == false);
AddAssert("current item is the other beatmap", () => MultiplayerClient.Room?.Settings.PlaylistItemId == 2);
}
[Test]
@ -101,10 +101,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
addItem(() => OtherBeatmap, new CatchRuleset().RulesetInfo);
AddUntilStep("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID);
AddUntilStep("wait for idle", () => Client.LocalUser?.State == MultiplayerUserState.Idle);
AddUntilStep("wait for idle", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Idle);
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddUntilStep("wait for ready", () => Client.LocalUser?.State == MultiplayerUserState.Ready);
AddUntilStep("wait for ready", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Ready);
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddUntilStep("wait for player", () => CurrentScreen is Player player && player.IsLoaded);
@ -118,10 +118,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
addItem(() => OtherBeatmap, mods: new Mod[] { new OsuModDoubleTime() });
AddUntilStep("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID);
AddUntilStep("wait for idle", () => Client.LocalUser?.State == MultiplayerUserState.Idle);
AddUntilStep("wait for idle", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Idle);
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddUntilStep("wait for ready", () => Client.LocalUser?.State == MultiplayerUserState.Ready);
AddUntilStep("wait for ready", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Ready);
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddUntilStep("wait for player", () => CurrentScreen is Player player && player.IsLoaded);

View File

@ -37,10 +37,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("end joining room", () => joiningRoomOperation.Dispose());
assertButtonEnableState(true);
AddStep("disconnect client", () => Client.Disconnect());
AddStep("disconnect client", () => MultiplayerClient.Disconnect());
assertButtonEnableState(false);
AddStep("re-connect client", () => Client.Connect());
AddStep("re-connect client", () => MultiplayerClient.Connect());
assertButtonEnableState(true);
}

View File

@ -53,19 +53,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
Type = { Value = MatchType.HeadToHead },
Playlist =
{
new PlaylistItem
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo)
{
Beatmap =
BeatmapInfo =
{
Value = new TestBeatmap(new OsuRuleset().RulesetInfo)
{
BeatmapInfo =
{
StarRating = 2.5
}
}.BeatmapInfo,
StarRating = 2.5
}
}
}.BeatmapInfo)
}
}),
createLoungeRoom(new Room
@ -76,26 +70,20 @@ namespace osu.Game.Tests.Visual.Multiplayer
Type = { Value = MatchType.HeadToHead },
Playlist =
{
new PlaylistItem
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo)
{
Beatmap =
BeatmapInfo =
{
Value = new TestBeatmap(new OsuRuleset().RulesetInfo)
StarRating = 2.5,
Metadata =
{
BeatmapInfo =
{
StarRating = 2.5,
Metadata =
{
Artist = "very very very very very very very very very long artist",
ArtistUnicode = "very very very very very very very very very long artist",
Title = "very very very very very very very very very very very long title",
TitleUnicode = "very very very very very very very very very very very long title",
}
}
}.BeatmapInfo,
Artist = "very very very very very very very very very long artist",
ArtistUnicode = "very very very very very very very very very long artist",
Title = "very very very very very very very very very very very long title",
TitleUnicode = "very very very very very very very very very very very long title",
}
}
}
}.BeatmapInfo)
}
}),
createLoungeRoom(new Room
@ -105,32 +93,20 @@ namespace osu.Game.Tests.Visual.Multiplayer
EndDate = { Value = DateTimeOffset.Now.AddDays(1) },
Playlist =
{
new PlaylistItem
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo)
{
Beatmap =
BeatmapInfo =
{
Value = new TestBeatmap(new OsuRuleset().RulesetInfo)
{
BeatmapInfo =
{
StarRating = 2.5
}
}.BeatmapInfo,
StarRating = 2.5
}
},
new PlaylistItem
}.BeatmapInfo),
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo)
{
Beatmap =
BeatmapInfo =
{
Value = new TestBeatmap(new OsuRuleset().RulesetInfo)
{
BeatmapInfo =
{
StarRating = 4.5
}
}.BeatmapInfo,
StarRating = 4.5
}
}
}.BeatmapInfo)
}
}),
createLoungeRoom(new Room

View File

@ -17,6 +17,7 @@ using osu.Game.Beatmaps.Drawables;
using osu.Game.Database;
using osu.Game.Graphics.Containers;
using osu.Game.Models;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
@ -29,20 +30,17 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneDrawableRoomPlaylist : OsuManualInputManagerTestScene
public class TestSceneDrawableRoomPlaylist : MultiplayerTestScene
{
private TestPlaylist playlist;
private BeatmapManager manager;
private RulesetStore rulesets;
[Cached(typeof(UserLookupCache))]
private readonly TestUserLookupCache userLookupCache = new TestUserLookupCache();
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(Realm));
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
}
@ -170,7 +168,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
assertDownloadButtonVisible(false);
void assertDownloadButtonVisible(bool visible) => AddUntilStep($"download button {(visible ? "shown" : "hidden")}",
() => playlist.ChildrenOfType<BeatmapDownloadButton>().Single().Alpha == (visible ? 1 : 0));
() => playlist.ChildrenOfType<BeatmapDownloadButton>().SingleOrDefault()?.Alpha == (visible ? 1 : 0));
}
[Test]
@ -211,29 +209,27 @@ namespace osu.Game.Tests.Visual.Multiplayer
Size = new Vector2(500, 300),
Items =
{
new PlaylistItem
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
ID = 0,
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
Expired = true,
RequiredMods =
RequiredMods = new[]
{
new OsuModHardRock(),
new OsuModDoubleTime(),
new OsuModAutoplay()
new APIMod(new OsuModHardRock()),
new APIMod(new OsuModDoubleTime()),
new APIMod(new OsuModAutoplay())
}
},
new PlaylistItem
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
ID = 1,
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RequiredMods =
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
RequiredMods = new[]
{
new OsuModHardRock(),
new OsuModDoubleTime(),
new OsuModAutoplay()
new APIMod(new OsuModHardRock()),
new APIMod(new OsuModDoubleTime()),
new APIMod(new OsuModAutoplay())
}
}
}
@ -264,7 +260,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
private void moveToItem(int index, Vector2? offset = null)
=> AddStep($"move mouse to item {index}", () => InputManager.MoveMouseTo(playlist.ChildrenOfType<DifficultyIcon>().ElementAt(index), offset));
=> AddStep($"move mouse to item {index}", () => InputManager.MoveMouseTo(playlist.ChildrenOfType<DrawableRoomPlaylistItem>().ElementAt(index), offset));
private void moveToDragger(int index, Vector2? offset = null) => AddStep($"move mouse to dragger {index}", () =>
{
@ -295,31 +291,27 @@ namespace osu.Game.Tests.Visual.Multiplayer
for (int i = 0; i < 20; i++)
{
playlist.Items.Add(new PlaylistItem
playlist.Items.Add(new PlaylistItem(i % 2 == 1
? new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo
: new BeatmapInfo
{
Metadata = new BeatmapMetadata
{
Artist = "Artist",
Author = new RealmUser { Username = "Creator name here" },
Title = "Long title used to check background colour",
},
BeatmapSet = new BeatmapSetInfo()
})
{
ID = i,
OwnerID = 2,
Beatmap =
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
RequiredMods = new[]
{
Value = i % 2 == 1
? new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo
: new BeatmapInfo
{
Metadata = new BeatmapMetadata
{
Artist = "Artist",
Author = new RealmUser { Username = "Creator name here" },
Title = "Long title used to check background colour",
},
BeatmapSet = new BeatmapSetInfo()
}
},
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RequiredMods =
{
new OsuModHardRock(),
new OsuModDoubleTime(),
new OsuModAutoplay()
new APIMod(new OsuModHardRock()),
new APIMod(new OsuModDoubleTime()),
new APIMod(new OsuModAutoplay())
}
});
}
@ -343,17 +335,16 @@ namespace osu.Game.Tests.Visual.Multiplayer
foreach (var b in beatmaps())
{
playlist.Items.Add(new PlaylistItem
playlist.Items.Add(new PlaylistItem(b)
{
ID = index++,
OwnerID = 2,
Beatmap = { Value = b },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RequiredMods =
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
RequiredMods = new[]
{
new OsuModHardRock(),
new OsuModDoubleTime(),
new OsuModAutoplay()
new APIMod(new OsuModHardRock()),
new APIMod(new OsuModDoubleTime()),
new APIMod(new OsuModAutoplay())
}
});
}

View File

@ -4,6 +4,7 @@
using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Extensions;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
@ -21,7 +22,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestFirstItemSelectedByDefault()
{
AddAssert("first item selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[0].ID);
AddAssert("first item selected", () => MultiplayerClient.Room?.Settings.PlaylistItemId == MultiplayerClient.APIRoom?.Playlist[0].ID);
}
[Test]
@ -29,7 +30,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
selectNewItem(() => InitialBeatmap);
AddAssert("playlist item still selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[0].ID);
AddAssert("playlist item still selected", () => MultiplayerClient.Room?.Settings.PlaylistItemId == MultiplayerClient.APIRoom?.Playlist[0].ID);
}
[Test]
@ -37,7 +38,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
selectNewItem(() => OtherBeatmap);
AddAssert("playlist item still selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[0].ID);
AddAssert("playlist item still selected", () => MultiplayerClient.Room?.Settings.PlaylistItemId == MultiplayerClient.APIRoom?.Playlist[0].ID);
}
[Test]
@ -45,10 +46,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
RunGameplay();
AddAssert("playlist contains two items", () => Client.APIRoom?.Playlist.Count == 2);
AddAssert("first playlist item expired", () => Client.APIRoom?.Playlist[0].Expired == true);
AddAssert("second playlist item not expired", () => Client.APIRoom?.Playlist[1].Expired == false);
AddAssert("second playlist item selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[1].ID);
AddAssert("playlist contains two items", () => MultiplayerClient.APIRoom?.Playlist.Count == 2);
AddAssert("first playlist item expired", () => MultiplayerClient.APIRoom?.Playlist[0].Expired == true);
AddAssert("second playlist item not expired", () => MultiplayerClient.APIRoom?.Playlist[1].Expired == false);
AddAssert("second playlist item selected", () => MultiplayerClient.Room?.Settings.PlaylistItemId == MultiplayerClient.APIRoom?.Playlist[1].ID);
}
[Test]
@ -57,23 +58,23 @@ namespace osu.Game.Tests.Visual.Multiplayer
RunGameplay();
IBeatmapInfo firstBeatmap = null;
AddStep("get first playlist item beatmap", () => firstBeatmap = Client.APIRoom?.Playlist[0].Beatmap.Value);
AddStep("get first playlist item beatmap", () => firstBeatmap = MultiplayerClient.APIRoom?.Playlist[0].Beatmap);
selectNewItem(() => OtherBeatmap);
AddAssert("first playlist item hasn't changed", () => Client.APIRoom?.Playlist[0].Beatmap.Value == firstBeatmap);
AddAssert("second playlist item changed", () => Client.APIRoom?.Playlist[1].Beatmap.Value != firstBeatmap);
AddAssert("first playlist item hasn't changed", () => MultiplayerClient.APIRoom?.Playlist[0].Beatmap == firstBeatmap);
AddAssert("second playlist item changed", () => MultiplayerClient.APIRoom?.Playlist[1].Beatmap != firstBeatmap);
}
[Test]
public void TestSettingsUpdatedWhenChangingQueueMode()
{
AddStep("change queue mode", () => Client.ChangeSettings(new MultiplayerRoomSettings
AddStep("change queue mode", () => MultiplayerClient.ChangeSettings(new MultiplayerRoomSettings
{
QueueMode = QueueMode.AllPlayers
}));
}).WaitSafely());
AddUntilStep("api room updated", () => Client.APIRoom?.QueueMode.Value == QueueMode.AllPlayers);
AddUntilStep("api room updated", () => MultiplayerClient.APIRoom?.QueueMode.Value == QueueMode.AllPlayers);
}
[Test]
@ -81,7 +82,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
addItem(() => OtherBeatmap);
AddAssert("playlist contains two items", () => Client.APIRoom?.Playlist.Count == 2);
AddAssert("playlist contains two items", () => MultiplayerClient.APIRoom?.Playlist.Count == 2);
}
private void selectNewItem(Func<BeatmapInfo> beatmap)
@ -104,7 +105,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("select other beatmap", () => ((Screens.Select.SongSelect)CurrentSubScreen).FinaliseSelection(otherBeatmap = beatmap()));
AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen);
AddUntilStep("selected item is new beatmap", () => (CurrentSubScreen as MultiplayerMatchSubScreen)?.SelectedItem.Value?.BeatmapID == otherBeatmap.OnlineID);
AddUntilStep("selected item is new beatmap", () => (CurrentSubScreen as MultiplayerMatchSubScreen)?.SelectedItem.Value?.Beatmap.OnlineID == otherBeatmap.OnlineID);
}
private void addItem(Func<BeatmapInfo> beatmap)

View File

@ -44,15 +44,20 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestBasicListChanges()
{
AddStep("add rooms", () => RoomManager.AddRooms(3));
AddStep("add rooms", () => RoomManager.AddRooms(5, withSpotlightRooms: true));
AddAssert("has 3 rooms", () => container.Rooms.Count == 3);
AddStep("remove first room", () => RoomManager.RemoveRoom(RoomManager.Rooms.FirstOrDefault()));
AddAssert("has 2 rooms", () => container.Rooms.Count == 2);
AddAssert("has 5 rooms", () => container.Rooms.Count == 5);
AddAssert("all spotlights at top", () => container.Rooms
.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)));
AddAssert("has 4 rooms", () => container.Rooms.Count == 4);
AddAssert("first room removed", () => container.Rooms.All(r => r.Room.RoomID.Value != 0));
AddStep("select first room", () => container.Rooms.First().TriggerClick());
AddAssert("first room selected", () => checkRoomSelected(RoomManager.Rooms.First()));
AddAssert("first spotlight selected", () => checkRoomSelected(RoomManager.Rooms.First(r => r.Category.Value == RoomCategory.Spotlight)));
}
[Test]

View File

@ -3,6 +3,7 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
@ -31,16 +32,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void createNewItem()
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
ID = SelectedRoom.Value.Playlist.Count,
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RequiredMods =
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
RequiredMods = new[]
{
new OsuModHardRock(),
new OsuModDoubleTime(),
new OsuModAutoplay()
new APIMod(new OsuModHardRock()),
new APIMod(new OsuModDoubleTime()),
new APIMod(new OsuModAutoplay())
}
});
}

View File

@ -34,8 +34,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
foreach ((int userId, var _) in clocks)
{
SpectatorClient.StartPlay(userId, 0);
OnlinePlayDependencies.Client.AddUser(new APIUser { Id = userId });
SpectatorClient.SendStartPlay(userId, 0);
OnlinePlayDependencies.MultiplayerClient.AddUser(new APIUser { Id = userId });
}
});
@ -68,10 +68,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
// For player 2, send frames in sets of 10.
for (int i = 0; i < 100; i++)
{
SpectatorClient.SendFrames(PLAYER_1_ID, 1);
SpectatorClient.SendFramesFromUser(PLAYER_1_ID, 1);
if (i % 10 == 0)
SpectatorClient.SendFrames(PLAYER_2_ID, 10);
SpectatorClient.SendFramesFromUser(PLAYER_2_ID, 10);
}
});

View File

@ -15,6 +15,7 @@ using osu.Game.Configuration;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate;
using osu.Game.Screens.Play;
@ -60,8 +61,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("start players silently", () =>
{
OnlinePlayDependencies.Client.AddUser(new APIUser { Id = PLAYER_1_ID }, true);
OnlinePlayDependencies.Client.AddUser(new APIUser { Id = PLAYER_2_ID }, true);
OnlinePlayDependencies.MultiplayerClient.AddUser(new APIUser { Id = PLAYER_1_ID }, true);
OnlinePlayDependencies.MultiplayerClient.AddUser(new APIUser { Id = PLAYER_2_ID }, true);
playingUsers.Add(new MultiplayerRoomUser(PLAYER_1_ID));
playingUsers.Add(new MultiplayerRoomUser(PLAYER_2_ID));
@ -70,11 +71,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
loadSpectateScreen(false);
AddWaitStep("wait a bit", 10);
AddStep("load player first_player_id", () => SpectatorClient.StartPlay(PLAYER_1_ID, importedBeatmapId));
AddStep("load player first_player_id", () => SpectatorClient.SendStartPlay(PLAYER_1_ID, importedBeatmapId));
AddUntilStep("one player added", () => spectatorScreen.ChildrenOfType<Player>().Count() == 1);
AddWaitStep("wait a bit", 10);
AddStep("load player second_player_id", () => SpectatorClient.StartPlay(PLAYER_2_ID, importedBeatmapId));
AddStep("load player second_player_id", () => SpectatorClient.SendStartPlay(PLAYER_2_ID, importedBeatmapId));
AddUntilStep("two players added", () => spectatorScreen.ChildrenOfType<Player>().Count() == 2);
}
@ -121,20 +122,20 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("start players", () =>
{
var player1 = OnlinePlayDependencies.Client.AddUser(new APIUser { Id = PLAYER_1_ID }, true);
var player1 = OnlinePlayDependencies.MultiplayerClient.AddUser(new APIUser { Id = PLAYER_1_ID }, true);
player1.MatchState = new TeamVersusUserState
{
TeamID = 0,
};
var player2 = OnlinePlayDependencies.Client.AddUser(new APIUser { Id = PLAYER_2_ID }, true);
var player2 = OnlinePlayDependencies.MultiplayerClient.AddUser(new APIUser { Id = PLAYER_2_ID }, true);
player2.MatchState = new TeamVersusUserState
{
TeamID = 1,
};
SpectatorClient.StartPlay(player1.UserID, importedBeatmapId);
SpectatorClient.StartPlay(player2.UserID, importedBeatmapId);
SpectatorClient.SendStartPlay(player1.UserID, importedBeatmapId);
SpectatorClient.SendStartPlay(player2.UserID, importedBeatmapId);
playingUsers.Add(player1);
playingUsers.Add(player2);
@ -360,7 +361,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
// to ensure negative gameplay start time does not affect spectator, send frames exactly after StartGameplay().
// (similar to real spectating sessions in which the first frames get sent between StartGameplay() and player load complete)
AddStep("send frames at gameplay start", () => getInstance(PLAYER_1_ID).OnGameplayStarted += () => SpectatorClient.SendFrames(PLAYER_1_ID, 100));
AddStep("send frames at gameplay start", () => getInstance(PLAYER_1_ID).OnGameplayStarted += () => SpectatorClient.SendFramesFromUser(PLAYER_1_ID, 100));
AddUntilStep("wait for player load", () => spectatorScreen.AllPlayersLoaded);
@ -377,7 +378,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Beatmap.Value = beatmapManager.GetWorkingBeatmap(importedBeatmap);
Ruleset.Value = importedBeatmap.Ruleset;
LoadScreen(spectatorScreen = new TestMultiSpectatorScreen(playingUsers.ToArray(), gameplayStartTime));
LoadScreen(spectatorScreen = new TestMultiSpectatorScreen(SelectedRoom.Value, playingUsers.ToArray(), gameplayStartTime));
});
AddUntilStep("wait for screen load", () => spectatorScreen.LoadState == LoadState.Loaded && (!waitForPlayerLoad || spectatorScreen.AllPlayersLoaded));
@ -396,8 +397,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
User = new APIUser { Id = id },
};
OnlinePlayDependencies.Client.AddUser(user.User, true);
SpectatorClient.StartPlay(id, beatmapId ?? importedBeatmapId);
OnlinePlayDependencies.MultiplayerClient.AddUser(user.User, true);
SpectatorClient.SendStartPlay(id, beatmapId ?? importedBeatmapId);
playingUsers.Add(user);
}
@ -410,8 +411,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
var user = playingUsers.Single(u => u.UserID == userId);
OnlinePlayDependencies.Client.RemoveUser(user.User.AsNonNull());
SpectatorClient.EndPlay(userId);
OnlinePlayDependencies.MultiplayerClient.RemoveUser(user.User.AsNonNull());
SpectatorClient.SendEndPlay(userId);
playingUsers.Remove(user);
});
@ -424,7 +425,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("send frames", () =>
{
foreach (int id in userIds)
SpectatorClient.SendFrames(id, count);
SpectatorClient.SendFramesFromUser(id, count);
});
}
@ -465,8 +466,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
private readonly double? gameplayStartTime;
public TestMultiSpectatorScreen(MultiplayerRoomUser[] users, double? gameplayStartTime = null)
: base(users)
public TestMultiSpectatorScreen(Room room, MultiplayerRoomUser[] users, double? gameplayStartTime = null)
: base(room, users)
{
this.gameplayStartTime = gameplayStartTime;
}

View File

@ -17,8 +17,8 @@ using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
@ -52,16 +52,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
private TestMultiplayerComponents multiplayerComponents;
private TestMultiplayerClient client => multiplayerComponents.Client;
private TestMultiplayerClient multiplayerClient => multiplayerComponents.MultiplayerClient;
private TestMultiplayerRoomManager roomManager => multiplayerComponents.RoomManager;
[Cached(typeof(UserLookupCache))]
private UserLookupCache lookupCache = new TestUserLookupCache();
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(Realm));
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, API, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
}
@ -96,10 +93,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
});
@ -112,66 +108,66 @@ namespace osu.Game.Tests.Visual.Multiplayer
// all ready
AddUntilStep("all players ready", () =>
{
var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle);
var nextUnready = multiplayerClient.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle);
if (nextUnready != null)
client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready);
multiplayerClient.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready);
return client.Room?.Users.All(u => u.State == MultiplayerUserState.Ready) == true;
return multiplayerClient.Room?.Users.All(u => u.State == MultiplayerUserState.Ready) == true;
});
AddStep("unready all players at once", () =>
{
Debug.Assert(client.Room != null);
Debug.Assert(multiplayerClient.Room != null);
foreach (var u in client.Room.Users) client.ChangeUserState(u.UserID, MultiplayerUserState.Idle);
foreach (var u in multiplayerClient.Room.Users) multiplayerClient.ChangeUserState(u.UserID, MultiplayerUserState.Idle);
});
AddStep("ready all players at once", () =>
{
Debug.Assert(client.Room != null);
Debug.Assert(multiplayerClient.Room != null);
foreach (var u in client.Room.Users) client.ChangeUserState(u.UserID, MultiplayerUserState.Ready);
foreach (var u in multiplayerClient.Room.Users) multiplayerClient.ChangeUserState(u.UserID, MultiplayerUserState.Ready);
});
}
private void addRandomPlayer()
{
int randomUser = RNG.Next(200000, 500000);
client.AddUser(new APIUser { Id = randomUser, Username = $"user {randomUser}" });
multiplayerClient.AddUser(new APIUser { Id = randomUser, Username = $"user {randomUser}" });
}
private void removeLastUser()
{
APIUser lastUser = client.Room?.Users.Last().User;
APIUser lastUser = multiplayerClient.Room?.Users.Last().User;
if (lastUser == null || lastUser == client.LocalUser?.User)
if (lastUser == null || lastUser == multiplayerClient.LocalUser?.User)
return;
client.RemoveUser(lastUser);
multiplayerClient.RemoveUser(lastUser);
}
private void kickLastUser()
{
APIUser lastUser = client.Room?.Users.Last().User;
APIUser lastUser = multiplayerClient.Room?.Users.Last().User;
if (lastUser == null || lastUser == client.LocalUser?.User)
if (lastUser == null || lastUser == multiplayerClient.LocalUser?.User)
return;
client.KickUser(lastUser.Id);
multiplayerClient.KickUser(lastUser.Id);
}
private void markNextPlayerReady()
{
var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle);
var nextUnready = multiplayerClient.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle);
if (nextUnready != null)
client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready);
multiplayerClient.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready);
}
private void markNextPlayerIdle()
{
var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Ready);
var nextUnready = multiplayerClient.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Ready);
if (nextUnready != null)
client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Idle);
multiplayerClient.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Idle);
}
private void performRandomAction()
@ -221,7 +217,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("Press select", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
AddUntilStep("wait for join", () => client.RoomJoined);
AddUntilStep("wait for join", () => multiplayerClient.RoomJoined);
}
[Test]
@ -232,16 +228,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
});
AddAssert("Check participant count correct", () => client.APIRoom?.ParticipantCount.Value == 1);
AddAssert("Check participant list contains user", () => client.APIRoom?.RecentParticipants.Count(u => u.Id == API.LocalUser.Value.Id) == 1);
AddAssert("Check participant count correct", () => multiplayerClient.APIRoom?.ParticipantCount.Value == 1);
AddAssert("Check participant list contains user", () => multiplayerClient.APIRoom?.RecentParticipants.Count(u => u.Id == API.LocalUser.Value.Id) == 1);
}
[Test]
@ -254,10 +249,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
}, API.LocalUser.Value);
@ -284,10 +278,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
}, API.LocalUser.Value);
@ -300,10 +293,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("join room", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
AddUntilStep("wait for join", () => client.RoomJoined);
AddUntilStep("wait for join", () => multiplayerClient.RoomJoined);
AddAssert("Check participant count correct", () => client.APIRoom?.ParticipantCount.Value == 1);
AddAssert("Check participant list contains user", () => client.APIRoom?.RecentParticipants.Count(u => u.Id == API.LocalUser.Value.Id) == 1);
AddAssert("Check participant count correct", () => multiplayerClient.APIRoom?.ParticipantCount.Value == 1);
AddAssert("Check participant list contains user", () => multiplayerClient.APIRoom?.RecentParticipants.Count(u => u.Id == API.LocalUser.Value.Id) == 1);
}
[Test]
@ -315,15 +308,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
Password = { Value = "password" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
});
AddAssert("room has password", () => client.APIRoom?.Password.Value == "password");
AddAssert("room has password", () => multiplayerClient.APIRoom?.Password.Value == "password");
}
[Test]
@ -337,10 +329,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
Password = { Value = "password" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
}, API.LocalUser.Value);
@ -358,7 +349,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType<OsuButton>().First().TriggerClick());
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
AddUntilStep("wait for join", () => client.RoomJoined);
AddUntilStep("wait for join", () => multiplayerClient.RoomJoined);
}
[Test]
@ -370,16 +361,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
Password = { Value = "password" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
});
AddStep("change password", () => client.ChangeSettings(password: "password2"));
AddUntilStep("local password changed", () => client.APIRoom?.Password.Value == "password2");
AddStep("change password", () => multiplayerClient.ChangeSettings(password: "password2"));
AddUntilStep("local password changed", () => multiplayerClient.APIRoom?.Password.Value == "password2");
}
[Test]
@ -390,10 +380,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
});
@ -401,7 +390,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
pressReadyButton();
AddStep("delete beatmap", () => beatmaps.Delete(importedSet));
AddUntilStep("user state is idle", () => client.LocalUser?.State == MultiplayerUserState.Idle);
AddUntilStep("user state is idle", () => multiplayerClient.LocalUser?.State == MultiplayerUserState.Idle);
}
[Test]
@ -412,10 +401,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
});
@ -425,22 +413,22 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("Enter song select", () =>
{
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen;
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(client.Room?.Settings.PlaylistItemId);
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(multiplayerClient.Room?.Settings.PlaylistItemId);
});
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
AddAssert("Beatmap matches current item", () => Beatmap.Value.BeatmapInfo.OnlineID == client.Room?.Playlist.First().BeatmapID);
AddAssert("Beatmap matches current item", () => Beatmap.Value.BeatmapInfo.OnlineID == multiplayerClient.Room?.Playlist.First().BeatmapID);
AddStep("Select next beatmap", () => InputManager.Key(Key.Down));
AddUntilStep("Beatmap doesn't match current item", () => Beatmap.Value.BeatmapInfo.OnlineID != client.Room?.Playlist.First().BeatmapID);
AddUntilStep("Beatmap doesn't match current item", () => Beatmap.Value.BeatmapInfo.OnlineID != multiplayerClient.Room?.Playlist.First().BeatmapID);
AddStep("start match externally", () => client.StartMatch());
AddStep("start match externally", () => multiplayerClient.StartMatch());
AddUntilStep("play started", () => multiplayerComponents.CurrentScreen is Player);
AddAssert("Beatmap matches current item", () => Beatmap.Value.BeatmapInfo.OnlineID == client.Room?.Playlist.First().BeatmapID);
AddAssert("Beatmap matches current item", () => Beatmap.Value.BeatmapInfo.OnlineID == multiplayerClient.Room?.Playlist.First().BeatmapID);
}
[Test]
@ -451,10 +439,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
});
@ -464,22 +451,22 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("Enter song select", () =>
{
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen;
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(client.Room?.Settings.PlaylistItemId);
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(multiplayerClient.Room?.Settings.PlaylistItemId);
});
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
AddAssert("Ruleset matches current item", () => Ruleset.Value.OnlineID == client.Room?.Playlist.First().RulesetID);
AddAssert("Ruleset matches current item", () => Ruleset.Value.OnlineID == multiplayerClient.Room?.Playlist.First().RulesetID);
AddStep("Switch ruleset", () => ((MultiplayerMatchSongSelect)multiplayerComponents.MultiplayerScreen.CurrentSubScreen).Ruleset.Value = new CatchRuleset().RulesetInfo);
AddUntilStep("Ruleset doesn't match current item", () => Ruleset.Value.OnlineID != client.Room?.Playlist.First().RulesetID);
AddUntilStep("Ruleset doesn't match current item", () => Ruleset.Value.OnlineID != multiplayerClient.Room?.Playlist.First().RulesetID);
AddStep("start match externally", () => client.StartMatch());
AddStep("start match externally", () => multiplayerClient.StartMatch());
AddUntilStep("play started", () => multiplayerComponents.CurrentScreen is Player);
AddAssert("Ruleset matches current item", () => Ruleset.Value.OnlineID == client.Room?.Playlist.First().RulesetID);
AddAssert("Ruleset matches current item", () => Ruleset.Value.OnlineID == multiplayerClient.Room?.Playlist.First().RulesetID);
}
[Test]
@ -490,10 +477,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
});
@ -503,22 +489,22 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("Enter song select", () =>
{
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen;
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(client.Room?.Settings.PlaylistItemId);
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(multiplayerClient.Room?.Settings.PlaylistItemId);
});
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
AddAssert("Mods match current item", () => SelectedMods.Value.Select(m => m.Acronym).SequenceEqual(client.Room.AsNonNull().Playlist.First().RequiredMods.Select(m => m.Acronym)));
AddAssert("Mods match current item", () => SelectedMods.Value.Select(m => m.Acronym).SequenceEqual(multiplayerClient.Room.AsNonNull().Playlist.First().RequiredMods.Select(m => m.Acronym)));
AddStep("Switch required mods", () => ((MultiplayerMatchSongSelect)multiplayerComponents.MultiplayerScreen.CurrentSubScreen).Mods.Value = new Mod[] { new OsuModDoubleTime() });
AddAssert("Mods don't match current item", () => !SelectedMods.Value.Select(m => m.Acronym).SequenceEqual(client.Room.AsNonNull().Playlist.First().RequiredMods.Select(m => m.Acronym)));
AddAssert("Mods don't match current item", () => !SelectedMods.Value.Select(m => m.Acronym).SequenceEqual(multiplayerClient.Room.AsNonNull().Playlist.First().RequiredMods.Select(m => m.Acronym)));
AddStep("start match externally", () => client.StartMatch());
AddStep("start match externally", () => multiplayerClient.StartMatch());
AddUntilStep("play started", () => multiplayerComponents.CurrentScreen is Player);
AddAssert("Mods match current item", () => SelectedMods.Value.Select(m => m.Acronym).SequenceEqual(client.Room.AsNonNull().Playlist.First().RequiredMods.Select(m => m.Acronym)));
AddAssert("Mods match current item", () => SelectedMods.Value.Select(m => m.Acronym).SequenceEqual(multiplayerClient.Room.AsNonNull().Playlist.First().RequiredMods.Select(m => m.Acronym)));
}
[Test]
@ -529,28 +515,27 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
});
AddStep("join other user (ready, host)", () =>
{
client.AddUser(new APIUser { Id = MultiplayerTestScene.PLAYER_1_ID, Username = "Other" });
client.TransferHost(MultiplayerTestScene.PLAYER_1_ID);
client.ChangeUserState(MultiplayerTestScene.PLAYER_1_ID, MultiplayerUserState.Ready);
multiplayerClient.AddUser(new APIUser { Id = MultiplayerTestScene.PLAYER_1_ID, Username = "Other" });
multiplayerClient.TransferHost(MultiplayerTestScene.PLAYER_1_ID);
multiplayerClient.ChangeUserState(MultiplayerTestScene.PLAYER_1_ID, MultiplayerUserState.Ready);
});
AddStep("delete beatmap", () => beatmaps.Delete(importedSet));
ClickButtonWhenEnabled<MultiplayerSpectateButton>();
AddUntilStep("wait for spectating user state", () => client.LocalUser?.State == MultiplayerUserState.Spectating);
AddUntilStep("wait for spectating user state", () => multiplayerClient.LocalUser?.State == MultiplayerUserState.Spectating);
AddStep("start match externally", () => client.StartMatch());
AddStep("start match externally", () => multiplayerClient.StartMatch());
AddAssert("play not started", () => multiplayerComponents.IsCurrentScreen());
}
@ -563,10 +548,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
});
@ -575,16 +559,16 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("join other user (ready, host)", () =>
{
client.AddUser(new APIUser { Id = MultiplayerTestScene.PLAYER_1_ID, Username = "Other" });
client.TransferHost(MultiplayerTestScene.PLAYER_1_ID);
client.ChangeUserState(MultiplayerTestScene.PLAYER_1_ID, MultiplayerUserState.Ready);
multiplayerClient.AddUser(new APIUser { Id = MultiplayerTestScene.PLAYER_1_ID, Username = "Other" });
multiplayerClient.TransferHost(MultiplayerTestScene.PLAYER_1_ID);
multiplayerClient.ChangeUserState(MultiplayerTestScene.PLAYER_1_ID, MultiplayerUserState.Ready);
});
ClickButtonWhenEnabled<MultiplayerSpectateButton>();
AddUntilStep("wait for spectating user state", () => client.LocalUser?.State == MultiplayerUserState.Spectating);
AddUntilStep("wait for spectating user state", () => multiplayerClient.LocalUser?.State == MultiplayerUserState.Spectating);
AddStep("start match externally", () => client.StartMatch());
AddStep("start match externally", () => multiplayerClient.StartMatch());
AddStep("restore beatmap", () =>
{
@ -603,15 +587,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
});
AddStep("disconnect", () => client.Disconnect());
AddStep("disconnect", () => multiplayerClient.Disconnect());
AddUntilStep("back in lounge", () => this.ChildrenOfType<LoungeSubScreen>().FirstOrDefault()?.IsCurrentScreen() == true);
}
@ -623,11 +606,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
AllowedMods = { new OsuModHidden() }
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
AllowedMods = new[] { new APIMod(new OsuModHidden()) }
}
}
});
@ -663,10 +645,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
});
@ -694,10 +675,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
QueueMode = { Value = QueueMode.AllPlayers },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
}, API.LocalUser.Value);
@ -711,17 +691,16 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("change server-side settings", () =>
{
roomManager.ServerSideRooms[0].Name.Value = "New name";
roomManager.ServerSideRooms[0].Playlist.Add(new PlaylistItem
roomManager.ServerSideRooms[0].Playlist.Add(new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
ID = 2,
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
});
});
AddStep("join room", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
AddUntilStep("wait for join", () => client.RoomJoined);
AddUntilStep("wait for join", () => multiplayerClient.RoomJoined);
AddAssert("local room has correct settings", () =>
{
@ -740,19 +719,18 @@ namespace osu.Game.Tests.Visual.Multiplayer
QueueMode = { Value = QueueMode.AllPlayers },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
});
AddStep("set spectating state", () => client.ChangeUserState(API.LocalUser.Value.OnlineID, MultiplayerUserState.Spectating));
AddUntilStep("state set to spectating", () => client.LocalUser?.State == MultiplayerUserState.Spectating);
AddStep("set spectating state", () => multiplayerClient.ChangeUserState(API.LocalUser.Value.OnlineID, MultiplayerUserState.Spectating));
AddUntilStep("state set to spectating", () => multiplayerClient.LocalUser?.State == MultiplayerUserState.Spectating);
AddStep("join other user", () => client.AddUser(new APIUser { Id = 1234 }));
AddStep("set other user ready", () => client.ChangeUserState(1234, MultiplayerUserState.Ready));
AddStep("join other user", () => multiplayerClient.AddUser(new APIUser { Id = 1234 }));
AddStep("set other user ready", () => multiplayerClient.ChangeUserState(1234, MultiplayerUserState.Ready));
pressReadyButton(1234);
AddUntilStep("wait for gameplay", () => (multiplayerComponents.CurrentScreen as MultiSpectatorScreen)?.IsLoaded == true);
@ -764,7 +742,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
});
AddUntilStep("wait for return to match subscreen", () => multiplayerComponents.MultiplayerScreen.IsCurrentScreen());
AddUntilStep("user state is idle", () => client.LocalUser?.State == MultiplayerUserState.Idle);
AddUntilStep("user state is idle", () => multiplayerClient.LocalUser?.State == MultiplayerUserState.Idle);
}
[Test]
@ -776,24 +754,23 @@ namespace osu.Game.Tests.Visual.Multiplayer
QueueMode = { Value = QueueMode.AllPlayers },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
});
AddStep("set spectating state", () => client.ChangeUserState(API.LocalUser.Value.OnlineID, MultiplayerUserState.Spectating));
AddUntilStep("state set to spectating", () => client.LocalUser?.State == MultiplayerUserState.Spectating);
AddStep("set spectating state", () => multiplayerClient.ChangeUserState(API.LocalUser.Value.OnlineID, MultiplayerUserState.Spectating));
AddUntilStep("state set to spectating", () => multiplayerClient.LocalUser?.State == MultiplayerUserState.Spectating);
AddStep("join other user", () => client.AddUser(new APIUser { Id = 1234 }));
AddStep("set other user ready", () => client.ChangeUserState(1234, MultiplayerUserState.Ready));
AddStep("join other user", () => multiplayerClient.AddUser(new APIUser { Id = 1234 }));
AddStep("set other user ready", () => multiplayerClient.ChangeUserState(1234, MultiplayerUserState.Ready));
pressReadyButton(1234);
AddUntilStep("wait for gameplay", () => (multiplayerComponents.CurrentScreen as MultiSpectatorScreen)?.IsLoaded == true);
AddStep("set other user loaded", () => client.ChangeUserState(1234, MultiplayerUserState.Loaded));
AddStep("set other user finished play", () => client.ChangeUserState(1234, MultiplayerUserState.FinishedPlay));
AddStep("set other user loaded", () => multiplayerClient.ChangeUserState(1234, MultiplayerUserState.Loaded));
AddStep("set other user finished play", () => multiplayerClient.ChangeUserState(1234, MultiplayerUserState.FinishedPlay));
AddStep("press back button and exit", () =>
{
@ -803,7 +780,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for return to match subscreen", () => multiplayerComponents.MultiplayerScreen.IsCurrentScreen());
AddWaitStep("wait for possible state change", 5);
AddUntilStep("user state is spectating", () => client.LocalUser?.State == MultiplayerUserState.Spectating);
AddUntilStep("user state is spectating", () => multiplayerClient.LocalUser?.State == MultiplayerUserState.Spectating);
}
[Test]
@ -815,23 +792,22 @@ namespace osu.Game.Tests.Visual.Multiplayer
QueueMode = { Value = QueueMode.AllPlayers },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
});
enterGameplay();
AddStep("join other user", () => multiplayerClient.AddUser(new APIUser { Id = 1234 }));
AddStep("add item as other user", () => multiplayerClient.AddUserPlaylistItem(1234, new MultiplayerPlaylistItem(
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
})).WaitSafely());
AddStep("join other user", () => client.AddUser(new APIUser { Id = 1234 }));
AddStep("add item as other user", () => client.AddUserPlaylistItem(1234, new MultiplayerPlaylistItem(new PlaylistItem
{
BeatmapID = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo.OnlineID
})));
AddUntilStep("item arrived in playlist", () => client.Room?.Playlist.Count == 2);
AddUntilStep("item arrived in playlist", () => multiplayerClient.Room?.Playlist.Count == 2);
AddStep("exit gameplay as initial user", () => multiplayerComponents.MultiplayerScreen.MakeCurrent());
AddUntilStep("queue contains item", () => this.ChildrenOfType<MultiplayerQueueList>().Single().Items.Single().ID == 2);
@ -846,26 +822,26 @@ namespace osu.Game.Tests.Visual.Multiplayer
QueueMode = { Value = QueueMode.AllPlayers },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
});
enterGameplay();
AddStep("join other user", () => client.AddUser(new APIUser { Id = 1234 }));
AddStep("add item as other user", () => client.AddUserPlaylistItem(1234, new MultiplayerPlaylistItem(new PlaylistItem
{
BeatmapID = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo.OnlineID
})));
AddStep("join other user", () => multiplayerClient.AddUser(new APIUser { Id = 1234 }));
AddStep("add item as other user", () => multiplayerClient.AddUserPlaylistItem(1234, new MultiplayerPlaylistItem(
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
})).WaitSafely());
AddUntilStep("item arrived in playlist", () => client.Room?.Playlist.Count == 2);
AddUntilStep("item arrived in playlist", () => multiplayerClient.Room?.Playlist.Count == 2);
AddStep("delete item as other user", () => client.RemoveUserPlaylistItem(1234, 2));
AddUntilStep("item removed from playlist", () => client.Room?.Playlist.Count == 1);
AddStep("delete item as other user", () => multiplayerClient.RemoveUserPlaylistItem(1234, 2).WaitSafely());
AddUntilStep("item removed from playlist", () => multiplayerClient.Room?.Playlist.Count == 1);
AddStep("exit gameplay as initial user", () => multiplayerComponents.MultiplayerScreen.MakeCurrent());
AddUntilStep("queue is empty", () => this.ChildrenOfType<MultiplayerQueueList>().Single().Items.Count == 0);
@ -879,27 +855,26 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
});
AddStep("join other user and make host", () =>
{
client.AddUser(new APIUser { Id = 1234 });
client.TransferHost(1234);
multiplayerClient.AddUser(new APIUser { Id = 1234 });
multiplayerClient.TransferHost(1234);
});
AddStep("set local user spectating", () => client.ChangeUserState(API.LocalUser.Value.OnlineID, MultiplayerUserState.Spectating));
AddUntilStep("wait for spectating state", () => client.LocalUser?.State == MultiplayerUserState.Spectating);
AddStep("set local user spectating", () => multiplayerClient.ChangeUserState(API.LocalUser.Value.OnlineID, MultiplayerUserState.Spectating));
AddUntilStep("wait for spectating state", () => multiplayerClient.LocalUser?.State == MultiplayerUserState.Spectating);
runGameplay();
AddStep("exit gameplay for other user", () => client.ChangeUserState(1234, MultiplayerUserState.Idle));
AddUntilStep("wait for room to be idle", () => client.Room?.State == MultiplayerRoomState.Open);
AddStep("exit gameplay for other user", () => multiplayerClient.ChangeUserState(1234, MultiplayerUserState.Idle));
AddUntilStep("wait for room to be idle", () => multiplayerClient.Room?.State == MultiplayerRoomState.Open);
runGameplay();
@ -907,13 +882,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("start match by other user", () =>
{
client.ChangeUserState(1234, MultiplayerUserState.Ready);
client.StartMatch();
multiplayerClient.ChangeUserState(1234, MultiplayerUserState.Ready);
multiplayerClient.StartMatch();
});
AddUntilStep("wait for loading", () => client.Room?.State == MultiplayerRoomState.WaitingForLoad);
AddStep("set player loaded", () => client.ChangeUserState(1234, MultiplayerUserState.Loaded));
AddUntilStep("wait for gameplay to start", () => client.Room?.State == MultiplayerRoomState.Playing);
AddUntilStep("wait for loading", () => multiplayerClient.Room?.State == MultiplayerRoomState.WaitingForLoad);
AddStep("set player loaded", () => multiplayerClient.ChangeUserState(1234, MultiplayerUserState.Loaded));
AddUntilStep("wait for gameplay to start", () => multiplayerClient.Room?.State == MultiplayerRoomState.Playing);
AddUntilStep("wait for local user to enter spectator", () => multiplayerComponents.CurrentScreen is MultiSpectatorScreen);
}
}
@ -938,7 +913,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("click ready button", () =>
{
user = playingUserId == null ? client.LocalUser : client.Room?.Users.Single(u => u.UserID == playingUserId);
user = playingUserId == null ? multiplayerClient.LocalUser : multiplayerClient.Room?.Users.Single(u => u.UserID == playingUserId);
lastState = user?.State ?? MultiplayerUserState.Idle;
InputManager.MoveMouseTo(readyButton);
@ -958,7 +933,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
AddUntilStep("wait for join", () => client.RoomJoined);
AddUntilStep("wait for join", () => multiplayerClient.RoomJoined);
}
}
}

View File

@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
base.SetUpSteps();
AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = LookupCache.GetUserAsync(1).GetResultSafely());
AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = UserLookupCache.GetUserAsync(1).GetResultSafely());
AddStep("create leaderboard", () =>
{
@ -58,8 +58,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
foreach (int user in users)
{
SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineID);
multiplayerUsers.Add(OnlinePlayDependencies.Client.AddUser(new APIUser { Id = user }, true));
SpectatorClient.SendStartPlay(user, Beatmap.Value.BeatmapInfo.OnlineID);
multiplayerUsers.Add(OnlinePlayDependencies.MultiplayerClient.AddUser(new APIUser { Id = user }, true));
}
Children = new Drawable[]
@ -77,7 +77,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
});
AddUntilStep("wait for load", () => leaderboard.IsLoaded);
AddUntilStep("wait for user population", () => Client.CurrentMatchPlayingUserIds.Count > 0);
AddUntilStep("wait for user population", () => MultiplayerClient.CurrentMatchPlayingUserIds.Count > 0);
}
[Test]
@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
public void TestUserQuit()
{
foreach (int user in users)
AddStep($"mark user {user} quit", () => Client.RemoveUser(LookupCache.GetUserAsync(user).GetResultSafely().AsNonNull()));
AddStep($"mark user {user} quit", () => MultiplayerClient.RemoveUser(UserLookupCache.GetUserAsync(user).GetResultSafely().AsNonNull()));
}
[Test]

View File

@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
base.SetUpSteps();
AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = LookupCache.GetUserAsync(1).GetResultSafely());
AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = UserLookupCache.GetUserAsync(1).GetResultSafely());
AddStep("create leaderboard", () =>
{
@ -62,8 +62,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
foreach (int user in users)
{
SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineID);
var roomUser = OnlinePlayDependencies.Client.AddUser(new APIUser { Id = user }, true);
SpectatorClient.SendStartPlay(user, Beatmap.Value.BeatmapInfo.OnlineID);
var roomUser = OnlinePlayDependencies.MultiplayerClient.AddUser(new APIUser { Id = user }, true);
roomUser.MatchState = new TeamVersusUserState
{
@ -105,7 +105,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
});
AddUntilStep("wait for load", () => leaderboard.IsLoaded);
AddUntilStep("wait for user population", () => Client.CurrentMatchPlayingUserIds.Count > 0);
AddUntilStep("wait for user population", () => MultiplayerClient.CurrentMatchPlayingUserIds.Count > 0);
}
[Test]

View File

@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(Realm));
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);

View File

@ -10,14 +10,18 @@ using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Overlays.Mods;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Taiko;
using osu.Game.Rulesets.Taiko.Mods;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.OnlinePlay.Match;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
using osu.Game.Screens.OnlinePlay.Multiplayer.Participants;
@ -42,7 +46,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(Realm));
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
@ -69,10 +73,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add playlist item", () =>
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
});
});
@ -86,11 +89,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add playlist item", () =>
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new TaikoRuleset().RulesetInfo).BeatmapInfo)
{
Beatmap = { Value = new TestBeatmap(new TaikoRuleset().RulesetInfo).BeatmapInfo },
Ruleset = { Value = new TaikoRuleset().RulesetInfo },
AllowedMods = { new TaikoModSwap() }
RulesetID = new TaikoRuleset().RulesetInfo.OnlineID,
AllowedMods = new[] { new APIMod(new TaikoModSwap()) }
});
});
@ -98,7 +100,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for join", () => RoomJoined);
AddStep("select swap mod", () => Client.ChangeUserMods(API.LocalUser.Value.OnlineID, new[] { new TaikoModSwap() }));
AddStep("select swap mod", () => MultiplayerClient.ChangeUserMods(API.LocalUser.Value.OnlineID, new[] { new TaikoModSwap() }));
AddUntilStep("participant panel has mod", () => this.ChildrenOfType<ParticipantPanel>().Any(p => p.ChildrenOfType<ModIcon>().Any(m => m.Mod is TaikoModSwap)));
}
@ -109,10 +111,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("set playlist", () =>
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
});
});
@ -124,10 +125,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("set playlist", () =>
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem
SelectedRoom.Value.Playlist.Add(new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First()).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First()).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
});
});
@ -137,17 +137,39 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("join other user (ready)", () =>
{
Client.AddUser(new APIUser { Id = PLAYER_1_ID });
Client.ChangeUserState(PLAYER_1_ID, MultiplayerUserState.Ready);
MultiplayerClient.AddUser(new APIUser { Id = PLAYER_1_ID });
MultiplayerClient.ChangeUserState(PLAYER_1_ID, MultiplayerUserState.Ready);
});
ClickButtonWhenEnabled<MultiplayerSpectateButton>();
AddUntilStep("wait for spectating user state", () => Client.LocalUser?.State == MultiplayerUserState.Spectating);
AddUntilStep("wait for spectating user state", () => MultiplayerClient.LocalUser?.State == MultiplayerUserState.Spectating);
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddUntilStep("match started", () => Client.Room?.State == MultiplayerRoomState.WaitingForLoad);
AddUntilStep("match started", () => MultiplayerClient.Room?.State == MultiplayerRoomState.WaitingForLoad);
}
[Test]
public void TestFreeModSelectionHasAllowedMods()
{
AddStep("add playlist item with allowed mod", () =>
{
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
{
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
AllowedMods = new[] { new APIMod(new OsuModDoubleTime()) }
});
});
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
AddUntilStep("wait for join", () => RoomJoined);
ClickButtonWhenEnabled<RoomSubScreen.UserModSelectButton>();
AddUntilStep("mod select contains only double time mod",
() => this.ChildrenOfType<UserModSelectOverlay>().SingleOrDefault()?.ChildrenOfType<ModButton>().SingleOrDefault()?.Mod is OsuModDoubleTime);
}
}
}

View File

@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddAssert("one unique panel", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 1);
AddStep("add user", () => Client.AddUser(new APIUser
AddStep("add user", () => MultiplayerClient.AddUser(new APIUser
{
Id = 3,
Username = "Second",
@ -50,15 +50,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddAssert("one unique panel", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 1);
AddStep("add non-resolvable user", () => Client.TestAddUnresolvedUser());
AddAssert("null user added", () => Client.Room.AsNonNull().Users.Count(u => u.User == null) == 1);
AddStep("add non-resolvable user", () => MultiplayerClient.TestAddUnresolvedUser());
AddAssert("null user added", () => MultiplayerClient.Room.AsNonNull().Users.Count(u => u.User == null) == 1);
AddUntilStep("two unique panels", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 2);
AddStep("kick null user", () => this.ChildrenOfType<ParticipantPanel>().Single(p => p.User.User == null)
.ChildrenOfType<ParticipantPanel.KickButton>().Single().TriggerClick());
AddAssert("null user kicked", () => Client.Room.AsNonNull().Users.Count == 1);
AddAssert("null user kicked", () => MultiplayerClient.Room.AsNonNull().Users.Count == 1);
}
[Test]
@ -68,7 +68,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("add a user", () =>
{
Client.AddUser(secondUser = new APIUser
MultiplayerClient.AddUser(secondUser = new APIUser
{
Id = 3,
Username = "Second",
@ -76,7 +76,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
});
});
AddStep("remove host", () => Client.RemoveUser(API.LocalUser.Value));
AddStep("remove host", () => MultiplayerClient.RemoveUser(API.LocalUser.Value));
AddAssert("single panel is for second user", () => this.ChildrenOfType<ParticipantPanel>().Single().User.User == secondUser);
}
@ -84,21 +84,21 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestGameStateHasPriorityOverDownloadState()
{
AddStep("set to downloading map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(0)));
AddStep("set to downloading map", () => MultiplayerClient.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(0)));
checkProgressBarVisibility(true);
AddStep("make user ready", () => Client.ChangeState(MultiplayerUserState.Results));
AddStep("make user ready", () => MultiplayerClient.ChangeState(MultiplayerUserState.Results));
checkProgressBarVisibility(false);
AddUntilStep("ready mark visible", () => this.ChildrenOfType<StateDisplay>().Single().IsPresent);
AddStep("make user ready", () => Client.ChangeState(MultiplayerUserState.Idle));
AddStep("make user ready", () => MultiplayerClient.ChangeState(MultiplayerUserState.Idle));
checkProgressBarVisibility(true);
}
[Test]
public void TestCorrectInitialState()
{
AddStep("set to downloading map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(0)));
AddStep("set to downloading map", () => MultiplayerClient.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(0)));
createNewParticipantsList();
checkProgressBarVisibility(true);
}
@ -106,23 +106,23 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestBeatmapDownloadingStates()
{
AddStep("set to no map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.NotDownloaded()));
AddStep("set to downloading map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(0)));
AddStep("set to no map", () => MultiplayerClient.ChangeBeatmapAvailability(BeatmapAvailability.NotDownloaded()));
AddStep("set to downloading map", () => MultiplayerClient.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(0)));
checkProgressBarVisibility(true);
AddRepeatStep("increment progress", () =>
{
float progress = this.ChildrenOfType<ParticipantPanel>().Single().User.BeatmapAvailability.DownloadProgress ?? 0;
Client.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(progress + RNG.NextSingle(0.1f)));
MultiplayerClient.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(progress + RNG.NextSingle(0.1f)));
}, 25);
AddAssert("progress bar increased", () => this.ChildrenOfType<ProgressBar>().Single().Current.Value > 0);
AddStep("set to importing map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.Importing()));
AddStep("set to importing map", () => MultiplayerClient.ChangeBeatmapAvailability(BeatmapAvailability.Importing()));
checkProgressBarVisibility(false);
AddStep("set to available", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.LocallyAvailable()));
AddStep("set to available", () => MultiplayerClient.ChangeBeatmapAvailability(BeatmapAvailability.LocallyAvailable()));
}
[Test]
@ -130,24 +130,24 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddAssert("ready mark invisible", () => !this.ChildrenOfType<StateDisplay>().Single().IsPresent);
AddStep("make user ready", () => Client.ChangeState(MultiplayerUserState.Ready));
AddStep("make user ready", () => MultiplayerClient.ChangeState(MultiplayerUserState.Ready));
AddUntilStep("ready mark visible", () => this.ChildrenOfType<StateDisplay>().Single().IsPresent);
AddStep("make user idle", () => Client.ChangeState(MultiplayerUserState.Idle));
AddStep("make user idle", () => MultiplayerClient.ChangeState(MultiplayerUserState.Idle));
AddUntilStep("ready mark invisible", () => !this.ChildrenOfType<StateDisplay>().Single().IsPresent);
}
[Test]
public void TestToggleSpectateState()
{
AddStep("make user spectating", () => Client.ChangeState(MultiplayerUserState.Spectating));
AddStep("make user idle", () => Client.ChangeState(MultiplayerUserState.Idle));
AddStep("make user spectating", () => MultiplayerClient.ChangeState(MultiplayerUserState.Spectating));
AddStep("make user idle", () => MultiplayerClient.ChangeState(MultiplayerUserState.Idle));
}
[Test]
public void TestCrownChangesStateWhenHostTransferred()
{
AddStep("add user", () => Client.AddUser(new APIUser
AddStep("add user", () => MultiplayerClient.AddUser(new APIUser
{
Id = 3,
Username = "Second",
@ -157,7 +157,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("first user crown visible", () => this.ChildrenOfType<ParticipantPanel>().ElementAt(0).ChildrenOfType<SpriteIcon>().First().Alpha == 1);
AddUntilStep("second user crown hidden", () => this.ChildrenOfType<ParticipantPanel>().ElementAt(1).ChildrenOfType<SpriteIcon>().First().Alpha == 0);
AddStep("make second user host", () => Client.TransferHost(3));
AddStep("make second user host", () => MultiplayerClient.TransferHost(3));
AddUntilStep("first user crown hidden", () => this.ChildrenOfType<ParticipantPanel>().ElementAt(0).ChildrenOfType<SpriteIcon>().First().Alpha == 0);
AddUntilStep("second user crown visible", () => this.ChildrenOfType<ParticipantPanel>().ElementAt(1).ChildrenOfType<SpriteIcon>().First().Alpha == 1);
@ -166,7 +166,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestKickButtonOnlyPresentWhenHost()
{
AddStep("add user", () => Client.AddUser(new APIUser
AddStep("add user", () => MultiplayerClient.AddUser(new APIUser
{
Id = 3,
Username = "Second",
@ -175,11 +175,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("kick buttons visible", () => this.ChildrenOfType<ParticipantPanel.KickButton>().Count(d => d.IsPresent) == 1);
AddStep("make second user host", () => Client.TransferHost(3));
AddStep("make second user host", () => MultiplayerClient.TransferHost(3));
AddUntilStep("kick buttons not visible", () => this.ChildrenOfType<ParticipantPanel.KickButton>().Count(d => d.IsPresent) == 0);
AddStep("make local user host again", () => Client.TransferHost(API.LocalUser.Value.Id));
AddStep("make local user host again", () => MultiplayerClient.TransferHost(API.LocalUser.Value.Id));
AddUntilStep("kick buttons visible", () => this.ChildrenOfType<ParticipantPanel.KickButton>().Count(d => d.IsPresent) == 1);
}
@ -187,7 +187,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestKickButtonKicks()
{
AddStep("add user", () => Client.AddUser(new APIUser
AddStep("add user", () => MultiplayerClient.AddUser(new APIUser
{
Id = 3,
Username = "Second",
@ -196,7 +196,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("kick second user", () => this.ChildrenOfType<ParticipantPanel.KickButton>().Single(d => d.IsPresent).TriggerClick());
AddAssert("second user kicked", () => Client.Room?.Users.Single().UserID == API.LocalUser.Value.Id);
AddAssert("second user kicked", () => MultiplayerClient.Room?.Users.Single().UserID == API.LocalUser.Value.Id);
}
[Test]
@ -206,7 +206,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
for (int i = 0; i < 20; i++)
{
Client.AddUser(new APIUser
MultiplayerClient.AddUser(new APIUser
{
Id = i,
Username = $"User {i}",
@ -220,7 +220,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
});
Client.ChangeUserState(i, (MultiplayerUserState)RNG.Next(0, (int)MultiplayerUserState.Results + 1));
MultiplayerClient.ChangeUserState(i, (MultiplayerUserState)RNG.Next(0, (int)MultiplayerUserState.Results + 1));
if (RNG.NextBool())
{
@ -229,15 +229,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
switch (beatmapState)
{
case DownloadState.NotDownloaded:
Client.ChangeUserBeatmapAvailability(i, BeatmapAvailability.NotDownloaded());
MultiplayerClient.ChangeUserBeatmapAvailability(i, BeatmapAvailability.NotDownloaded());
break;
case DownloadState.Downloading:
Client.ChangeUserBeatmapAvailability(i, BeatmapAvailability.Downloading(RNG.NextSingle()));
MultiplayerClient.ChangeUserBeatmapAvailability(i, BeatmapAvailability.Downloading(RNG.NextSingle()));
break;
case DownloadState.Importing:
Client.ChangeUserBeatmapAvailability(i, BeatmapAvailability.Importing());
MultiplayerClient.ChangeUserBeatmapAvailability(i, BeatmapAvailability.Importing());
break;
}
}
@ -250,7 +250,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add user", () =>
{
Client.AddUser(new APIUser
MultiplayerClient.AddUser(new APIUser
{
Id = 0,
Username = "User 0",
@ -264,7 +264,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
});
Client.ChangeUserMods(0, new Mod[]
MultiplayerClient.ChangeUserMods(0, new Mod[]
{
new OsuModHardRock(),
new OsuModDifficultyAdjust { ApproachRate = { Value = 1 } }
@ -274,12 +274,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
for (var i = MultiplayerUserState.Idle; i < MultiplayerUserState.Results; i++)
{
var state = i;
AddStep($"set state: {state}", () => Client.ChangeUserState(0, state));
AddStep($"set state: {state}", () => MultiplayerClient.ChangeUserState(0, state));
}
AddStep("set state: downloading", () => Client.ChangeUserBeatmapAvailability(0, BeatmapAvailability.Downloading(0)));
AddStep("set state: downloading", () => MultiplayerClient.ChangeUserBeatmapAvailability(0, BeatmapAvailability.Downloading(0)));
AddStep("set state: locally available", () => Client.ChangeUserBeatmapAvailability(0, BeatmapAvailability.LocallyAvailable()));
AddStep("set state: locally available", () => MultiplayerClient.ChangeUserBeatmapAvailability(0, BeatmapAvailability.LocallyAvailable()));
}
[Test]
@ -287,7 +287,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add dummy mods", () =>
{
Client.ChangeUserMods(new Mod[]
MultiplayerClient.ChangeUserMods(new Mod[]
{
new OsuModNoFail(),
new OsuModDoubleTime()
@ -296,7 +296,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("add user with mods", () =>
{
Client.AddUser(new APIUser
MultiplayerClient.AddUser(new APIUser
{
Id = 0,
Username = "Baka",
@ -309,34 +309,34 @@ namespace osu.Game.Tests.Visual.Multiplayer
},
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
});
Client.ChangeUserMods(0, new Mod[]
MultiplayerClient.ChangeUserMods(0, new Mod[]
{
new OsuModHardRock(),
new OsuModDoubleTime()
});
});
AddStep("set 0 ready", () => Client.ChangeState(MultiplayerUserState.Ready));
AddStep("set 0 ready", () => MultiplayerClient.ChangeState(MultiplayerUserState.Ready));
AddStep("set 1 spectate", () => Client.ChangeUserState(0, MultiplayerUserState.Spectating));
AddStep("set 1 spectate", () => MultiplayerClient.ChangeUserState(0, MultiplayerUserState.Spectating));
// Have to set back to idle due to status priority.
AddStep("set 0 no map, 1 ready", () =>
{
Client.ChangeState(MultiplayerUserState.Idle);
Client.ChangeBeatmapAvailability(BeatmapAvailability.NotDownloaded());
Client.ChangeUserState(0, MultiplayerUserState.Ready);
MultiplayerClient.ChangeState(MultiplayerUserState.Idle);
MultiplayerClient.ChangeBeatmapAvailability(BeatmapAvailability.NotDownloaded());
MultiplayerClient.ChangeUserState(0, MultiplayerUserState.Ready);
});
AddStep("set 0 downloading", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(0)));
AddStep("set 0 downloading", () => MultiplayerClient.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(0)));
AddStep("set 0 spectate", () => Client.ChangeUserState(0, MultiplayerUserState.Spectating));
AddStep("set 0 spectate", () => MultiplayerClient.ChangeUserState(0, MultiplayerUserState.Spectating));
AddStep("make both default", () =>
{
Client.ChangeBeatmapAvailability(BeatmapAvailability.LocallyAvailable());
Client.ChangeUserState(0, MultiplayerUserState.Idle);
Client.ChangeState(MultiplayerUserState.Idle);
MultiplayerClient.ChangeBeatmapAvailability(BeatmapAvailability.LocallyAvailable());
MultiplayerClient.ChangeUserState(0, MultiplayerUserState.Idle);
MultiplayerClient.ChangeState(MultiplayerUserState.Idle);
});
}

View File

@ -28,15 +28,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("initialise gameplay", () =>
{
Stack.Push(player = new MultiplayerPlayer(Client.APIRoom, new PlaylistItem
Stack.Push(player = new MultiplayerPlayer(MultiplayerClient.APIRoom, new PlaylistItem(Beatmap.Value.BeatmapInfo)
{
Beatmap = { Value = Beatmap.Value.BeatmapInfo },
Ruleset = { Value = Beatmap.Value.BeatmapInfo.Ruleset }
}, Client.Room?.Users.ToArray()));
RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID,
}, MultiplayerClient.Room?.Users.ToArray()));
});
AddUntilStep("wait for player to be current", () => player.IsCurrentScreen() && player.IsLoaded);
AddStep("start gameplay", () => ((IMultiplayerClient)Client).MatchStarted());
AddStep("start gameplay", () => ((IMultiplayerClient)MultiplayerClient).MatchStarted());
}
[Test]

View File

@ -33,7 +33,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(Realm));
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
}
@ -60,7 +60,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
importedBeatmap = importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0);
});
AddStep("change to all players mode", () => Client.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }));
AddStep("change to all players mode", () => MultiplayerClient.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }).WaitSafely());
}
[Test]
@ -97,19 +97,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
addItemStep();
addItemStep();
AddStep("finish current item", () => Client.FinishCurrentItem());
AddStep("finish current item", () => MultiplayerClient.FinishCurrentItem().WaitSafely());
assertItemInHistoryListStep(1, 0);
assertItemInQueueListStep(2, 0);
assertItemInQueueListStep(3, 1);
AddStep("finish current item", () => Client.FinishCurrentItem());
AddStep("finish current item", () => MultiplayerClient.FinishCurrentItem().WaitSafely());
assertItemInHistoryListStep(2, 0);
assertItemInHistoryListStep(1, 1);
assertItemInQueueListStep(3, 0);
AddStep("finish current item", () => Client.FinishCurrentItem());
AddStep("finish current item", () => MultiplayerClient.FinishCurrentItem().WaitSafely());
assertItemInHistoryListStep(3, 0);
assertItemInHistoryListStep(2, 1);
@ -120,7 +120,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
public void TestListsClearedWhenRoomLeft()
{
addItemStep();
AddStep("finish current item", () => Client.FinishCurrentItem());
AddStep("finish current item", () => MultiplayerClient.FinishCurrentItem().WaitSafely());
AddStep("leave room", () => RoomManager.PartRoom());
AddUntilStep("wait for room part", () => !RoomJoined);
@ -143,15 +143,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "test name" },
Playlist =
{
new PlaylistItem
new PlaylistItem(new TestBeatmap(Ruleset.Value).BeatmapInfo)
{
Beatmap = { Value = new TestBeatmap(Ruleset.Value).BeatmapInfo },
Ruleset = { Value = Ruleset.Value }
RulesetID = Ruleset.Value.OnlineID
},
new PlaylistItem
new PlaylistItem(new TestBeatmap(Ruleset.Value).BeatmapInfo)
{
Beatmap = { Value = new TestBeatmap(Ruleset.Value).BeatmapInfo },
Ruleset = { Value = Ruleset.Value },
RulesetID = Ruleset.Value.OnlineID,
Expired = true
}
}
@ -167,10 +165,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
/// <summary>
/// Adds a step to create a new playlist item.
/// </summary>
private void addItemStep(bool expired = false) => AddStep("add item", () => Client.AddPlaylistItem(new MultiplayerPlaylistItem(new PlaylistItem
private void addItemStep(bool expired = false) => AddStep("add item", () => MultiplayerClient.AddPlaylistItem(new MultiplayerPlaylistItem(new PlaylistItem(importedBeatmap)
{
Beatmap = { Value = importedBeatmap },
BeatmapID = importedBeatmap.OnlineID,
Expired = expired,
PlayedAt = DateTimeOffset.Now
})));

View File

@ -12,7 +12,6 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
@ -26,9 +25,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneMultiplayerQueueList : MultiplayerTestScene
{
[Cached(typeof(UserLookupCache))]
private readonly TestUserLookupCache userLookupCache = new TestUserLookupCache();
private MultiplayerQueueList playlist;
private BeatmapManager beatmaps;
private RulesetStore rulesets;
@ -38,7 +34,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(Realm));
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, API, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
}
@ -54,7 +50,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500, 300),
Items = { BindTarget = Client.APIRoom!.Playlist }
Items = { BindTarget = MultiplayerClient.APIRoom!.Playlist }
};
});
@ -65,14 +61,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
importedBeatmap = importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0);
});
AddStep("change to all players mode", () => Client.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }));
AddStep("change to all players mode", () => MultiplayerClient.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }).WaitSafely());
}
[Test]
public void TestDeleteButtonAlwaysVisibleForHost()
{
AddStep("set all players queue mode", () => Client.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }));
AddUntilStep("wait for queue mode change", () => Client.APIRoom?.QueueMode.Value == QueueMode.AllPlayers);
AddStep("set all players queue mode", () => MultiplayerClient.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }).WaitSafely());
AddUntilStep("wait for queue mode change", () => MultiplayerClient.APIRoom?.QueueMode.Value == QueueMode.AllPlayers);
addPlaylistItem(() => API.LocalUser.Value.OnlineID);
assertDeleteButtonVisibility(1, true);
@ -83,18 +79,18 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestDeleteButtonOnlyVisibleForItemOwnerIfNotHost()
{
AddStep("set all players queue mode", () => Client.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }));
AddUntilStep("wait for queue mode change", () => Client.APIRoom?.QueueMode.Value == QueueMode.AllPlayers);
AddStep("set all players queue mode", () => MultiplayerClient.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }).WaitSafely());
AddUntilStep("wait for queue mode change", () => MultiplayerClient.APIRoom?.QueueMode.Value == QueueMode.AllPlayers);
AddStep("join other user", () => Client.AddUser(new APIUser { Id = 1234 }));
AddStep("set other user as host", () => Client.TransferHost(1234));
AddStep("join other user", () => MultiplayerClient.AddUser(new APIUser { Id = 1234 }));
AddStep("set other user as host", () => MultiplayerClient.TransferHost(1234));
addPlaylistItem(() => API.LocalUser.Value.OnlineID);
assertDeleteButtonVisibility(1, true);
addPlaylistItem(() => 1234);
assertDeleteButtonVisibility(2, false);
AddStep("set local user as host", () => Client.TransferHost(API.LocalUser.Value.OnlineID));
AddStep("set local user as host", () => MultiplayerClient.TransferHost(API.LocalUser.Value.OnlineID));
assertDeleteButtonVisibility(1, true);
assertDeleteButtonVisibility(2, true);
}
@ -102,16 +98,16 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestCurrentItemDoesNotHaveDeleteButton()
{
AddStep("set all players queue mode", () => Client.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }));
AddUntilStep("wait for queue mode change", () => Client.APIRoom?.QueueMode.Value == QueueMode.AllPlayers);
AddStep("set all players queue mode", () => MultiplayerClient.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }).WaitSafely());
AddUntilStep("wait for queue mode change", () => MultiplayerClient.APIRoom?.QueueMode.Value == QueueMode.AllPlayers);
addPlaylistItem(() => API.LocalUser.Value.OnlineID);
assertDeleteButtonVisibility(0, false);
assertDeleteButtonVisibility(1, true);
AddStep("finish current item", () => Client.FinishCurrentItem());
AddUntilStep("wait for next item to be selected", () => Client.Room?.Settings.PlaylistItemId == 2);
AddStep("finish current item", () => MultiplayerClient.FinishCurrentItem().WaitSafely());
AddUntilStep("wait for next item to be selected", () => MultiplayerClient.Room?.Settings.PlaylistItemId == 2);
AddUntilStep("wait for two items in playlist", () => playlist.ChildrenOfType<DrawableRoomPlaylistItem>().Count() == 2);
assertDeleteButtonVisibility(0, false);
@ -124,13 +120,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("add playlist item", () =>
{
MultiplayerPlaylistItem item = new MultiplayerPlaylistItem(new PlaylistItem
{
Beatmap = { Value = importedBeatmap },
BeatmapID = importedBeatmap.OnlineID,
});
MultiplayerPlaylistItem item = new MultiplayerPlaylistItem(new PlaylistItem(importedBeatmap));
Client.AddUserPlaylistItem(userId(), item);
MultiplayerClient.AddUserPlaylistItem(userId(), item).WaitSafely();
itemId = item.ID;
});

View File

@ -40,7 +40,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(Realm));
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
@ -54,10 +54,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
importedSet = beatmaps.GetAllUsableBeatmapSets().First();
Beatmap.Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First());
selectedItem.Value = new PlaylistItem
selectedItem.Value = new PlaylistItem(Beatmap.Value.BeatmapInfo)
{
Beatmap = { Value = Beatmap.Value.BeatmapInfo },
Ruleset = { Value = Beatmap.Value.BeatmapInfo.Ruleset },
RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID
};
if (button != null)
@ -74,13 +73,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
Task.Run(async () =>
{
if (Client.IsHost && Client.LocalUser?.State == MultiplayerUserState.Ready)
if (MultiplayerClient.IsHost && MultiplayerClient.LocalUser?.State == MultiplayerUserState.Ready)
{
await Client.StartMatch();
await MultiplayerClient.StartMatch();
return;
}
await Client.ToggleReady();
await MultiplayerClient.ToggleReady();
readyClickOperation.Dispose();
});
@ -110,15 +109,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add second user as host", () =>
{
Client.AddUser(new APIUser { Id = 2, Username = "Another user" });
Client.TransferHost(2);
MultiplayerClient.AddUser(new APIUser { Id = 2, Username = "Another user" });
MultiplayerClient.TransferHost(2);
});
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddUntilStep("user is ready", () => Client.Room?.Users[0].State == MultiplayerUserState.Ready);
AddUntilStep("user is ready", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Ready);
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddUntilStep("user is idle", () => Client.Room?.Users[0].State == MultiplayerUserState.Idle);
AddUntilStep("user is idle", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Idle);
}
[TestCase(true)]
@ -127,14 +126,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("setup", () =>
{
Client.TransferHost(Client.Room?.Users[0].UserID ?? 0);
MultiplayerClient.TransferHost(MultiplayerClient.Room?.Users[0].UserID ?? 0);
if (!allReady)
Client.AddUser(new APIUser { Id = 2, Username = "Another user" });
MultiplayerClient.AddUser(new APIUser { Id = 2, Username = "Another user" });
});
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddUntilStep("user is ready", () => Client.Room?.Users[0].State == MultiplayerUserState.Ready);
AddUntilStep("user is ready", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Ready);
verifyGameplayStartFlow();
}
@ -144,12 +143,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add host", () =>
{
Client.AddUser(new APIUser { Id = 2, Username = "Another user" });
Client.TransferHost(2);
MultiplayerClient.AddUser(new APIUser { Id = 2, Username = "Another user" });
MultiplayerClient.TransferHost(2);
});
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddStep("make user host", () => Client.TransferHost(Client.Room?.Users[0].UserID ?? 0));
AddStep("make user host", () => MultiplayerClient.TransferHost(MultiplayerClient.Room?.Users[0].UserID ?? 0));
verifyGameplayStartFlow();
}
@ -159,17 +158,17 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("setup", () =>
{
Client.TransferHost(Client.Room?.Users[0].UserID ?? 0);
Client.AddUser(new APIUser { Id = 2, Username = "Another user" });
MultiplayerClient.TransferHost(MultiplayerClient.Room?.Users[0].UserID ?? 0);
MultiplayerClient.AddUser(new APIUser { Id = 2, Username = "Another user" });
});
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddUntilStep("user is ready", () => Client.Room?.Users[0].State == MultiplayerUserState.Ready);
AddUntilStep("user is ready", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Ready);
AddStep("transfer host", () => Client.TransferHost(Client.Room?.Users[1].UserID ?? 0));
AddStep("transfer host", () => MultiplayerClient.TransferHost(MultiplayerClient.Room?.Users[1].UserID ?? 0));
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddUntilStep("user is idle (match not started)", () => Client.Room?.Users[0].State == MultiplayerUserState.Idle);
AddUntilStep("user is idle (match not started)", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Idle);
AddAssert("ready button enabled", () => button.ChildrenOfType<OsuButton>().Single().Enabled.Value);
}
@ -180,42 +179,42 @@ namespace osu.Game.Tests.Visual.Multiplayer
const int users = 10;
AddStep("setup", () =>
{
Client.TransferHost(Client.Room?.Users[0].UserID ?? 0);
MultiplayerClient.TransferHost(MultiplayerClient.Room?.Users[0].UserID ?? 0);
for (int i = 0; i < users; i++)
Client.AddUser(new APIUser { Id = i, Username = "Another user" });
MultiplayerClient.AddUser(new APIUser { Id = i, Username = "Another user" });
});
if (!isHost)
AddStep("transfer host", () => Client.TransferHost(2));
AddStep("transfer host", () => MultiplayerClient.TransferHost(2));
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddRepeatStep("change user ready state", () =>
{
Client.ChangeUserState(RNG.Next(0, users), RNG.NextBool() ? MultiplayerUserState.Ready : MultiplayerUserState.Idle);
MultiplayerClient.ChangeUserState(RNG.Next(0, users), RNG.NextBool() ? MultiplayerUserState.Ready : MultiplayerUserState.Idle);
}, 20);
AddRepeatStep("ready all users", () =>
{
var nextUnready = Client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle);
var nextUnready = MultiplayerClient.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle);
if (nextUnready != null)
Client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready);
MultiplayerClient.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready);
}, users);
}
private void verifyGameplayStartFlow()
{
AddUntilStep("user is ready", () => Client.Room?.Users[0].State == MultiplayerUserState.Ready);
AddUntilStep("user is ready", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Ready);
ClickButtonWhenEnabled<MultiplayerReadyButton>();
AddUntilStep("user waiting for load", () => Client.Room?.Users[0].State == MultiplayerUserState.WaitingForLoad);
AddUntilStep("user waiting for load", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.WaitingForLoad);
AddAssert("ready button disabled", () => !button.ChildrenOfType<OsuButton>().Single().Enabled.Value);
AddStep("transitioned to gameplay", () => readyClickOperation.Dispose());
AddStep("finish gameplay", () =>
{
Client.ChangeUserState(Client.Room?.Users[0].UserID ?? 0, MultiplayerUserState.Loaded);
Client.ChangeUserState(Client.Room?.Users[0].UserID ?? 0, MultiplayerUserState.FinishedPlay);
MultiplayerClient.ChangeUserState(MultiplayerClient.Room?.Users[0].UserID ?? 0, MultiplayerUserState.Loaded);
MultiplayerClient.ChangeUserState(MultiplayerClient.Room?.Users[0].UserID ?? 0, MultiplayerUserState.FinishedPlay);
});
AddUntilStep("ready button enabled", () => button.ChildrenOfType<OsuButton>().Single().Enabled.Value);

View File

@ -22,12 +22,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
var beatmapInfo = CreateBeatmap(rulesetInfo).BeatmapInfo;
var score = TestResources.CreateTestScoreInfo(beatmapInfo);
PlaylistItem playlistItem = new PlaylistItem
{
BeatmapID = beatmapInfo.OnlineID,
};
Stack.Push(screen = new MultiplayerResultsScreen(score, 1, playlistItem));
Stack.Push(screen = new MultiplayerResultsScreen(score, 1, new PlaylistItem(beatmapInfo)));
});
AddUntilStep("wait for loaded", () => screen.IsLoaded);

View File

@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(Realm));
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
@ -55,10 +55,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
importedSet = beatmaps.GetAllUsableBeatmapSets().First();
Beatmap.Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First());
selectedItem.Value = new PlaylistItem
selectedItem.Value = new PlaylistItem(Beatmap.Value.BeatmapInfo)
{
Beatmap = { Value = Beatmap.Value.BeatmapInfo },
Ruleset = { Value = Beatmap.Value.BeatmapInfo.Ruleset },
RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID,
};
Child = new FillFlowContainer
@ -78,7 +77,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Task.Run(async () =>
{
await Client.ToggleSpectate();
await MultiplayerClient.ToggleSpectate();
readyClickOperation.Dispose();
});
}
@ -94,13 +93,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
Task.Run(async () =>
{
if (Client.IsHost && Client.LocalUser?.State == MultiplayerUserState.Ready)
if (MultiplayerClient.IsHost && MultiplayerClient.LocalUser?.State == MultiplayerUserState.Ready)
{
await Client.StartMatch();
await MultiplayerClient.StartMatch();
return;
}
await Client.ToggleReady();
await MultiplayerClient.ToggleReady();
readyClickOperation.Dispose();
});
@ -115,7 +114,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[TestCase(MultiplayerRoomState.Playing)]
public void TestEnabledWhenRoomOpenOrInGameplay(MultiplayerRoomState roomState)
{
AddStep($"change room to {roomState}", () => Client.ChangeRoomState(roomState));
AddStep($"change room to {roomState}", () => MultiplayerClient.ChangeRoomState(roomState));
assertSpectateButtonEnablement(true);
}
@ -124,16 +123,16 @@ namespace osu.Game.Tests.Visual.Multiplayer
public void TestToggleWhenIdle(MultiplayerUserState initialState)
{
ClickButtonWhenEnabled<MultiplayerSpectateButton>();
AddUntilStep("user is spectating", () => Client.Room?.Users[0].State == MultiplayerUserState.Spectating);
AddUntilStep("user is spectating", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Spectating);
ClickButtonWhenEnabled<MultiplayerSpectateButton>();
AddUntilStep("user is idle", () => Client.Room?.Users[0].State == MultiplayerUserState.Idle);
AddUntilStep("user is idle", () => MultiplayerClient.Room?.Users[0].State == MultiplayerUserState.Idle);
}
[TestCase(MultiplayerRoomState.Closed)]
public void TestDisabledWhenClosed(MultiplayerRoomState roomState)
{
AddStep($"change room to {roomState}", () => Client.ChangeRoomState(roomState));
AddStep($"change room to {roomState}", () => MultiplayerClient.ChangeRoomState(roomState));
assertSpectateButtonEnablement(false);
}
@ -147,8 +146,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestReadyButtonEnabledWhenHostAndUsersReady()
{
AddStep("add user", () => Client.AddUser(new APIUser { Id = PLAYER_1_ID }));
AddStep("set user ready", () => Client.ChangeUserState(PLAYER_1_ID, MultiplayerUserState.Ready));
AddStep("add user", () => MultiplayerClient.AddUser(new APIUser { Id = PLAYER_1_ID }));
AddStep("set user ready", () => MultiplayerClient.ChangeUserState(PLAYER_1_ID, MultiplayerUserState.Ready));
ClickButtonWhenEnabled<MultiplayerSpectateButton>();
assertReadyButtonEnablement(true);
@ -159,11 +158,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add user and transfer host", () =>
{
Client.AddUser(new APIUser { Id = PLAYER_1_ID });
Client.TransferHost(PLAYER_1_ID);
MultiplayerClient.AddUser(new APIUser { Id = PLAYER_1_ID });
MultiplayerClient.TransferHost(PLAYER_1_ID);
});
AddStep("set user ready", () => Client.ChangeUserState(PLAYER_1_ID, MultiplayerUserState.Ready));
AddStep("set user ready", () => MultiplayerClient.ChangeUserState(PLAYER_1_ID, MultiplayerUserState.Ready));
ClickButtonWhenEnabled<MultiplayerSpectateButton>();
assertReadyButtonEnablement(false);

View File

@ -26,18 +26,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
var beatmapInfo = CreateBeatmap(rulesetInfo).BeatmapInfo;
var score = TestResources.CreateTestScoreInfo(beatmapInfo);
PlaylistItem playlistItem = new PlaylistItem
{
BeatmapID = beatmapInfo.OnlineID,
};
SortedDictionary<int, BindableInt> teamScores = new SortedDictionary<int, BindableInt>
{
{ 0, new BindableInt(team1Score) },
{ 1, new BindableInt(team2Score) }
};
Stack.Push(screen = new MultiplayerTeamResultsScreen(score, 1, playlistItem, teamScores));
Stack.Push(screen = new MultiplayerTeamResultsScreen(score, 1, new PlaylistItem(beatmapInfo), teamScores));
});
AddUntilStep("wait for loaded", () => screen.IsLoaded);

View File

@ -4,33 +4,29 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Database;
using osu.Game.Graphics.Containers;
using osu.Game.Models;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.OnlinePlay;
using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Visual.OnlinePlay;
using osuTK;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestScenePlaylistsRoomSettingsPlaylist : OsuManualInputManagerTestScene
public class TestScenePlaylistsRoomSettingsPlaylist : OnlinePlayTestScene
{
private TestPlaylist playlist;
[Cached(typeof(UserLookupCache))]
private readonly TestUserLookupCache userLookupCache = new TestUserLookupCache();
[Test]
public void TestItemRemovedOnDeletion()
{
@ -110,18 +106,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("item 0 is selected", () => playlist.SelectedItem.Value == playlist.Items[0]);
}
[Test]
public void TestChangeBeatmapAndRemove()
{
createPlaylist();
AddStep("change beatmap of first item", () => playlist.Items[0].BeatmapID = 30);
moveToDeleteButton(0);
AddStep("click delete button", () => InputManager.Click(MouseButton.Left));
}
private void moveToItem(int index, Vector2? offset = null)
=> AddStep($"move mouse to item {index}", () => InputManager.MoveMouseTo(playlist.ChildrenOfType<DifficultyIcon>().ElementAt(index), offset));
=> AddStep($"move mouse to item {index}", () => InputManager.MoveMouseTo(playlist.ChildrenOfType<DrawableRoomPlaylistItem>().ElementAt(index), offset));
private void moveToDeleteButton(int index, Vector2? offset = null) => AddStep($"move mouse to delete button {index}", () =>
{
@ -142,31 +128,27 @@ namespace osu.Game.Tests.Visual.Multiplayer
for (int i = 0; i < 20; i++)
{
playlist.Items.Add(new PlaylistItem
playlist.Items.Add(new PlaylistItem(i % 2 == 1
? new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo
: new BeatmapInfo
{
Metadata = new BeatmapMetadata
{
Artist = "Artist",
Author = new RealmUser { Username = "Creator name here" },
Title = "Long title used to check background colour",
},
BeatmapSet = new BeatmapSetInfo()
})
{
ID = i,
OwnerID = 2,
Beatmap =
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
RequiredMods = new[]
{
Value = i % 2 == 1
? new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo
: new BeatmapInfo
{
Metadata = new BeatmapMetadata
{
Artist = "Artist",
Author = new RealmUser { Username = "Creator name here" },
Title = "Long title used to check background colour",
},
BeatmapSet = new BeatmapSetInfo()
}
},
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RequiredMods =
{
new OsuModHardRock(),
new OsuModDoubleTime(),
new OsuModAutoplay()
new APIMod(new OsuModHardRock()),
new APIMod(new OsuModDoubleTime()),
new APIMod(new OsuModAutoplay())
}
});
}

View File

@ -33,7 +33,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(Realm));
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
@ -115,8 +115,17 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("change mod rate", () => ((OsuModDoubleTime)SelectedMods.Value[0]).SpeedChange.Value = 2);
AddStep("create item", () => songSelect.BeatmapDetails.CreateNewItem());
AddAssert("item 1 has rate 1.5", () => Precision.AlmostEquals(1.5, ((OsuModDoubleTime)SelectedRoom.Value.Playlist.First().RequiredMods[0]).SpeedChange.Value));
AddAssert("item 2 has rate 2", () => Precision.AlmostEquals(2, ((OsuModDoubleTime)SelectedRoom.Value.Playlist.Last().RequiredMods[0]).SpeedChange.Value));
AddAssert("item 1 has rate 1.5", () =>
{
var mod = (OsuModDoubleTime)SelectedRoom.Value.Playlist.First().RequiredMods[0].ToMod(new OsuRuleset());
return Precision.AlmostEquals(1.5, mod.SpeedChange.Value);
});
AddAssert("item 2 has rate 2", () =>
{
var mod = (OsuModDoubleTime)SelectedRoom.Value.Playlist.Last().RequiredMods[0].ToMod(new OsuRuleset());
return Precision.AlmostEquals(2, mod.SpeedChange.Value);
});
}
/// <summary>
@ -138,7 +147,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("create item", () => songSelect.BeatmapDetails.CreateNewItem());
AddStep("change stored mod rate", () => mod.SpeedChange.Value = 2);
AddAssert("item has rate 1.5", () => Precision.AlmostEquals(1.5, ((OsuModDoubleTime)SelectedRoom.Value.Playlist.First().RequiredMods[0]).SpeedChange.Value));
AddAssert("item has rate 1.5", () =>
{
var m = (OsuModDoubleTime)SelectedRoom.Value.Playlist.First().RequiredMods[0].ToMod(new OsuRuleset());
return Precision.AlmostEquals(1.5, m.SpeedChange.Value);
});
}
private class TestPlaylistsSongSelect : PlaylistsSongSelect

View File

@ -25,14 +25,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add user", () =>
{
Client.AddUser(new APIUser
MultiplayerClient.AddUser(new APIUser
{
Id = 2,
Statistics = { GlobalRank = 1234 }
});
// Remove the local user so only the one above is displayed.
Client.RemoveUser(API.LocalUser.Value);
MultiplayerClient.RemoveUser(API.LocalUser.Value);
});
}
@ -41,26 +41,26 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add users", () =>
{
Client.AddUser(new APIUser
MultiplayerClient.AddUser(new APIUser
{
Id = 2,
Statistics = { GlobalRank = 1234 }
});
Client.AddUser(new APIUser
MultiplayerClient.AddUser(new APIUser
{
Id = 3,
Statistics = { GlobalRank = 3333 }
});
Client.AddUser(new APIUser
MultiplayerClient.AddUser(new APIUser
{
Id = 4,
Statistics = { GlobalRank = 4321 }
});
// Remove the local user so only the ones above are displayed.
Client.RemoveUser(API.LocalUser.Value);
MultiplayerClient.RemoveUser(API.LocalUser.Value);
});
}
@ -75,20 +75,20 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add users", () =>
{
Client.AddUser(new APIUser
MultiplayerClient.AddUser(new APIUser
{
Id = 2,
Statistics = { GlobalRank = min }
});
Client.AddUser(new APIUser
MultiplayerClient.AddUser(new APIUser
{
Id = 3,
Statistics = { GlobalRank = max }
});
// Remove the local user so only the ones above are displayed.
Client.RemoveUser(API.LocalUser.Value);
MultiplayerClient.RemoveUser(API.LocalUser.Value);
});
}
}

View File

@ -31,8 +31,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
SelectedRoom.Value.Playlist.AddRange(new[]
{
new PlaylistItem { Beatmap = { Value = new BeatmapInfo { StarRating = min } } },
new PlaylistItem { Beatmap = { Value = new BeatmapInfo { StarRating = max } } },
new PlaylistItem(new BeatmapInfo { StarRating = min }),
new PlaylistItem(new BeatmapInfo { StarRating = max }),
});
});
}

View File

@ -10,7 +10,6 @@ using osu.Framework.Extensions;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
@ -34,15 +33,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
private TestMultiplayerComponents multiplayerComponents;
private TestMultiplayerClient client => multiplayerComponents.Client;
[Cached(typeof(UserLookupCache))]
private UserLookupCache lookupCache = new TestUserLookupCache();
private TestMultiplayerClient multiplayerClient => multiplayerComponents.MultiplayerClient;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(Realm));
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, rulesets, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(Realm);
}
@ -71,16 +67,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
Type = { Value = MatchType.TeamVersus },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
});
AddUntilStep("room type is team vs", () => client.Room?.Settings.MatchType == MatchType.TeamVersus);
AddAssert("user state arrived", () => client.Room?.Users.FirstOrDefault()?.MatchState is TeamVersusUserState);
AddUntilStep("room type is team vs", () => multiplayerClient.Room?.Settings.MatchType == MatchType.TeamVersus);
AddAssert("user state arrived", () => multiplayerClient.Room?.Users.FirstOrDefault()?.MatchState is TeamVersusUserState);
}
[Test]
@ -92,33 +87,32 @@ namespace osu.Game.Tests.Visual.Multiplayer
Type = { Value = MatchType.TeamVersus },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
}
}
});
AddAssert("user on team 0", () => (client.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 0);
AddStep("add another user", () => client.AddUser(new APIUser { Username = "otheruser", Id = 44 }));
AddAssert("user on team 0", () => (multiplayerClient.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 0);
AddStep("add another user", () => multiplayerClient.AddUser(new APIUser { Username = "otheruser", Id = 44 }));
AddStep("press own button", () =>
{
InputManager.MoveMouseTo(multiplayerComponents.ChildrenOfType<TeamDisplay>().First());
InputManager.Click(MouseButton.Left);
});
AddAssert("user on team 1", () => (client.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 1);
AddAssert("user on team 1", () => (multiplayerClient.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 1);
AddStep("press own button again", () => InputManager.Click(MouseButton.Left));
AddAssert("user on team 0", () => (client.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 0);
AddAssert("user on team 0", () => (multiplayerClient.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 0);
AddStep("press other user's button", () =>
{
InputManager.MoveMouseTo(multiplayerComponents.ChildrenOfType<TeamDisplay>().ElementAt(1));
InputManager.Click(MouseButton.Left);
});
AddAssert("user still on team 0", () => (client.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 0);
AddAssert("user still on team 0", () => (multiplayerClient.Room?.Users.FirstOrDefault()?.MatchState as TeamVersusUserState)?.TeamID == 0);
}
[Test]
@ -130,22 +124,21 @@ namespace osu.Game.Tests.Visual.Multiplayer
Type = { Value = MatchType.HeadToHead },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
});
AddUntilStep("match type head to head", () => client.APIRoom?.Type.Value == MatchType.HeadToHead);
AddUntilStep("match type head to head", () => multiplayerClient.APIRoom?.Type.Value == MatchType.HeadToHead);
AddStep("change match type", () => client.ChangeSettings(new MultiplayerRoomSettings
AddStep("change match type", () => multiplayerClient.ChangeSettings(new MultiplayerRoomSettings
{
MatchType = MatchType.TeamVersus
}));
}).WaitSafely());
AddUntilStep("api room updated to team versus", () => client.APIRoom?.Type.Value == MatchType.TeamVersus);
AddUntilStep("api room updated to team versus", () => multiplayerClient.APIRoom?.Type.Value == MatchType.TeamVersus);
}
[Test]
@ -156,21 +149,20 @@ namespace osu.Game.Tests.Visual.Multiplayer
Name = { Value = "Test Room" },
Playlist =
{
new PlaylistItem
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
}
}
});
AddUntilStep("room type is head to head", () => client.Room?.Settings.MatchType == MatchType.HeadToHead);
AddUntilStep("room type is head to head", () => multiplayerClient.Room?.Settings.MatchType == MatchType.HeadToHead);
AddUntilStep("team displays are not displaying teams", () => multiplayerComponents.ChildrenOfType<TeamDisplay>().All(d => d.DisplayedTeam == null));
AddStep("change to team vs", () => client.ChangeSettings(matchType: MatchType.TeamVersus));
AddStep("change to team vs", () => multiplayerClient.ChangeSettings(matchType: MatchType.TeamVersus));
AddUntilStep("room type is team vs", () => client.Room?.Settings.MatchType == MatchType.TeamVersus);
AddUntilStep("room type is team vs", () => multiplayerClient.Room?.Settings.MatchType == MatchType.TeamVersus);
AddUntilStep("team displays are displaying teams", () => multiplayerComponents.ChildrenOfType<TeamDisplay>().All(d => d.DisplayedTeam != null));
}
@ -189,7 +181,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for join", () => client.RoomJoined);
AddUntilStep("wait for join", () => multiplayerClient.RoomJoined);
}
}
}

View File

@ -0,0 +1,43 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.IO;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Models;
using osu.Game.Scoring;
using osu.Game.Skinning;
using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Visual.Navigation
{
public class TestEFToRealmMigration : OsuGameTestScene
{
public override void RecycleLocalStorage(bool isDisposing)
{
base.RecycleLocalStorage(isDisposing);
if (isDisposing)
return;
using (var outStream = LocalStorage.GetStream(DatabaseContextFactory.DATABASE_NAME, FileAccess.Write, FileMode.Create))
using (var stream = TestResources.OpenResource(DatabaseContextFactory.DATABASE_NAME))
stream.CopyTo(outStream);
}
[Test]
public void TestMigration()
{
// Numbers are taken from the test database (see commit f03de16ee5a46deac3b5f2ca1edfba5c4c5dca7d).
AddAssert("Check beatmaps", () => Game.Dependencies.Get<RealmAccess>().Run(r => r.All<BeatmapSetInfo>().Count(s => !s.Protected) == 1));
AddAssert("Check skins", () => Game.Dependencies.Get<RealmAccess>().Run(r => r.All<SkinInfo>().Count(s => !s.Protected) == 1));
AddAssert("Check scores", () => Game.Dependencies.Get<RealmAccess>().Run(r => r.All<ScoreInfo>().Count() == 1));
// One extra file is created during realm migration / startup due to the circles intro import.
AddAssert("Check files", () => Game.Dependencies.Get<RealmAccess>().Run(r => r.All<RealmFile>().Count() == 271));
}
}
}

Some files were not shown because too many files have changed in this diff Show More