1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-13 14:53:21 +08:00

Merge branch 'master' into scroll-to-20

This commit is contained in:
Dean Herbert 2021-01-21 13:48:26 +09:00
commit 7c4a072568
454 changed files with 6346 additions and 3321 deletions

View File

@ -15,7 +15,7 @@
]
},
"jetbrains.resharper.globaltools": {
"version": "2020.2.4",
"version": "2020.3.2",
"commands": [
"jb"
]

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/Release/netcoreapp3.1/osu.Game.Benchmarks.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Benchmarks/bin/Release/net5.0/osu.Game.Benchmarks.dll" />
<option name="PROGRAM_PARAMETERS" value="--filter *" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Benchmarks/bin/Release/netcoreapp3.1" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Benchmarks/bin/Release/net5.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=".NETCoreApp,Version=v3.1" />
<option name="PROJECT_TFM" value="net5.0" />
<method v="2">
<option name="Build" enabled="true" />
</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/netcoreapp3.1/osu.Game.Rulesets.Catch.Tests.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/net5.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/netcoreapp3.1" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/net5.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=".NETCoreApp,Version=v3.1" />
<option name="PROJECT_TFM" value="net5.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/netcoreapp3.1/osu.Game.Rulesets.Mania.Tests.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/net5.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/netcoreapp3.1" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/net5.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=".NETCoreApp,Version=v3.1" />
<option name="PROJECT_TFM" value="net5.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/netcoreapp3.1/osu.Game.Rulesets.Osu.Tests.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/net5.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/netcoreapp3.1" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/net5.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=".NETCoreApp,Version=v3.1" />
<option name="PROJECT_TFM" value="net5.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/netcoreapp3.1/osu.Game.Rulesets.Taiko.Tests.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/net5.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/netcoreapp3.1" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/net5.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=".NETCoreApp,Version=v3.1" />
<option name="PROJECT_TFM" value="net5.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/netcoreapp3.1/osu!.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0/osu!.dll" />
<option name="PROGRAM_PARAMETERS" value="--tournament" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp3.1" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.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=".NETCoreApp,Version=v3.1" />
<option name="PROJECT_TFM" value="net5.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/netcoreapp3.1/osu.Game.Tournament.Tests.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tournament.Tests/bin/Debug/net5.0/osu.Game.Tournament.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.1" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tournament.Tests/bin/Debug/net5.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=".NETCoreApp,Version=v3.1" />
<option name="PROJECT_TFM" value="net5.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/netcoreapp3.1/osu!.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0/osu!.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp3.1" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.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=".NETCoreApp,Version=v3.1" />
<option name="PROJECT_TFM" value="net5.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/netcoreapp3.1/osu.Game.Tests.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/net5.0/osu.Game.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/netcoreapp3.1" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/net5.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=".NETCoreApp,Version=v3.1" />
<option name="PROJECT_TFM" value="net5.0" />
<method v="2">
<option name="Build" />
</method>

View File

@ -1,8 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="osu! (legacy osuTK)" type="DotNetProject" factoryName=".NET Project" folderName="osu!" activateToolWindowBeforeRun="false">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp3.1/osu!.dll" />
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0/osu!.dll" />
<option name="PROGRAM_PARAMETERS" value="--tk" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp3.1" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.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=".NETCoreApp,Version=v3.1" />
<option name="PROJECT_TFM" value="net5.0" />
<method v="2">
<option name="Build" />
</method>

18
.vscode/launch.json vendored
View File

@ -7,7 +7,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.1/osu!.dll"
"${workspaceRoot}/osu.Desktop/bin/Debug/net5.0/osu!.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Debug)",
@ -19,7 +19,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.1/osu!.dll"
"${workspaceRoot}/osu.Desktop/bin/Release/net5.0/osu!.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Release)",
@ -31,7 +31,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp3.1/osu.Game.Tests.dll"
"${workspaceRoot}/osu.Game.Tests/bin/Debug/net5.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/netcoreapp3.1/osu.Game.Tests.dll"
"${workspaceRoot}/osu.Game.Tests/bin/Release/net5.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/netcoreapp3.1/osu!.dll",
"${workspaceRoot}/osu.Desktop/bin/Debug/net5.0/osu!.dll",
"--tournament"
],
"cwd": "${workspaceRoot}",
@ -68,7 +68,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.1/osu!.dll",
"${workspaceRoot}/osu.Desktop/bin/Release/net5.0/osu!.dll",
"--tournament"
],
"cwd": "${workspaceRoot}",
@ -81,7 +81,7 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.1/osu.Game.Tournament.Tests.dll",
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/net5.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/netcoreapp3.1/osu.Game.Tournament.Tests.dll",
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/net5.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/netcoreapp3.1/osu.Game.Benchmarks.dll",
"program": "${workspaceRoot}/osu.Game.Benchmarks/bin/Release/net5.0/osu.Game.Benchmarks.dll",
"args": [
"--filter",
"*"

View File

@ -16,9 +16,9 @@
<EmbeddedResource Include="Resources\**\*.*" />
</ItemGroup>
<ItemGroup Label="Code Analysis">
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.2" PrivateAssets="All" />
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\BannedSymbols.txt" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.2" PrivateAssets="All" />
</ItemGroup>
<PropertyGroup Label="Code Analysis">
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)CodeAnalysis\osu.ruleset</CodeAnalysisRuleSet>
@ -28,9 +28,17 @@
<NoWarn>$(NoWarn);CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup Label="Project">
<!-- 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 -->
<NoWarn>$(NoWarn);NU1701</NoWarn>
<!--
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>
</PropertyGroup>
<PropertyGroup Label="Nuget">
<IsPackable>false</IsPackable>
@ -40,7 +48,7 @@
<RepositoryUrl>https://github.com/ppy/osu</RepositoryUrl>
<PackageReleaseNotes>Automated release.</PackageReleaseNotes>
<Company>ppy Pty Ltd</Company>
<Copyright>Copyright (c) 2020 ppy Pty Ltd</Copyright>
<Copyright>Copyright (c) 2021 ppy Pty Ltd</Copyright>
<PackageTags>osu game</PackageTags>
</PropertyGroup>
</Project>
</Project>

View File

@ -1,27 +1,27 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.2)
CFPropertyList (3.0.3)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
atomos (0.1.3)
aws-eventstream (1.1.0)
aws-partitions (1.354.0)
aws-sdk-core (3.104.3)
aws-partitions (1.413.0)
aws-sdk-core (3.110.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.239.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-kms (1.36.0)
aws-sdk-core (~> 3, >= 3.99.0)
aws-sdk-kms (1.40.0)
aws-sdk-core (~> 3, >= 3.109.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.78.0)
aws-sdk-core (~> 3, >= 3.104.3)
aws-sdk-s3 (1.87.0)
aws-sdk-core (~> 3, >= 3.109.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1)
aws-sigv4 (1.2.1)
aws-sigv4 (1.2.2)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.3)
babosa (1.0.4)
claide (1.0.3)
colored (1.2)
colored2 (3.1.2)
@ -29,22 +29,23 @@ GEM
highline (~> 1.7.2)
declarative (0.0.20)
declarative-option (0.1.0)
digest-crc (0.6.1)
rake (~> 13.0)
digest-crc (0.6.3)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.6)
emoji_regex (3.0.0)
excon (0.76.0)
faraday (1.0.1)
emoji_regex (3.2.1)
excon (0.78.1)
faraday (1.2.0)
multipart-post (>= 1.2, < 3)
faraday-cookie_jar (0.0.6)
faraday (>= 0.7.4)
ruby2_keywords
faraday-cookie_jar (0.0.7)
faraday (>= 0.8.0)
http-cookie (~> 1.0.0)
faraday_middleware (1.0.0)
faraday (~> 1.0)
fastimage (2.2.0)
fastlane (2.156.0)
fastimage (2.2.1)
fastlane (2.170.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0)
aws-sdk-s3 (~> 1.0)
@ -96,17 +97,17 @@ GEM
google-cloud-core (1.5.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.3.3)
google-cloud-env (1.4.0)
faraday (>= 0.17.3, < 2.0)
google-cloud-errors (1.0.1)
google-cloud-storage (1.27.0)
google-cloud-storage (1.29.2)
addressable (~> 2.5)
digest-crc (~> 0.4)
google-api-client (~> 0.33)
google-cloud-core (~> 1.2)
googleauth (~> 0.9)
mini_mime (~> 1.0)
googleauth (0.13.1)
googleauth (0.14.0)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
@ -118,10 +119,10 @@ GEM
domain_name (~> 0.5)
httpclient (2.8.3)
jmespath (1.4.0)
json (2.3.1)
jwt (2.2.1)
json (2.5.1)
jwt (2.2.2)
memoist (0.16.2)
mini_magick (4.10.1)
mini_magick (4.11.0)
mini_mime (1.0.2)
mini_portile2 (2.4.0)
multi_json (1.15.0)
@ -132,14 +133,15 @@ GEM
mini_portile2 (~> 2.4.0)
os (1.1.1)
plist (3.5.0)
public_suffix (4.0.5)
rake (13.0.1)
public_suffix (4.0.6)
rake (13.0.3)
representable (3.0.4)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rouge (2.0.7)
ruby2_keywords (0.0.2)
rubyzip (2.3.0)
security (0.1.3)
signet (0.14.0)
@ -168,7 +170,7 @@ GEM
unf_ext (0.0.7.7)
unicode-display_width (1.7.0)
word_wrap (1.0.0)
xcodeproj (1.18.0)
xcodeproj (1.19.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)

View File

@ -1,4 +1,4 @@
Copyright (c) 2020 ppy Pty Ltd <contact@ppy.sh>.
Copyright (c) 2021 ppy Pty Ltd <contact@ppy.sh>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -36,8 +36,7 @@ If you are looking to install or test osu! without setting up a development envi
- The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets.
- When running on Windows 7 or 8.1, **[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/install/dependencies?tabs=netcore31&pivots=os-windows)** may be required to correctly run .NET Core applications if your operating system is not up-to-date with the latest service packs.
- When running on Windows 7 or 8.1, *[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/install/windows?tabs=net50&pivots=os-windows#dependencies)** may be required to correctly run .NET 5 applications if your operating system is not up-to-date with the latest service packs.
If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
## Developing a custom ruleset
@ -50,7 +49,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 Core 3.1 SDK](https://dotnet.microsoft.com/download) or higher installed.
- A desktop platform with the [.NET 5.0 SDK](https://dotnet.microsoft.com/download) or higher 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

@ -1,21 +1,68 @@
clone_depth: 1
version: '{build}'
image: Visual Studio 2019
dotnet_csproj:
patch: true
file: 'osu.Game\osu.Game.csproj' # Use wildcard when it's able to exclude Xamarin projects
version: $(APPVEYOR_REPO_TAG_NAME)
before_build:
- ps: dotnet --info # Useful when version mismatch between CI and local
- ps: nuget restore -verbosity quiet # Only nuget.exe knows both new (.NET Core) and old (Xamarin) projects
test: off
skip_non_tags: true
configuration: Release
build:
project: build\Desktop.proj # Skipping Xamarin Release that's slow and covered by fastlane
parallel: true
verbosity: minimal
publish_nuget: true
environment:
matrix:
- job_name: osu-game
- job_name: osu-ruleset
job_depends_on: osu-game
- job_name: taiko-ruleset
job_depends_on: osu-game
- job_name: catch-ruleset
job_depends_on: osu-game
- job_name: mania-ruleset
job_depends_on: osu-game
nuget:
project_feed: true
for:
-
matrix:
only:
- job_name: osu-game
build_script:
- cmd: dotnet pack osu.Game\osu.Game.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
-
matrix:
only:
- job_name: osu-ruleset
build_script:
- cmd: dotnet remove osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj reference osu.Game\osu.Game.csproj
- cmd: dotnet add osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
- cmd: dotnet pack osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
-
matrix:
only:
- job_name: taiko-ruleset
build_script:
- cmd: dotnet remove osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj reference osu.Game\osu.Game.csproj
- cmd: dotnet add osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
- cmd: dotnet pack osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
-
matrix:
only:
- job_name: catch-ruleset
build_script:
- cmd: dotnet remove osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj reference osu.Game\osu.Game.csproj
- cmd: dotnet add osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
- cmd: dotnet pack osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
-
matrix:
only:
- job_name: mania-ruleset
build_script:
- cmd: dotnet remove osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj reference osu.Game\osu.Game.csproj
- cmd: dotnet add osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj package ppy.osu.Game -v %APPVEYOR_REPO_TAG_NAME%
- cmd: dotnet pack osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj /p:Version=%APPVEYOR_REPO_TAG_NAME%
artifacts:
- path: '**\*.nupkg'
deploy:
- provider: Environment
name: nuget
name: nuget

View File

@ -48,9 +48,12 @@ desc 'Deploy to play store'
desc 'Compile the project'
lane :build do |options|
nuget_restore(
project_path: 'osu.sln'
)
nuget_restore(project_path: 'osu.Android/osu.Android.csproj')
nuget_restore(project_path: 'osu.Game/osu.Game.csproj')
nuget_restore(project_path: 'osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj')
nuget_restore(project_path: 'osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj')
nuget_restore(project_path: 'osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj')
nuget_restore(project_path: 'osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj')
souyuz(
build_configuration: 'Release',
@ -107,9 +110,12 @@ platform :ios do
desc 'Compile the project'
lane :build do
nuget_restore(
project_path: 'osu.sln'
)
nuget_restore(project_path: 'osu.iOS/osu.iOS.csproj')
nuget_restore(project_path: 'osu.Game/osu.Game.csproj')
nuget_restore(project_path: 'osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj')
nuget_restore(project_path: 'osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj')
nuget_restore(project_path: 'osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj')
nuget_restore(project_path: 'osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj')
souyuz(
platform: "ios",

View File

@ -1,10 +0,0 @@
{
"sdk": {
"allowPrerelease": false,
"rollForward": "minor",
"version": "3.1.100"
},
"msbuild-sdks": {
"Microsoft.Build.Traversal": "3.0.2"
}
}

View File

@ -52,6 +52,6 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1202.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1222.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.118.0" />
</ItemGroup>
</Project>

View File

@ -1,7 +1,9 @@
// 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.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
@ -11,13 +13,19 @@ using Android.OS;
using Android.Provider;
using Android.Views;
using osu.Framework.Android;
using osu.Game.Database;
namespace osu.Android
{
[Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false)]
[IntentFilter(new[] { Intent.ActionDefault, Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataPathPatterns = new[] { ".*\\.osz", ".*\\.osk" }, DataMimeType = "application/*")]
[Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false, LaunchMode = LaunchMode.SingleInstance)]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")]
[IntentFilter(new[] { Intent.ActionSend, Intent.ActionSendMultiple }, Categories = new[] { Intent.CategoryDefault }, DataMimeTypes = new[] { "application/zip", "application/octet-stream" })]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataSchemes = new[] { "osu", "osump" })]
public class OsuGameActivity : AndroidGameActivity
{
private static readonly string[] osu_url_schemes = { "osu", "osump" };
private OsuGameAndroid game;
protected override Framework.Game CreateGame() => game = new OsuGameAndroid(this);
@ -48,41 +56,59 @@ namespace osu.Android
{
case Intent.ActionDefault:
if (intent.Scheme == ContentResolver.SchemeContent)
handleImportFromUri(intent.Data);
handleImportFromUris(intent.Data);
else if (osu_url_schemes.Contains(intent.Scheme))
game.HandleLink(intent.DataString);
break;
case Intent.ActionSend:
case Intent.ActionSendMultiple:
{
var content = intent.ClipData?.GetItemAt(0);
if (content != null)
handleImportFromUri(content.Uri);
var uris = new List<Uri>();
for (int i = 0; i < intent.ClipData?.ItemCount; i++)
{
var content = intent.ClipData?.GetItemAt(i);
if (content != null)
uris.Add(content.Uri);
}
handleImportFromUris(uris.ToArray());
break;
}
}
}
private void handleImportFromUri(Uri uri) => Task.Factory.StartNew(async () =>
private void handleImportFromUris(params Uri[] uris) => Task.Factory.StartNew(async () =>
{
// there are more performant overloads of this method, but this one is the most backwards-compatible
// (dates back to API 1).
var cursor = ContentResolver?.Query(uri, null, null, null, null);
var tasks = new List<ImportTask>();
if (cursor == null)
return;
await Task.WhenAll(uris.Select(async uri =>
{
// there are more performant overloads of this method, but this one is the most backwards-compatible
// (dates back to API 1).
var cursor = ContentResolver?.Query(uri, null, null, null, null);
cursor.MoveToFirst();
if (cursor == null)
return;
var filenameColumn = cursor.GetColumnIndex(OpenableColumns.DisplayName);
string filename = cursor.GetString(filenameColumn);
cursor.MoveToFirst();
// SharpCompress requires archive streams to be seekable, which the stream opened by
// OpenInputStream() seems to not necessarily be.
// copy to an arbitrary-access memory stream to be able to proceed with the import.
var copy = new MemoryStream();
using (var stream = ContentResolver.OpenInputStream(uri))
await stream.CopyToAsync(copy);
var filenameColumn = cursor.GetColumnIndex(OpenableColumns.DisplayName);
string filename = cursor.GetString(filenameColumn);
await game.Import(copy, filename);
// SharpCompress requires archive streams to be seekable, which the stream opened by
// OpenInputStream() seems to not necessarily be.
// copy to an arbitrary-access memory stream to be able to proceed with the import.
var copy = new MemoryStream();
using (var stream = ContentResolver.OpenInputStream(uri))
await stream.CopyToAsync(copy);
lock (tasks)
{
tasks.Add(new ImportTask(copy, filename));
}
}));
await game.Import(tasks.ToArray());
}, TaskCreationOptions.LongRunning);
}
}

View File

@ -9,6 +9,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Logging;
using osu.Game.Configuration;
using osu.Game.Online.API;
using osu.Game.Rulesets;
using osu.Game.Users;
@ -31,13 +32,15 @@ namespace osu.Desktop
private readonly IBindable<UserStatus> status = new Bindable<UserStatus>();
private readonly IBindable<UserActivity> activity = new Bindable<UserActivity>();
private readonly Bindable<DiscordRichPresenceMode> privacyMode = new Bindable<DiscordRichPresenceMode>();
private readonly RichPresence presence = new RichPresence
{
Assets = new Assets { LargeImageKey = "osu_logo_lazer", }
};
[BackgroundDependencyLoader]
private void load(IAPIProvider provider)
private void load(IAPIProvider provider, OsuConfigManager config)
{
client = new DiscordRpcClient(client_id)
{
@ -51,6 +54,8 @@ namespace osu.Desktop
client.OnError += (_, e) => Logger.Log($"An error occurred with Discord RPC Client: {e.Code} {e.Message}", LoggingTarget.Network);
config.BindWith(OsuSetting.DiscordRichPresence, privacyMode);
(user = provider.LocalUser.GetBoundCopy()).BindValueChanged(u =>
{
status.UnbindBindings();
@ -63,6 +68,7 @@ namespace osu.Desktop
ruleset.BindValueChanged(_ => updateStatus());
status.BindValueChanged(_ => updateStatus());
activity.BindValueChanged(_ => updateStatus());
privacyMode.BindValueChanged(_ => updateStatus());
client.Initialize();
}
@ -78,7 +84,7 @@ namespace osu.Desktop
if (!client.IsInitialized)
return;
if (status.Value is UserStatusOffline)
if (status.Value is UserStatusOffline || privacyMode.Value == DiscordRichPresenceMode.Off)
{
client.ClearPresence();
return;
@ -96,7 +102,10 @@ namespace osu.Desktop
}
// update user information
presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.Ranks.Global > 0 ? $" (rank #{user.Value.Statistics.Ranks.Global:N0})" : string.Empty);
if (privacyMode.Value == DiscordRichPresenceMode.Limited)
presence.Assets.LargeImageText = string.Empty;
else
presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.Ranks.Global > 0 ? $" (rank #{user.Value.Statistics.Ranks.Global:N0})" : string.Empty);
// update ruleset
presence.Assets.SmallImageKey = ruleset.Value.ID <= 3 ? $"mode_{ruleset.Value.ID}" : "mode_custom";
@ -137,7 +146,7 @@ namespace osu.Desktop
return edit.Beatmap.ToString();
case UserActivity.InLobby lobby:
return lobby.Room.Name.Value;
return privacyMode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value;
}
return string.Empty;

View File

@ -5,6 +5,7 @@ using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using Microsoft.Win32;
using osu.Desktop.Overlays;
@ -56,16 +57,16 @@ namespace osu.Desktop
string stableInstallPath;
try
if (OperatingSystem.IsWindows())
{
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu"))
stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(string.Empty)?.ToString()?.Split('"')[1].Replace("osu!.exe", "");
try
{
stableInstallPath = getStableInstallPathFromRegistry();
if (checkExists(stableInstallPath))
return stableInstallPath;
}
catch
{
if (!string.IsNullOrEmpty(stableInstallPath) && checkExists(stableInstallPath))
return stableInstallPath;
}
catch { }
}
stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!");
@ -79,6 +80,13 @@ namespace osu.Desktop
return null;
}
[SupportedOSPlatform("windows")]
private string getStableInstallPathFromRegistry()
{
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu"))
return key?.OpenSubKey(@"shell\open\command")?.GetValue(string.Empty)?.ToString()?.Split('"')[1].Replace("osu!.exe", "");
}
protected override UpdateManager CreateUpdateManager()
{
switch (RuntimeInfo.OS)

View File

@ -26,9 +26,11 @@ namespace osu.Desktop.Overlays
Alpha = 0;
FillFlowContainer mainFill;
Children = new Drawable[]
{
new FillFlowContainer
mainFill = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
@ -55,23 +57,30 @@ namespace osu.Desktop.Overlays
},
}
},
new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Font = OsuFont.Numeric.With(size: 12),
Colour = colours.Yellow,
Text = @"Development Build"
},
new Sprite
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Texture = textures.Get(@"Menu/dev-build-footer"),
},
}
}
};
if (!game.IsDeployedBuild)
{
mainFill.AddRange(new Drawable[]
{
new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Font = OsuFont.Numeric.With(size: 12),
Colour = colours.Yellow,
Text = @"Development Build"
},
new Sprite
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Texture = textures.Get(@"Menu/dev-build-footer"),
},
});
}
}
protected override void PopIn()

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup Label="Project">
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<OutputType>WinExe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>A free-to-win rhythm game. Rhythm is just a *click* away!</Description>

View File

@ -11,7 +11,7 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>A free-to-win rhythm game. Rhythm is just a *click* away!</description>
<releaseNotes>testing</releaseNotes>
<copyright>Copyright (c) 2020 ppy Pty Ltd</copyright>
<copyright>Copyright (c) 2021 ppy Pty Ltd</copyright>
<language>en-AU</language>
</metadata>
<files>

View File

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

View File

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

View File

@ -0,0 +1,151 @@
// 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.Allocation;
using osu.Framework.Audio;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Skinning;
using osu.Game.Skinning;
using osu.Game.Tests.Beatmaps;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Catch.Tests
{
public class TestSceneLegacyBeatmapSkin : LegacyBeatmapSkinColourTest
{
[Resolved]
private AudioManager audio { get; set; }
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
config.BindWith(OsuSetting.BeatmapSkins, BeatmapSkins);
config.BindWith(OsuSetting.BeatmapColours, BeatmapColours);
}
[TestCase(true, true)]
[TestCase(true, false)]
[TestCase(false, true)]
[TestCase(false, false)]
public override void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin)
{
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true);
base.TestBeatmapComboColours(userHasCustomColours, useBeatmapSkin);
AddAssert("is beatmap skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours));
}
[TestCase(true)]
[TestCase(false)]
public override void TestBeatmapComboColoursOverride(bool useBeatmapSkin)
{
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true);
base.TestBeatmapComboColoursOverride(useBeatmapSkin);
AddAssert("is user custom skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours));
}
[TestCase(true)]
[TestCase(false)]
public override void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin)
{
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true);
base.TestBeatmapComboColoursOverrideWithDefaultColours(useBeatmapSkin);
AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
}
[TestCase(true, true)]
[TestCase(false, true)]
[TestCase(true, false)]
[TestCase(false, false)]
public override void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour)
{
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, false);
base.TestBeatmapNoComboColours(useBeatmapSkin, useBeatmapColour);
AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
}
[TestCase(true, true)]
[TestCase(false, true)]
[TestCase(true, false)]
[TestCase(false, false)]
public override void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour)
{
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, false);
base.TestBeatmapNoComboColoursSkinOverride(useBeatmapSkin, useBeatmapColour);
AddAssert("is custom user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours));
}
[TestCase(true)]
[TestCase(false)]
public void TestBeatmapHyperDashColours(bool useBeatmapSkin)
{
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true);
ConfigureTest(useBeatmapSkin, true, true);
AddAssert("is custom hyper dash colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashColour == TestBeatmapSkin.HYPER_DASH_COLOUR);
AddAssert("is custom hyper dash after image colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashAfterImageColour == TestBeatmapSkin.HYPER_DASH_AFTER_IMAGE_COLOUR);
AddAssert("is custom hyper dash fruit colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashFruitColour == TestBeatmapSkin.HYPER_DASH_FRUIT_COLOUR);
}
[TestCase(true)]
[TestCase(false)]
public void TestBeatmapHyperDashColoursOverride(bool useBeatmapSkin)
{
TestBeatmap = new CatchCustomSkinWorkingBeatmap(audio, true);
ConfigureTest(useBeatmapSkin, false, true);
AddAssert("is custom hyper dash colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashColour == TestSkin.HYPER_DASH_COLOUR);
AddAssert("is custom hyper dash after image colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashAfterImageColour == TestSkin.HYPER_DASH_AFTER_IMAGE_COLOUR);
AddAssert("is custom hyper dash fruit colours", () => ((CatchExposedPlayer)TestPlayer).UsableHyperDashFruitColour == TestSkin.HYPER_DASH_FRUIT_COLOUR);
}
protected override ExposedPlayer CreateTestPlayer(bool userHasCustomColours) => new CatchExposedPlayer(userHasCustomColours);
private class CatchExposedPlayer : ExposedPlayer
{
public CatchExposedPlayer(bool userHasCustomColours)
: base(userHasCustomColours)
{
}
public Color4 UsableHyperDashColour =>
GameplayClockContainer.ChildrenOfType<BeatmapSkinProvidingContainer>()
.First()
.GetConfig<SkinCustomColourLookup, Color4>(new SkinCustomColourLookup(CatchSkinColour.HyperDash))?
.Value ?? Color4.Red;
public Color4 UsableHyperDashAfterImageColour =>
GameplayClockContainer.ChildrenOfType<BeatmapSkinProvidingContainer>()
.First()
.GetConfig<SkinCustomColourLookup, Color4>(new SkinCustomColourLookup(CatchSkinColour.HyperDashAfterImage))?
.Value ?? Color4.Red;
public Color4 UsableHyperDashFruitColour =>
GameplayClockContainer.ChildrenOfType<BeatmapSkinProvidingContainer>()
.First()
.GetConfig<SkinCustomColourLookup, Color4>(new SkinCustomColourLookup(CatchSkinColour.HyperDashFruit))?
.Value ?? Color4.Red;
}
private class CatchCustomSkinWorkingBeatmap : CustomSkinWorkingBeatmap
{
public CatchCustomSkinWorkingBeatmap(AudioManager audio, bool hasColours)
: base(createBeatmap(), audio, hasColours)
{
}
private static IBeatmap createBeatmap() =>
new Beatmap
{
BeatmapInfo =
{
BeatmapSet = new BeatmapSetInfo(),
Ruleset = new CatchRuleset().RulesetInfo
},
HitObjects = { new Fruit { StartTime = 1816, X = 56, NewCombo = true } }
};
}
}
}

View File

@ -2,14 +2,14 @@
<Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />

View File

@ -59,8 +59,8 @@ namespace osu.Game.Rulesets.Catch.Mods
{
base.ApplySettings(difficulty);
difficulty.CircleSize = CircleSize.Value;
difficulty.ApproachRate = ApproachRate.Value;
ApplySetting(CircleSize, cs => difficulty.CircleSize = cs);
ApplySetting(ApproachRate, ar => difficulty.ApproachRate = ar);
}
}
}

View File

@ -5,6 +5,13 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>catch the fruit. to the beat.</Description>
</PropertyGroup>
<PropertyGroup Label="Nuget">
<Title>osu!catch (ruleset)</Title>
<PackageId>ppy.osu.Game.Rulesets.Catch</PackageId>
<IsPackable>true</IsPackable>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
</ItemGroup>

View File

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

View File

@ -355,7 +355,11 @@ namespace osu.Game.Rulesets.Mania.Tests
protected override bool PauseOnFocusLost => false;
public ScoreAccessibleReplayPlayer(Score score)
: base(score, false, false)
: base(score, new PlayerConfiguration
{
AllowPause = false,
ShowResults = false,
})
{
}
}

View File

@ -176,7 +176,11 @@ namespace osu.Game.Rulesets.Mania.Tests
protected override bool PauseOnFocusLost => false;
public ScoreAccessibleReplayPlayer(Score score)
: base(score, false, false)
: base(score, new PlayerConfiguration
{
AllowPause = false,
ShowResults = false,
})
{
}
}

View File

@ -2,14 +2,14 @@
<Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />

View File

@ -5,6 +5,13 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>smash the keys. to the beat.</Description>
</PropertyGroup>
<PropertyGroup Label="Nuget">
<Title>osu!mania (ruleset)</Title>
<PackageId>ppy.osu.Game.Rulesets.Mania</PackageId>
<IsPackable>true</IsPackable>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
</ItemGroup>

View File

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

View File

@ -1,13 +1,17 @@
// 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.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Tests.Mods
@ -18,8 +22,23 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
public void TestNoAdjustment() => CreateModTest(new ModTestData
{
Mod = new OsuModDifficultyAdjust(),
Beatmap = new Beatmap
{
BeatmapInfo = new BeatmapInfo
{
BaseDifficulty = new BeatmapDifficulty
{
CircleSize = 8
}
},
HitObjects = new List<HitObject>
{
new HitCircle { StartTime = 1000 },
new HitCircle { StartTime = 2000 }
}
},
Autoplay = true,
PassCondition = checkSomeHit
PassCondition = () => checkSomeHit() && checkObjectsScale(0.29f)
});
[Test]

View File

@ -1,103 +1,91 @@
// 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;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.IO.Stores;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Play;
using osu.Game.Skinning;
using osu.Game.Tests.Visual;
using osu.Game.Tests.Beatmaps;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestSceneLegacyBeatmapSkin : ScreenTestScene
public class TestSceneLegacyBeatmapSkin : LegacyBeatmapSkinColourTest
{
[Resolved]
private AudioManager audio { get; set; }
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
config.BindWith(OsuSetting.BeatmapSkins, BeatmapSkins);
config.BindWith(OsuSetting.BeatmapColours, BeatmapColours);
}
[TestCase(true, true)]
[TestCase(true, false)]
[TestCase(false, true)]
[TestCase(false, false)]
public override void TestBeatmapComboColours(bool userHasCustomColours, bool useBeatmapSkin)
{
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, true);
base.TestBeatmapComboColours(userHasCustomColours, useBeatmapSkin);
AddAssert("is beatmap skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours));
}
[TestCase(true)]
[TestCase(false)]
public void TestBeatmapComboColours(bool customSkinColoursPresent)
public override void TestBeatmapComboColoursOverride(bool useBeatmapSkin)
{
ExposedPlayer player = null;
AddStep("load coloured beatmap", () => player = loadBeatmap(customSkinColoursPresent, true));
AddUntilStep("wait for player", () => player.IsLoaded);
AddAssert("is beatmap skin colours", () => player.UsableComboColours.SequenceEqual(TestBeatmapSkin.Colours));
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, true);
base.TestBeatmapComboColoursOverride(useBeatmapSkin);
AddAssert("is user custom skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours));
}
[Test]
public void TestBeatmapNoComboColours()
[TestCase(true)]
[TestCase(false)]
public override void TestBeatmapComboColoursOverrideWithDefaultColours(bool useBeatmapSkin)
{
ExposedPlayer player = null;
AddStep("load no-colour beatmap", () => player = loadBeatmap(false, false));
AddUntilStep("wait for player", () => player.IsLoaded);
AddAssert("is default user skin colours", () => player.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, true);
base.TestBeatmapComboColoursOverrideWithDefaultColours(useBeatmapSkin);
AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
}
[Test]
public void TestBeatmapNoComboColoursSkinOverride()
[TestCase(true, true)]
[TestCase(false, true)]
[TestCase(true, false)]
[TestCase(false, false)]
public override void TestBeatmapNoComboColours(bool useBeatmapSkin, bool useBeatmapColour)
{
ExposedPlayer player = null;
AddStep("load custom-skin colour", () => player = loadBeatmap(true, false));
AddUntilStep("wait for player", () => player.IsLoaded);
AddAssert("is custom user skin colours", () => player.UsableComboColours.SequenceEqual(TestSkin.Colours));
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, false);
base.TestBeatmapNoComboColours(useBeatmapSkin, useBeatmapColour);
AddAssert("is default user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(SkinConfiguration.DefaultComboColours));
}
private ExposedPlayer loadBeatmap(bool userHasCustomColours, bool beatmapHasColours)
[TestCase(true, true)]
[TestCase(false, true)]
[TestCase(true, false)]
[TestCase(false, false)]
public override void TestBeatmapNoComboColoursSkinOverride(bool useBeatmapSkin, bool useBeatmapColour)
{
ExposedPlayer player;
Beatmap.Value = new CustomSkinWorkingBeatmap(audio, beatmapHasColours);
LoadScreen(player = new ExposedPlayer(userHasCustomColours));
return player;
TestBeatmap = new OsuCustomSkinWorkingBeatmap(audio, false);
base.TestBeatmapNoComboColoursSkinOverride(useBeatmapSkin, useBeatmapColour);
AddAssert("is custom user skin colours", () => TestPlayer.UsableComboColours.SequenceEqual(TestSkin.Colours));
}
private class ExposedPlayer : Player
private class OsuCustomSkinWorkingBeatmap : CustomSkinWorkingBeatmap
{
private readonly bool userHasCustomColours;
public ExposedPlayer(bool userHasCustomColours)
: base(false, false)
public OsuCustomSkinWorkingBeatmap(AudioManager audio, bool hasColours)
: base(createBeatmap(), audio, hasColours)
{
this.userHasCustomColours = userHasCustomColours;
}
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs<ISkinSource>(new TestSkin(userHasCustomColours));
return dependencies;
}
public IReadOnlyList<Color4> UsableComboColours =>
GameplayClockContainer.ChildrenOfType<BeatmapSkinProvidingContainer>()
.First()
.GetConfig<GlobalSkinColours, IReadOnlyList<Color4>>(GlobalSkinColours.ComboColours)?.Value;
}
private class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap
{
private readonly bool hasColours;
public CustomSkinWorkingBeatmap(AudioManager audio, bool hasColours)
: base(new Beatmap
private static IBeatmap createBeatmap() =>
new Beatmap
{
BeatmapInfo =
{
@ -105,50 +93,7 @@ namespace osu.Game.Rulesets.Osu.Tests
Ruleset = new OsuRuleset().RulesetInfo,
},
HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
}, null, null, audio)
{
this.hasColours = hasColours;
}
protected override ISkin GetSkin() => new TestBeatmapSkin(BeatmapInfo, hasColours);
}
private class TestBeatmapSkin : LegacyBeatmapSkin
{
public static Color4[] Colours { get; } =
{
new Color4(50, 100, 150, 255),
new Color4(40, 80, 120, 255),
};
public TestBeatmapSkin(BeatmapInfo beatmap, bool hasColours)
: base(beatmap, new ResourceStore<byte[]>(), null)
{
if (hasColours)
Configuration.AddComboColours(Colours);
}
}
private class TestSkin : LegacySkin, ISkinSource
{
public static Color4[] Colours { get; } =
{
new Color4(150, 100, 50, 255),
new Color4(20, 20, 20, 255),
};
public TestSkin(bool hasCustomColours)
: base(new SkinInfo(), null, null, string.Empty)
{
if (hasCustomColours)
Configuration.AddComboColours(Colours);
}
public event Action SourceChanged
{
add { }
remove { }
}
};
}
}
}

View File

@ -439,7 +439,11 @@ namespace osu.Game.Rulesets.Osu.Tests
protected override bool PauseOnFocusLost => false;
public ScoreAccessibleReplayPlayer(Score score)
: base(score, false, false)
: base(score, new PlayerConfiguration
{
AllowPause = false,
ShowResults = false,
})
{
}
}

View File

@ -52,6 +52,31 @@ namespace osu.Game.Rulesets.Osu.Tests
checkNextHitObject(null);
}
[Test]
public void TestBeatmapColourDefault()
{
AddStep("enable user provider", () => testUserSkin.Enabled = true);
AddStep("enable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, true));
AddStep("enable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, true));
checkNextHitObject("beatmap");
AddStep("enable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, true));
AddStep("disable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, false));
checkNextHitObject("beatmap");
AddStep("disable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, false));
AddStep("enable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, true));
checkNextHitObject("user");
AddStep("disable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, false));
AddStep("disable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, false));
checkNextHitObject("user");
AddStep("disable user provider", () => testUserSkin.Enabled = false);
checkNextHitObject(null);
}
private void checkNextHitObject(string skin) =>
AddUntilStep($"check skin from {skin}", () =>
{

View File

@ -378,7 +378,11 @@ namespace osu.Game.Rulesets.Osu.Tests
protected override bool PauseOnFocusLost => false;
public ScoreAccessibleReplayPlayer(Score score)
: base(score, false, false)
: base(score, new PlayerConfiguration
{
AllowPause = false,
ShowResults = false,
})
{
}
}

View File

@ -1,9 +1,11 @@
// 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.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Mods;
@ -34,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Tests
[TestCase(true)]
public void TestLongSpinner(bool autoplay)
{
AddStep("Very short spinner", () => SetContents(() => testSingle(5, autoplay, 2000)));
AddStep("Very long spinner", () => SetContents(() => testSingle(5, autoplay, 4000)));
AddUntilStep("Wait for completion", () => drawableSpinner.Result.HasResult);
AddUntilStep("Check correct progress", () => drawableSpinner.Progress == (autoplay ? 1 : 0));
}
@ -55,7 +57,11 @@ namespace osu.Game.Rulesets.Osu.Tests
var spinner = new Spinner
{
StartTime = Time.Current + delay,
EndTime = Time.Current + delay + length
EndTime = Time.Current + delay + length,
Samples = new List<HitSampleInfo>
{
new HitSampleInfo("hitnormal")
}
};
spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = circleSize });

View File

@ -2,14 +2,14 @@
<Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />

View File

@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
if (Attributes.ApproachRate > 10.33)
approachRateFactor += 0.4 * (Attributes.ApproachRate - 10.33);
else if (Attributes.ApproachRate < 8.0)
approachRateFactor += 0.1 * (8.0 - Attributes.ApproachRate);
approachRateFactor += 0.01 * (8.0 - Attributes.ApproachRate);
aimValue *= 1.0 + Math.Min(approachRateFactor, approachRateFactor * (totalHits / 1000.0));

View File

@ -30,6 +30,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => DrawableObject.HitArea.ReceivePositionalInputAt(screenSpacePos);
public override Quad SelectionQuad => DrawableObject.HitArea.ScreenSpaceDrawQuad;
public override Quad SelectionQuad => CirclePiece.ScreenSpaceDrawQuad;
}
}

View File

@ -44,6 +44,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
[Resolved(CanBeNull = true)]
private IEditorChangeHandler changeHandler { get; set; }
public override Quad SelectionQuad => BodyPiece.ScreenSpaceDrawQuad;
private readonly BindableList<PathControlPoint> controlPoints = new BindableList<PathControlPoint>();
private readonly IBindable<int> pathVersion = new Bindable<int>();

View File

@ -157,10 +157,16 @@ namespace osu.Game.Rulesets.Osu.Edit
foreach (var h in hitObjects)
{
h.Position = new Vector2(
quad.TopLeft.X + (h.X - quad.TopLeft.X) / quad.Width * (quad.Width + scale.X),
quad.TopLeft.Y + (h.Y - quad.TopLeft.Y) / quad.Height * (quad.Height + scale.Y)
);
var newPosition = h.Position;
// guard against no-ops and NaN.
if (scale.X != 0 && quad.Width > 0)
newPosition.X = quad.TopLeft.X + (h.X - quad.TopLeft.X) / quad.Width * (quad.Width + scale.X);
if (scale.Y != 0 && quad.Height > 0)
newPosition.Y = quad.TopLeft.Y + (h.Y - quad.TopLeft.Y) / quad.Height * (quad.Height + scale.Y);
h.Position = newPosition;
}
}
@ -230,7 +236,20 @@ namespace osu.Game.Rulesets.Osu.Edit
/// </summary>
/// <param name="hitObjects">The hit objects to calculate a quad for.</param>
private Quad getSurroundingQuad(OsuHitObject[] hitObjects) =>
getSurroundingQuad(hitObjects.SelectMany(h => new[] { h.Position, h.EndPosition }));
getSurroundingQuad(hitObjects.SelectMany(h =>
{
if (h is IHasPath path)
{
return new[]
{
h.Position,
// can't use EndPosition for reverse slider cases.
h.Position + path.Path.PositionAt(1)
};
}
return new[] { h.Position };
}));
/// <summary>
/// Returns a gamefield-space quad surrounding the provided points.

View File

@ -59,8 +59,8 @@ namespace osu.Game.Rulesets.Osu.Mods
{
base.ApplySettings(difficulty);
difficulty.CircleSize = CircleSize.Value;
difficulty.ApproachRate = ApproachRate.Value;
ApplySetting(CircleSize, cs => difficulty.CircleSize = cs);
ApplySetting(ApproachRate, ar => difficulty.ApproachRate = ar);
}
}
}

View File

@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Mods
var destination = e.MousePosition;
FlashlightPosition = Interpolation.ValueAt(
Math.Clamp(Clock.ElapsedFrameTime, 0, follow_delay), position, destination, 0, follow_delay, Easing.Out);
Math.Min(Math.Abs(Clock.ElapsedFrameTime), follow_delay), position, destination, 0, follow_delay, Easing.Out);
return base.OnMouseMove(e);
}

View File

@ -130,12 +130,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
if (tracking.NewValue)
{
spinningSample?.Play();
spinningSample?.VolumeTo(1, 200);
spinningSample?.Play(!spinningSample.IsPlaying);
spinningSample?.VolumeTo(1, 300);
}
else
{
spinningSample?.VolumeTo(0, 200).Finally(_ => spinningSample.Stop());
spinningSample?.VolumeTo(0, 300).OnComplete(_ => spinningSample.Stop());
}
}

View File

@ -20,17 +20,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
private double lastTrailTime;
private IBindable<float> cursorSize;
public LegacyCursorTrail()
{
Blending = BlendingParameters.Additive;
}
[BackgroundDependencyLoader]
private void load(ISkinSource skin, OsuConfigManager config)
{
Texture = skin.GetTexture("cursortrail");
disjointTrail = skin.GetTexture("cursormiddle") == null;
Blending = !disjointTrail ? BlendingParameters.Additive : BlendingParameters.Inherit;
if (Texture != null)
{
// stable "magic ratio". see OsuPlayfieldAdjustmentContainer for full explanation.

View File

@ -5,6 +5,13 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>click the circles. to the beat.</Description>
</PropertyGroup>
<PropertyGroup Label="Nuget">
<Title>osu! (ruleset)</Title>
<PackageId>ppy.osu.Game.Rulesets.Osu</PackageId>
<IsPackable>true</IsPackable>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
</ItemGroup>

View File

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

View File

@ -23,6 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
[TestCase("sample-to-type-conversions")]
[TestCase("slider-conversion-v6")]
[TestCase("slider-conversion-v14")]
[TestCase("slider-generating-drumroll-2")]
public void Test(string name) => base.Test(name);
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)

View File

@ -2,14 +2,14 @@
<Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />

View File

@ -160,7 +160,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
}
}
private bool shouldConvertSliderToHits(HitObject obj, IBeatmap beatmap, IHasDistance distanceData, out double taikoDuration, out double tickSpacing)
private bool shouldConvertSliderToHits(HitObject obj, IBeatmap beatmap, IHasDistance distanceData, out int taikoDuration, out double tickSpacing)
{
// DO NOT CHANGE OR REFACTOR ANYTHING IN HERE WITHOUT TESTING AGAINST _ALL_ BEATMAPS.
// Some of these calculations look redundant, but they are not - extremely small floating point errors are introduced to maintain 1:1 compatibility with stable.
@ -185,7 +185,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
// The velocity and duration of the taiko hit object - calculated as the velocity of a drum roll.
double taikoVelocity = sliderScoringPointDistance * beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate;
taikoDuration = distance / taikoVelocity * beatLength;
taikoDuration = (int)(distance / taikoVelocity * beatLength);
if (isForCurrentRuleset)
{
@ -200,7 +200,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
beatLength = timingPoint.BeatLength;
// If the drum roll is to be split into hit circles, assume the ticks are 1/8 spaced within the duration of one beat
tickSpacing = Math.Min(beatLength / beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate, taikoDuration / spans);
tickSpacing = Math.Min(beatLength / beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate, (double)taikoDuration / spans);
return tickSpacing > 0
&& distance / osuVelocity * 1000 < 2 * beatLength;

View File

@ -1,7 +1,9 @@
{
"Mappings": [{
"Mappings": [
{
"StartTime": 2000,
"Objects": [{
"Objects": [
{
"StartTime": 2000,
"EndTime": 2000,
"IsRim": false,
@ -23,7 +25,8 @@
},
{
"StartTime": 4000,
"Objects": [{
"Objects": [
{
"StartTime": 4000,
"EndTime": 4000,
"IsRim": false,
@ -45,7 +48,8 @@
},
{
"StartTime": 6000,
"Objects": [{
"Objects": [
{
"StartTime": 6000,
"EndTime": 6000,
"IsRim": true,
@ -76,300 +80,13 @@
},
{
"StartTime": 8000,
"Objects": [{
"Objects": [
{
"StartTime": 8000,
"EndTime": 8000,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8026,
"EndTime": 8026,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8053,
"EndTime": 8053,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8080,
"EndTime": 8080,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8107,
"EndTime": 8107,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8133,
"EndTime": 8133,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8160,
"EndTime": 8160,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8187,
"EndTime": 8187,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8214,
"EndTime": 8214,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8241,
"EndTime": 8241,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8267,
"EndTime": 8267,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8294,
"EndTime": 8294,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8321,
"EndTime": 8321,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8348,
"EndTime": 8348,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8374,
"EndTime": 8374,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8401,
"EndTime": 8401,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8428,
"EndTime": 8428,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8455,
"EndTime": 8455,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8482,
"EndTime": 8482,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8508,
"EndTime": 8508,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8535,
"EndTime": 8535,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8562,
"EndTime": 8562,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8589,
"EndTime": 8589,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8615,
"EndTime": 8615,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8642,
"EndTime": 8642,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8669,
"EndTime": 8669,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8696,
"EndTime": 8696,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8723,
"EndTime": 8723,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8749,
"EndTime": 8749,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8776,
"EndTime": 8776,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8803,
"EndTime": 8803,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8830,
"EndTime": 8830,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsSwell": false,
"IsStrong": false
},
{
"StartTime": 8857,
"EndTime": 8857,
"IsRim": false,
"IsCentre": true,
"IsDrumRoll": false,
"IsCentre": false,
"IsDrumRoll": true,
"IsSwell": false,
"IsStrong": false
}

View File

@ -0,0 +1,18 @@
{
"Mappings": [
{
"StartTime": 51532,
"Objects": [
{
"StartTime": 51532,
"EndTime": 52301,
"IsRim": false,
"IsCentre": false,
"IsDrumRoll": true,
"IsSwell": false,
"IsStrong": false
}
]
}
]
}

View File

@ -0,0 +1,19 @@
osu file format v14
[General]
Mode: 0
[Difficulty]
HPDrainRate:2
CircleSize:3.2
OverallDifficulty:2
ApproachRate:3
SliderMultiplier:0.999999999999999
SliderTickRate:1
[TimingPoints]
763,384.615384615385,4,2,0,70,1,0
49993,-90.9090909090909,4,2,0,75,0,1
[HitObjects]
51,245,51532,2,0,P|18:150|17:122,2,110.000003356934,0|8|0,0:0|0:0|0:0,0:0:0:0:

View File

@ -5,6 +5,13 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>bash the drum. to the beat.</Description>
</PropertyGroup>
<PropertyGroup Label="Nuget">
<Title>osu!taiko (ruleset)</Title>
<PackageId>ppy.osu.Game.Rulesets.Taiko</PackageId>
<IsPackable>true</IsPackable>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
</ItemGroup>

View File

@ -95,6 +95,26 @@ namespace osu.Game.Tests.Beatmaps.Formats
}
}
[Test]
public void TestOutOfOrderStartTimes()
{
var decoder = new LegacyStoryboardDecoder();
using (var resStream = TestResources.OpenResource("out-of-order-starttimes.osb"))
using (var stream = new LineBufferedReader(resStream))
{
var storyboard = decoder.Decode(stream);
StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3);
Assert.AreEqual(2, background.Elements.Count);
Assert.AreEqual(1500, background.Elements[0].StartTime);
Assert.AreEqual(1000, background.Elements[1].StartTime);
Assert.AreEqual(1000, storyboard.EarliestEventTime);
}
}
[Test]
public void TestDecodeVariableWithSuffix()
{

View File

@ -10,9 +10,11 @@ using NUnit.Framework;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics.Audio;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
using osu.Framework.Testing;
using osu.Game.Audio;
using osu.Game.IO;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
@ -27,7 +29,7 @@ using osu.Game.Tests.Visual;
namespace osu.Game.Tests.Gameplay
{
[HeadlessTest]
public class TestSceneStoryboardSamples : OsuTestScene
public class TestSceneStoryboardSamples : OsuTestScene, IStorageResourceProvider
{
[Test]
public void TestRetrieveTopLevelSample()
@ -35,7 +37,7 @@ namespace osu.Game.Tests.Gameplay
ISkin skin = null;
SampleChannel channel = null;
AddStep("create skin", () => skin = new TestSkin("test-sample", Audio));
AddStep("create skin", () => skin = new TestSkin("test-sample", this));
AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("test-sample")));
AddAssert("sample is non-null", () => channel != null);
@ -47,7 +49,7 @@ namespace osu.Game.Tests.Gameplay
ISkin skin = null;
SampleChannel channel = null;
AddStep("create skin", () => skin = new TestSkin("folder/test-sample", Audio));
AddStep("create skin", () => skin = new TestSkin("folder/test-sample", this));
AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("folder/test-sample")));
AddAssert("sample is non-null", () => channel != null);
@ -105,7 +107,7 @@ namespace osu.Game.Tests.Gameplay
AddStep("setup storyboard sample", () =>
{
Beatmap.Value = new TestCustomSkinWorkingBeatmap(new OsuRuleset().RulesetInfo, Audio);
Beatmap.Value = new TestCustomSkinWorkingBeatmap(new OsuRuleset().RulesetInfo, this);
SelectedMods.Value = new[] { testedMod };
var beatmapSkinSourceContainer = new BeatmapSkinProvidingContainer(Beatmap.Value.Skin);
@ -128,8 +130,8 @@ namespace osu.Game.Tests.Gameplay
private class TestSkin : LegacySkin
{
public TestSkin(string resourceName, AudioManager audioManager)
: base(DefaultLegacySkin.Info, new TestResourceStore(resourceName), audioManager, "skin.ini")
public TestSkin(string resourceName, IStorageResourceProvider resources)
: base(DefaultLegacySkin.Info, new TestResourceStore(resourceName), resources, "skin.ini")
{
}
}
@ -158,15 +160,15 @@ namespace osu.Game.Tests.Gameplay
private class TestCustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap
{
private readonly AudioManager audio;
private readonly IStorageResourceProvider resources;
public TestCustomSkinWorkingBeatmap(RulesetInfo ruleset, AudioManager audio)
: base(ruleset, null, audio)
public TestCustomSkinWorkingBeatmap(RulesetInfo ruleset, IStorageResourceProvider resources)
: base(ruleset, null, resources.AudioManager)
{
this.audio = audio;
this.resources = resources;
}
protected override ISkin GetSkin() => new TestSkin("test-sample", audio);
protected override ISkin GetSkin() => new TestSkin("test-sample", resources);
}
private class TestDrawableStoryboardSample : DrawableStoryboardSample
@ -176,5 +178,13 @@ namespace osu.Game.Tests.Gameplay
{
}
}
#region IResourceStorageProvider
public AudioManager AudioManager => Audio;
public IResourceStore<byte[]> Files => null;
public IResourceStore<TextureUpload> CreateTextureLoaderStore(IResourceStore<byte[]> underlyingStore) => null;
#endregion
}
}

View File

@ -246,5 +246,32 @@ namespace osu.Game.Tests.NonVisual
Assert.That(cpi.DifficultyPoints.Count, Is.EqualTo(0));
Assert.That(cpi.AllControlPoints.Count, Is.EqualTo(0));
}
[Test]
public void TestCreateCopyIsDeepClone()
{
var cpi = new ControlPointInfo();
cpi.Add(1000, new TimingControlPoint { BeatLength = 500 });
var cpiCopy = cpi.CreateCopy();
cpiCopy.Add(2000, new TimingControlPoint { BeatLength = 500 });
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
Assert.That(cpiCopy.Groups.Count, Is.EqualTo(2));
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(1));
Assert.That(cpiCopy.TimingPoints.Count, Is.EqualTo(2));
Assert.That(cpi.TimingPoints[0], Is.Not.SameAs(cpiCopy.TimingPoints[0]));
Assert.That(cpi.TimingPoints[0].BeatLengthBindable, Is.Not.SameAs(cpiCopy.TimingPoints[0].BeatLengthBindable));
Assert.That(cpi.TimingPoints[0].BeatLength, Is.EqualTo(cpiCopy.TimingPoints[0].BeatLength));
cpi.TimingPoints[0].BeatLength = 800;
Assert.That(cpi.TimingPoints[0].BeatLength, Is.Not.EqualTo(cpiCopy.TimingPoints[0].BeatLength));
}
}
}

View File

@ -0,0 +1,57 @@
// 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 Humanizer;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Online.Multiplayer;
using osu.Game.Tests.Visual.Multiplayer;
using osu.Game.Users;
namespace osu.Game.Tests.NonVisual.Multiplayer
{
[HeadlessTest]
public class StatefulMultiplayerClientTest : MultiplayerTestScene
{
[Test]
public void TestPlayingUserTracking()
{
int id = 2000;
AddRepeatStep("add some users", () => Client.AddUser(new User { Id = id++ }), 5);
checkPlayingUserCount(0);
changeState(3, MultiplayerUserState.WaitingForLoad);
checkPlayingUserCount(3);
changeState(3, MultiplayerUserState.Playing);
checkPlayingUserCount(3);
changeState(3, MultiplayerUserState.Results);
checkPlayingUserCount(0);
changeState(6, MultiplayerUserState.WaitingForLoad);
checkPlayingUserCount(6);
AddStep("another user left", () => Client.RemoveUser(Client.Room?.Users.Last().User));
checkPlayingUserCount(5);
AddStep("leave room", () => Client.LeaveRoom());
checkPlayingUserCount(0);
}
private void checkPlayingUserCount(int expectedCount)
=> AddAssert($"{"user".ToQuantity(expectedCount)} playing", () => Client.CurrentMatchPlayingUserIds.Count == expectedCount);
private void changeState(int userCount, MultiplayerUserState state)
=> AddStep($"{"user".ToQuantity(userCount)} in {state}", () =>
{
for (int i = 0; i < userCount; ++i)
{
var userId = Client.Room?.Users[i].UserID ?? throw new AssertionException("Room cannot be null!");
Client.ChangeUserState(userId, state);
}
});
}
}

View File

@ -0,0 +1,6 @@
[Events]
//Storyboard Layer 0 (Background)
Sprite,Background,TopCentre,"img.jpg",320,240
F,0,1500,1600,0,1
Sprite,Background,TopCentre,"img.jpg",320,240
F,0,1000,1100,0,1

View File

@ -9,7 +9,6 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;

View File

@ -5,7 +5,7 @@ using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Audio.Sample;
using osu.Framework.Configuration.Tracking;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;

View File

@ -82,7 +82,7 @@ namespace osu.Game.Tests.Visual.Background
});
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
AddStep("Stop background preview", () => InputManager.MoveMouseTo(playerLoader.ScreenPos));
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect());
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.CheckBackgroundBlur(playerLoader.ExpectedBackgroundBlur));
}
/// <summary>
@ -106,6 +106,7 @@ namespace osu.Game.Tests.Visual.Background
public void TestStoryboardBackgroundVisibility()
{
performFullSetup();
AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent());
createFakeStoryboard();
AddStep("Enable Storyboard", () =>
{
@ -198,8 +199,9 @@ namespace osu.Game.Tests.Visual.Background
})));
AddUntilStep("Wait for results is current", () => results.IsCurrentScreen());
AddUntilStep("Screen is undimmed, original background retained", () =>
songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && results.IsBlurCorrect());
songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && songSelect.CheckBackgroundBlur(results.ExpectedBackgroundBlur));
}
/// <summary>
@ -224,7 +226,7 @@ namespace osu.Game.Tests.Visual.Background
AddStep("Resume PlayerLoader", () => player.Restart());
AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied());
AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos));
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && playerLoader.IsBlurCorrect());
AddUntilStep("Screen is undimmed and user blur removed", () => songSelect.IsBackgroundUndimmed() && songSelect.CheckBackgroundBlur(playerLoader.ExpectedBackgroundBlur));
}
private void createFakeStoryboard() => AddStep("Create storyboard", () =>
@ -274,9 +276,11 @@ namespace osu.Game.Tests.Visual.Background
private class DummySongSelect : PlaySongSelect
{
private FadeAccessibleBackground background;
protected override BackgroundScreen CreateBackground()
{
FadeAccessibleBackground background = new FadeAccessibleBackground(Beatmap.Value);
background = new FadeAccessibleBackground(Beatmap.Value);
DimEnabled.BindTo(background.EnableUserDim);
return background;
}
@ -294,25 +298,27 @@ namespace osu.Game.Tests.Visual.Background
config.BindWith(OsuSetting.BlurLevel, BlurLevel);
}
public bool IsBackgroundDimmed() => ((FadeAccessibleBackground)Background).CurrentColour == OsuColour.Gray(1f - ((FadeAccessibleBackground)Background).CurrentDim);
public bool IsBackgroundDimmed() => background.CurrentColour == OsuColour.Gray(1f - background.CurrentDim);
public bool IsBackgroundUndimmed() => ((FadeAccessibleBackground)Background).CurrentColour == Color4.White;
public bool IsBackgroundUndimmed() => background.CurrentColour == Color4.White;
public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR);
public bool IsUserBlurApplied() => background.CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR);
public bool IsUserBlurDisabled() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(0);
public bool IsUserBlurDisabled() => background.CurrentBlur == new Vector2(0);
public bool IsBackgroundInvisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 0;
public bool IsBackgroundInvisible() => background.CurrentAlpha == 0;
public bool IsBackgroundVisible() => ((FadeAccessibleBackground)Background).CurrentAlpha == 1;
public bool IsBackgroundVisible() => background.CurrentAlpha == 1;
public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR);
public bool IsBlurCorrect() => background.CurrentBlur == new Vector2(BACKGROUND_BLUR);
public bool CheckBackgroundBlur(Vector2 expected) => background.CurrentBlur == expected;
/// <summary>
/// Make sure every time a screen gets pushed, the background doesn't get replaced
/// </summary>
/// <returns>Whether or not the original background (The one created in DummySongSelect) is still the current background</returns>
public bool IsBackgroundCurrent() => ((FadeAccessibleBackground)Background).IsCurrentScreen();
public bool IsBackgroundCurrent() => background?.IsCurrentScreen() == true;
}
private class FadeAccessibleResults : ResultsScreen
@ -324,12 +330,20 @@ namespace osu.Game.Tests.Visual.Background
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR);
public Vector2 ExpectedBackgroundBlur => new Vector2(BACKGROUND_BLUR);
}
private class LoadBlockingTestPlayer : TestPlayer
{
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
protected override BackgroundScreen CreateBackground() =>
new FadeAccessibleBackground(Beatmap.Value);
public override void OnEntering(IScreen last)
{
base.OnEntering(last);
ApplyToBackground(b => ReplacesBackground.BindTo(b.StoryboardReplacesBackground));
}
public new DimmableStoryboard DimmableStoryboard => base.DimmableStoryboard;
@ -354,15 +368,16 @@ namespace osu.Game.Tests.Visual.Background
Thread.Sleep(1);
StoryboardEnabled = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
ReplacesBackground.BindTo(Background.StoryboardReplacesBackground);
DrawableRuleset.IsPaused.BindTo(IsPaused);
}
}
private class TestPlayerLoader : PlayerLoader
{
private FadeAccessibleBackground background;
public VisualSettings VisualSettingsPos => VisualSettings;
public BackgroundScreen ScreenPos => Background;
public BackgroundScreen ScreenPos => background;
public TestPlayerLoader(Player player)
: base(() => player)
@ -371,9 +386,9 @@ namespace osu.Game.Tests.Visual.Background
public void TriggerOnHover() => OnHover(new HoverEvent(new InputState()));
public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR);
public Vector2 ExpectedBackgroundBlur => new Vector2(BACKGROUND_BLUR);
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
protected override BackgroundScreen CreateBackground() => background = new FadeAccessibleBackground(Beatmap.Value);
}
private class FadeAccessibleBackground : BackgroundScreenBeatmap

View File

@ -8,7 +8,6 @@ using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Containers;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using static osu.Game.Tests.Visual.Components.TestScenePreviewTrackManager.TestPreviewTrackManager;
namespace osu.Game.Tests.Visual.Components
{
@ -100,7 +99,7 @@ namespace osu.Game.Tests.Visual.Components
[Test]
public void TestNonPresentTrack()
{
TestPreviewTrack track = null;
TestPreviewTrackManager.TestPreviewTrack track = null;
AddStep("get non-present track", () =>
{
@ -182,9 +181,9 @@ namespace osu.Game.Tests.Visual.Components
AddAssert("track stopped", () => !track.IsRunning);
}
private TestPreviewTrack getTrack() => (TestPreviewTrack)trackManager.Get(null);
private TestPreviewTrackManager.TestPreviewTrack getTrack() => (TestPreviewTrackManager.TestPreviewTrack)trackManager.Get(null);
private TestPreviewTrack getOwnedTrack()
private TestPreviewTrackManager.TestPreviewTrack getOwnedTrack()
{
var track = getTrack();

View File

@ -52,19 +52,19 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("add player 2", () => createLeaderboardScore(player2Score, new User { Username = "Player 2" }));
AddStep("add player 3", () => createLeaderboardScore(player3Score, new User { Username = "Player 3" }));
AddAssert("is player 2 position #1", () => leaderboard.CheckPositionByUsername("Player 2", 1));
AddAssert("is player position #2", () => leaderboard.CheckPositionByUsername("You", 2));
AddAssert("is player 3 position #3", () => leaderboard.CheckPositionByUsername("Player 3", 3));
AddUntilStep("is player 2 position #1", () => leaderboard.CheckPositionByUsername("Player 2", 1));
AddUntilStep("is player position #2", () => leaderboard.CheckPositionByUsername("You", 2));
AddUntilStep("is player 3 position #3", () => leaderboard.CheckPositionByUsername("Player 3", 3));
AddStep("set score above player 3", () => player2Score.Value = playerScore.Value - 500);
AddAssert("is player position #1", () => leaderboard.CheckPositionByUsername("You", 1));
AddAssert("is player 2 position #2", () => leaderboard.CheckPositionByUsername("Player 2", 2));
AddAssert("is player 3 position #3", () => leaderboard.CheckPositionByUsername("Player 3", 3));
AddUntilStep("is player position #1", () => leaderboard.CheckPositionByUsername("You", 1));
AddUntilStep("is player 2 position #2", () => leaderboard.CheckPositionByUsername("Player 2", 2));
AddUntilStep("is player 3 position #3", () => leaderboard.CheckPositionByUsername("Player 3", 3));
AddStep("set score below players", () => player2Score.Value = playerScore.Value - 123456);
AddAssert("is player position #1", () => leaderboard.CheckPositionByUsername("You", 1));
AddAssert("is player 3 position #2", () => leaderboard.CheckPositionByUsername("Player 3", 2));
AddAssert("is player 2 position #3", () => leaderboard.CheckPositionByUsername("Player 2", 3));
AddUntilStep("is player position #1", () => leaderboard.CheckPositionByUsername("You", 1));
AddUntilStep("is player 3 position #2", () => leaderboard.CheckPositionByUsername("Player 3", 2));
AddUntilStep("is player 2 position #3", () => leaderboard.CheckPositionByUsername("Player 2", 3));
}
[Test]
@ -95,7 +95,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
public bool CheckPositionByUsername(string username, int? expectedPosition)
{
var scoreItem = this.FirstOrDefault(i => i.User.Username == username);
var scoreItem = this.FirstOrDefault(i => i.User?.Username == username);
return scoreItem != null && scoreItem.ScorePosition == expectedPosition;
}

View File

@ -244,7 +244,7 @@ namespace osu.Game.Tests.Visual.Gameplay
internal class TestKeyBindingContainer : KeyBindingContainer<TestAction>
{
public override IEnumerable<KeyBinding> DefaultKeyBindings => new[]
public override IEnumerable<IKeyBinding> DefaultKeyBindings => new[]
{
new KeyBinding(InputKey.MouseLeft, TestAction.Down),
};

View File

@ -179,7 +179,7 @@ namespace osu.Game.Tests.Visual.Gameplay
internal class TestKeyBindingContainer : KeyBindingContainer<TestAction>
{
public override IEnumerable<KeyBinding> DefaultKeyBindings => new[]
public override IEnumerable<IKeyBinding> DefaultKeyBindings => new[]
{
new KeyBinding(InputKey.MouseLeft, TestAction.Down),
};

View File

@ -9,7 +9,7 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD;
namespace osu.Game.Tests.Visual.Gameplay
{

View File

@ -12,6 +12,7 @@ using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Online;
using osu.Game.Online.Spectator;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Osu;
@ -238,6 +239,11 @@ namespace osu.Game.Tests.Visual.Gameplay
private int beatmapId;
public TestSpectatorStreamingClient()
: base(new DevelopmentEndpointConfiguration())
{
}
protected override Task Connect()
{
return Task.CompletedTask;

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
@ -74,6 +75,8 @@ namespace osu.Game.Tests.Visual.Gameplay
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
Debug.Assert(args.NewItems != null);
foreach (int user in args.NewItems)
{
if (user == api.LocalUser.Value.Id)
@ -83,6 +86,8 @@ namespace osu.Game.Tests.Visual.Gameplay
break;
case NotifyCollectionChangedAction.Remove:
Debug.Assert(args.OldItems != null);
foreach (int user in args.OldItems)
{
if (user == api.LocalUser.Value.Id)
@ -298,7 +303,7 @@ namespace osu.Game.Tests.Visual.Gameplay
internal class TestKeyBindingContainer : KeyBindingContainer<TestAction>
{
public override IEnumerable<KeyBinding> DefaultKeyBindings => new[]
public override IEnumerable<IKeyBinding> DefaultKeyBindings => new[]
{
new KeyBinding(InputKey.MouseLeft, TestAction.Down),
};

View File

@ -4,14 +4,14 @@
using System;
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Screens.Multi;
using osu.Game.Screens.OnlinePlay;
using osu.Game.Users;
namespace osu.Game.Tests.Visual.Multiplayer
{
public abstract class RoomManagerTestScene : MultiplayerTestScene
public abstract class RoomManagerTestScene : RoomTestScene
{
[Cached(Type = typeof(IRoomManager))]
protected TestRoomManager RoomManager { get; } = new TestRoomManager();

View File

@ -3,8 +3,8 @@
using System;
using osu.Framework.Bindables;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi;
using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay;
namespace osu.Game.Tests.Visual.Multiplayer
{

View File

@ -0,0 +1,50 @@
// 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;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Screens.OnlinePlay.Multiplayer;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneCreateMultiplayerMatchButton : MultiplayerTestScene
{
private CreateMultiplayerMatchButton button;
public override void SetUpSteps()
{
base.SetUpSteps();
AddStep("create button", () => Child = button = new CreateMultiplayerMatchButton
{
Width = 200,
Height = 100,
Anchor = Anchor.Centre,
Origin = Anchor.Centre
});
}
[Test]
public void TestButtonEnableStateChanges()
{
IDisposable joiningRoomOperation = null;
assertButtonEnableState(true);
AddStep("begin joining room", () => joiningRoomOperation = OngoingOperationTracker.BeginOperation());
assertButtonEnableState(false);
AddStep("end joining room", () => joiningRoomOperation.Dispose());
assertButtonEnableState(true);
AddStep("disconnect client", () => Client.Disconnect());
assertButtonEnableState(false);
AddStep("re-connect client", () => Client.Connect());
assertButtonEnableState(true);
}
private void assertButtonEnableState(bool enabled)
=> AddAssert($"button {(enabled ? "enabled" : "disabled")}", () => button.Enabled.Value == enabled);
}
}

View File

@ -13,12 +13,12 @@ using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Multi;
using osu.Game.Screens.OnlinePlay;
using osu.Game.Tests.Beatmaps;
using osuTK;
using osuTK.Input;
@ -201,11 +201,20 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
[Test]
public void TestDownloadButtonHiddenInitiallyWhenBeatmapExists()
public void TestDownloadButtonHiddenWhenBeatmapExists()
{
createPlaylist(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo);
AddAssert("download button hidden", () => !playlist.ChildrenOfType<BeatmapDownloadTrackingComposite>().Single().IsPresent);
assertDownloadButtonVisible(false);
AddStep("delete beatmap set", () => manager.Delete(manager.QueryBeatmapSets(_ => true).Single()));
assertDownloadButtonVisible(true);
AddStep("undelete beatmap set", () => manager.Undelete(manager.QueryBeatmapSets(_ => true).Single()));
assertDownloadButtonVisible(false);
void assertDownloadButtonVisible(bool visible) => AddUntilStep($"download button {(visible ? "shown" : "hidden")}",
() => playlist.ChildrenOfType<BeatmapDownloadTrackingComposite>().Single().Alpha == (visible ? 1 : 0));
}
[Test]
@ -222,6 +231,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("download buttons shown", () => playlist.ChildrenOfType<BeatmapDownloadTrackingComposite>().All(d => d.IsPresent));
}
[Test]
public void TestExplicitBeatmapItem()
{
var beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
beatmap.BeatmapSet.OnlineInfo.HasExplicitContent = true;
createPlaylist(beatmap);
}
private void moveToItem(int index, Vector2? offset = null)
=> AddStep($"move mouse to item {index}", () => InputManager.MoveMouseTo(playlist.ChildrenOfType<OsuRearrangeableListItem<PlaylistItem>>().ElementAt(index), offset));

View File

@ -4,13 +4,13 @@
using System;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Online.Multiplayer.RoomStatuses;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Online.Rooms.RoomStatuses;
using osu.Game.Screens.OnlinePlay.Lounge.Components;
using osu.Game.Users;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneLoungeRoomInfo : MultiplayerTestScene
public class TestSceneLoungeRoomInfo : RoomTestScene
{
[SetUp]
public new void Setup() => Schedule(() =>

View File

@ -6,10 +6,10 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Screens.OnlinePlay.Lounge.Components;
using osuTK.Graphics;
using osuTK.Input;

View File

@ -5,17 +5,17 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Multi.Components;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneMatchBeatmapDetailArea : MultiplayerTestScene
public class TestSceneMatchBeatmapDetailArea : RoomTestScene
{
[Resolved]
private BeatmapManager beatmapManager { get; set; }

View File

@ -3,15 +3,15 @@
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Users;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneMatchHeader : MultiplayerTestScene
public class TestSceneMatchHeader : RoomTestScene
{
public TestSceneMatchHeader()
{

View File

@ -7,13 +7,13 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Online.API;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneMatchLeaderboard : MultiplayerTestScene
public class TestSceneMatchLeaderboard : RoomTestScene
{
protected override bool UseOnlineAPI => true;

View File

@ -18,12 +18,12 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Multi.Components;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneMatchSongSelect : MultiplayerTestScene
public class TestSceneMatchSongSelect : RoomTestScene
{
[Resolved]
private BeatmapManager beatmapManager { get; set; }

View File

@ -5,7 +5,7 @@ using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Screens;
using osu.Game.Screens;
using osu.Game.Screens.Multi;
using osu.Game.Screens.OnlinePlay;
namespace osu.Game.Tests.Visual.Multiplayer
{
@ -18,24 +18,24 @@ namespace osu.Game.Tests.Visual.Multiplayer
OsuScreenStack screenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both };
screenStack.Push(new TestMultiplayerSubScreen(index));
screenStack.Push(new TestOnlinePlaySubScreen(index));
Children = new Drawable[]
{
screenStack,
new Header(screenStack)
new Header("Multiplayer", screenStack)
};
AddStep("push multi screen", () => screenStack.CurrentScreen.Push(new TestMultiplayerSubScreen(++index)));
AddStep("push multi screen", () => screenStack.CurrentScreen.Push(new TestOnlinePlaySubScreen(++index)));
}
private class TestMultiplayerSubScreen : OsuScreen, IMultiplayerSubScreen
private class TestOnlinePlaySubScreen : OsuScreen, IOnlinePlaySubScreen
{
private readonly int index;
public string ShortTitle => $"Screen {index}";
public TestMultiplayerSubScreen(int index)
public TestOnlinePlaySubScreen(int index)
{
this.index = index;
}

View File

@ -0,0 +1,47 @@
// 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 NUnit.Framework;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Users;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneMultiplayer : MultiplayerTestScene
{
public TestSceneMultiplayer()
{
var multi = new TestMultiplayer();
AddStep("show", () => LoadScreen(multi));
AddUntilStep("wait for loaded", () => multi.IsLoaded);
}
[Test]
public void TestOneUserJoinedMultipleTimes()
{
var user = new User { Id = 33 };
AddRepeatStep("add user multiple times", () => Client.AddUser(user), 3);
AddAssert("room has 2 users", () => Client.Room?.Users.Count == 2);
}
[Test]
public void TestOneUserLeftMultipleTimes()
{
var user = new User { Id = 44 };
AddStep("add user", () => Client.AddUser(user));
AddAssert("room has 2 users", () => Client.Room?.Users.Count == 2);
AddRepeatStep("remove user multiple times", () => Client.RemoveUser(user), 3);
AddAssert("room has 1 user", () => Client.Room?.Users.Count == 1);
}
private class TestMultiplayer : Screens.OnlinePlay.Multiplayer.Multiplayer
{
protected override RoomManager CreateRoomManager() => new TestMultiplayerRoomManager();
}
}
}

View File

@ -13,6 +13,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Database;
using osu.Game.Online;
using osu.Game.Online.Spectator;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Osu.Scoring;
@ -21,12 +22,14 @@ using osu.Game.Scoring;
using osu.Game.Screens.Play.HUD;
using osu.Game.Tests.Visual.Online;
namespace osu.Game.Tests.Visual.Gameplay
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneMultiplayerGameplayLeaderboard : OsuTestScene
public class TestSceneMultiplayerGameplayLeaderboard : MultiplayerTestScene
{
private const int users = 16;
[Cached(typeof(SpectatorStreamingClient))]
private TestMultiplayerStreaming streamingClient = new TestMultiplayerStreaming(16);
private TestMultiplayerStreaming streamingClient = new TestMultiplayerStreaming(users);
[Cached(typeof(UserLookupCache))]
private UserLookupCache lookupCache = new TestSceneCurrentlyPlayingDisplay.TestUserLookupCache();
@ -46,10 +49,12 @@ namespace osu.Game.Tests.Visual.Gameplay
}
[SetUpSteps]
public void SetUpSteps()
public override void SetUpSteps()
{
AddStep("create leaderboard", () =>
{
leaderboard?.Expire();
OsuScoreProcessor scoreProcessor;
Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value);
@ -57,6 +62,9 @@ namespace osu.Game.Tests.Visual.Gameplay
streamingClient.Start(Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0);
Client.CurrentMatchPlayingUserIds.Clear();
Client.CurrentMatchPlayingUserIds.AddRange(streamingClient.PlayingUsers);
Children = new Drawable[]
{
scoreProcessor = new OsuScoreProcessor(),
@ -80,6 +88,12 @@ namespace osu.Game.Tests.Visual.Gameplay
AddRepeatStep("update state", () => streamingClient.RandomlyUpdateState(), 100);
}
[Test]
public void TestUserQuit()
{
AddRepeatStep("mark user quit", () => Client.CurrentMatchPlayingUserIds.RemoveAt(0), users);
}
public class TestMultiplayerStreaming : SpectatorStreamingClient
{
public new BindableList<int> PlayingUsers => (BindableList<int>)base.PlayingUsers;
@ -87,6 +101,7 @@ namespace osu.Game.Tests.Visual.Gameplay
private readonly int totalUsers;
public TestMultiplayerStreaming(int totalUsers)
: base(new DevelopmentEndpointConfiguration())
{
this.totalUsers = totalUsers;
}

View File

@ -0,0 +1,145 @@
// 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;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Extensions;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Catch;
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.Screens.OnlinePlay.Multiplayer;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneMultiplayerMatchSongSelect : RoomTestScene
{
private BeatmapManager manager;
private RulesetStore rulesets;
private List<BeatmapInfo> beatmaps;
private TestMultiplayerMatchSongSelect songSelect;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, Beatmap.Default));
beatmaps = new List<BeatmapInfo>();
for (int i = 0; i < 8; ++i)
{
int beatmapId = 10 * 10 + i;
int length = RNG.Next(30000, 200000);
double bpm = RNG.NextSingle(80, 200);
beatmaps.Add(new BeatmapInfo
{
Ruleset = rulesets.GetRuleset(i % 4),
OnlineBeatmapID = beatmapId,
Length = length,
BPM = bpm,
BaseDifficulty = new BeatmapDifficulty()
});
}
manager.Import(new BeatmapSetInfo
{
OnlineBeatmapSetID = 10,
Hash = Guid.NewGuid().ToString().ComputeMD5Hash(),
Metadata = new BeatmapMetadata
{
Artist = "Some Artist",
Title = "Some Beatmap",
AuthorString = "Some Author"
},
Beatmaps = beatmaps,
DateAdded = DateTimeOffset.UtcNow
}).Wait();
}
public override void SetUpSteps()
{
base.SetUpSteps();
AddStep("reset", () =>
{
Ruleset.Value = new OsuRuleset().RulesetInfo;
Beatmap.SetDefault();
SelectedMods.SetDefault();
});
AddStep("create song select", () => LoadScreen(songSelect = new TestMultiplayerMatchSongSelect()));
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen());
}
[Test]
public void TestBeatmapRevertedOnExitIfNoSelection()
{
BeatmapInfo selectedBeatmap = null;
AddStep("select beatmap",
() => songSelect.Carousel.SelectBeatmap(selectedBeatmap = beatmaps.Where(beatmap => beatmap.RulesetID == new OsuRuleset().LegacyID).ElementAt(1)));
AddUntilStep("wait for selection", () => Beatmap.Value.BeatmapInfo.Equals(selectedBeatmap));
AddStep("exit song select", () => songSelect.Exit());
AddAssert("beatmap reverted", () => Beatmap.IsDefault);
}
[Test]
public void TestModsRevertedOnExitIfNoSelection()
{
AddStep("change mods", () => SelectedMods.Value = new[] { new OsuModDoubleTime() });
AddStep("exit song select", () => songSelect.Exit());
AddAssert("mods reverted", () => SelectedMods.Value.Count == 0);
}
[Test]
public void TestRulesetRevertedOnExitIfNoSelection()
{
AddStep("change ruleset", () => Ruleset.Value = new CatchRuleset().RulesetInfo);
AddStep("exit song select", () => songSelect.Exit());
AddAssert("ruleset reverted", () => Ruleset.Value.Equals(new OsuRuleset().RulesetInfo));
}
[Test]
public void TestBeatmapConfirmed()
{
BeatmapInfo selectedBeatmap = null;
AddStep("change ruleset", () => Ruleset.Value = new TaikoRuleset().RulesetInfo);
AddStep("select beatmap",
() => songSelect.Carousel.SelectBeatmap(selectedBeatmap = beatmaps.First(beatmap => beatmap.RulesetID == new TaikoRuleset().LegacyID)));
AddUntilStep("wait for selection", () => Beatmap.Value.BeatmapInfo.Equals(selectedBeatmap));
AddStep("set mods", () => SelectedMods.Value = new[] { new TaikoModDoubleTime() });
AddStep("confirm selection", () => songSelect.FinaliseSelection());
AddStep("exit song select", () => songSelect.Exit());
AddAssert("beatmap not changed", () => Beatmap.Value.BeatmapInfo.Equals(selectedBeatmap));
AddAssert("ruleset not changed", () => Ruleset.Value.Equals(new TaikoRuleset().RulesetInfo));
AddAssert("mods not changed", () => SelectedMods.Value.Single() is TaikoModDoubleTime);
}
private class TestMultiplayerMatchSongSelect : MultiplayerMatchSongSelect
{
public new BeatmapCarousel Carousel => base.Carousel;
}
}
}

View File

@ -3,22 +3,27 @@
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Multi.RealtimeMultiplayer;
using osu.Game.Screens.Multi.RealtimeMultiplayer.Match;
using osu.Game.Screens.OnlinePlay;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
using osu.Game.Tests.Beatmaps;
using osuTK.Input;
namespace osu.Game.Tests.Visual.RealtimeMultiplayer
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneRealtimeMatchSubScreen : RealtimeMultiplayerTestScene
public class TestSceneMultiplayerMatchSubScreen : MultiplayerTestScene
{
private RealtimeMatchSubScreen screen;
private MultiplayerMatchSubScreen screen;
public TestSceneRealtimeMatchSubScreen()
[Cached]
private OngoingOperationTracker ongoingOperationTracker = new OngoingOperationTracker();
public TestSceneMultiplayerMatchSubScreen()
: base(false)
{
}
@ -32,14 +37,14 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
[SetUpSteps]
public void SetupSteps()
{
AddStep("load match", () => LoadScreen(screen = new RealtimeMatchSubScreen(Room)));
AddStep("load match", () => LoadScreen(screen = new MultiplayerMatchSubScreen(Room)));
AddUntilStep("wait for load", () => screen.IsCurrentScreen());
}
[Test]
public void TestSettingValidity()
{
AddAssert("create button not enabled", () => !this.ChildrenOfType<RealtimeMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
AddAssert("create button not enabled", () => !this.ChildrenOfType<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
AddStep("set playlist", () =>
{
@ -50,7 +55,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
});
});
AddAssert("create button enabled", () => this.ChildrenOfType<RealtimeMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
AddAssert("create button enabled", () => this.ChildrenOfType<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
}
[Test]
@ -67,7 +72,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
AddStep("click create button", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<RealtimeMatchSettingsOverlay.CreateOrUpdateButton>().Single());
InputManager.MoveMouseTo(this.ChildrenOfType<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>().Single());
InputManager.Click(MouseButton.Left);
});

View File

@ -6,14 +6,15 @@ using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Testing;
using osu.Game.Online.RealtimeMultiplayer;
using osu.Game.Screens.Multi.RealtimeMultiplayer.Participants;
using osu.Framework.Utils;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.OnlinePlay.Multiplayer.Participants;
using osu.Game.Users;
using osuTK;
namespace osu.Game.Tests.Visual.RealtimeMultiplayer
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneParticipantsList : RealtimeMultiplayerTestScene
public class TestSceneMultiplayerParticipantsList : MultiplayerTestScene
{
[SetUp]
public new void Setup() => Schedule(() =>
@ -42,6 +43,16 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
AddAssert("two unique panels", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 2);
}
[Test]
public void TestAddNullUser()
{
AddAssert("one unique panel", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 1);
AddStep("add non-resolvable user", () => Client.AddNullUser(-3));
AddUntilStep("two unique panels", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 2);
}
[Test]
public void TestRemoveUser()
{
@ -65,13 +76,13 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
[Test]
public void TestToggleReadyState()
{
AddAssert("ready mark invisible", () => !this.ChildrenOfType<ReadyMark>().Single().IsPresent);
AddAssert("ready mark invisible", () => !this.ChildrenOfType<StateDisplay>().Single().IsPresent);
AddStep("make user ready", () => Client.ChangeState(MultiplayerUserState.Ready));
AddUntilStep("ready mark visible", () => this.ChildrenOfType<ReadyMark>().Single().IsPresent);
AddUntilStep("ready mark visible", () => this.ChildrenOfType<StateDisplay>().Single().IsPresent);
AddStep("make user idle", () => Client.ChangeState(MultiplayerUserState.Idle));
AddUntilStep("ready mark invisible", () => !this.ChildrenOfType<ReadyMark>().Single().IsPresent);
AddUntilStep("ready mark invisible", () => !this.ChildrenOfType<StateDisplay>().Single().IsPresent);
}
[Test]
@ -104,11 +115,11 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
{
Id = i,
Username = $"User {i}",
CurrentModeRank = RNG.Next(1, 100000),
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
});
if (i % 2 == 0)
Client.ChangeUserState(i, MultiplayerUserState.Ready);
Client.ChangeUserState(i, (MultiplayerUserState)RNG.Next(0, (int)MultiplayerUserState.Results + 1));
}
});
}

View File

@ -1,31 +1,38 @@
// 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;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Graphics;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.RealtimeMultiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Screens.Multi.RealtimeMultiplayer.Match;
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
using osu.Game.Tests.Resources;
using osu.Game.Users;
using osuTK;
using osuTK.Input;
namespace osu.Game.Tests.Visual.RealtimeMultiplayer
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneRealtimeReadyButton : RealtimeMultiplayerTestScene
public class TestSceneMultiplayerReadyButton : MultiplayerTestScene
{
private RealtimeReadyButton button;
private MultiplayerReadyButton button;
private BeatmapSetInfo importedSet;
private BeatmapManager beatmaps;
private RulesetStore rulesets;
private IDisposable readyClickOperation;
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
@ -37,11 +44,10 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
[SetUp]
public new void Setup() => Schedule(() =>
{
var beatmap = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First().Beatmaps.First();
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
Beatmap.Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First());
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap);
Child = button = new RealtimeReadyButton
Child = button = new MultiplayerReadyButton
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@ -50,15 +56,43 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
{
Value = new PlaylistItem
{
Beatmap = { Value = beatmap },
Ruleset = { Value = beatmap.Ruleset }
Beatmap = { Value = Beatmap.Value.BeatmapInfo },
Ruleset = { Value = Beatmap.Value.BeatmapInfo.Ruleset }
}
},
OnReadyClick = async () =>
{
readyClickOperation = OngoingOperationTracker.BeginOperation();
if (Client.IsHost && Client.LocalUser?.State == MultiplayerUserState.Ready)
{
await Client.StartMatch();
return;
}
await Client.ToggleReady();
readyClickOperation.Dispose();
}
};
Client.AddUser(API.LocalUser.Value);
});
[Test]
public void TestDeletedBeatmapDisableReady()
{
OsuButton readyButton = null;
AddAssert("ensure ready button enabled", () =>
{
readyButton = button.ChildrenOfType<OsuButton>().Single();
return readyButton.Enabled.Value;
});
AddStep("delete beatmap", () => beatmaps.Delete(importedSet));
AddAssert("ready button disabled", () => !readyButton.Enabled.Value);
AddStep("undelete beatmap", () => beatmaps.Undelete(importedSet));
AddAssert("ready button enabled back", () => readyButton.Enabled.Value);
}
[Test]
public void TestToggleStateWhenNotHost()
{
@ -90,8 +124,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
addClickButtonStep();
AddAssert("user is ready", () => Client.Room?.Users[0].State == MultiplayerUserState.Ready);
addClickButtonStep();
AddAssert("match started", () => Client.Room?.Users[0].State == MultiplayerUserState.WaitingForLoad);
verifyGameplayStartFlow();
}
[Test]
@ -106,8 +139,7 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
addClickButtonStep();
AddStep("make user host", () => Client.TransferHost(Client.Room?.Users[0].UserID ?? 0));
addClickButtonStep();
AddAssert("match started", () => Client.Room?.Users[0].State == MultiplayerUserState.WaitingForLoad);
verifyGameplayStartFlow();
}
[Test]
@ -126,10 +158,50 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
AddAssert("match not started", () => Client.Room?.Users[0].State == MultiplayerUserState.Idle);
}
[TestCase(true)]
[TestCase(false)]
public void TestManyUsersChangingState(bool isHost)
{
const int users = 10;
AddStep("setup", () =>
{
Client.TransferHost(Client.Room?.Users[0].UserID ?? 0);
for (int i = 0; i < users; i++)
Client.AddUser(new User { Id = i, Username = "Another user" });
});
if (!isHost)
AddStep("transfer host", () => Client.TransferHost(2));
addClickButtonStep();
AddRepeatStep("change user ready state", () =>
{
Client.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);
if (nextUnready != null)
Client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready);
}, users);
}
private void addClickButtonStep() => AddStep("click button", () =>
{
InputManager.MoveMouseTo(button);
InputManager.Click(MouseButton.Left);
});
private void verifyGameplayStartFlow()
{
addClickButtonStep();
AddAssert("user waiting for load", () => Client.Room?.Users[0].State == MultiplayerUserState.WaitingForLoad);
AddAssert("ready button disabled", () => !button.ChildrenOfType<OsuButton>().Single().Enabled.Value);
AddStep("transitioned to gameplay", () => readyClickOperation.Dispose());
AddAssert("ready button enabled", () => button.ChildrenOfType<OsuButton>().Single().Enabled.Value);
}
}
}

View File

@ -4,15 +4,15 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
namespace osu.Game.Tests.Visual.RealtimeMultiplayer
namespace osu.Game.Tests.Visual.Multiplayer
{
[HeadlessTest]
public class TestSceneRealtimeRoomManager : MultiplayerTestScene
public class TestSceneMultiplayerRoomManager : RoomTestScene
{
private TestRealtimeRoomContainer roomContainer;
private TestRealtimeRoomManager roomManager => roomContainer.RoomManager;
private TestMultiplayerRoomContainer roomContainer;
private TestMultiplayerRoomManager roomManager => roomContainer.RoomManager;
[Test]
public void TestPollsInitially()
@ -136,9 +136,9 @@ namespace osu.Game.Tests.Visual.RealtimeMultiplayer
AddAssert("multiplayer room joined", () => roomContainer.Client.Room != null);
}
private TestRealtimeRoomManager createRoomManager()
private TestMultiplayerRoomManager createRoomManager()
{
Child = roomContainer = new TestRealtimeRoomContainer
Child = roomContainer = new TestMultiplayerRoomContainer
{
RoomManager =
{

View File

@ -4,9 +4,9 @@
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.RoomStatuses;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Online.Rooms;
using osu.Game.Online.Rooms.RoomStatuses;
using osu.Game.Screens.OnlinePlay.Lounge.Components;
namespace osu.Game.Tests.Visual.Multiplayer
{
@ -40,7 +40,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}) { MatchingFilter = true },
new DrawableRoom(new Room
{
Name = { Value = "Open (realtime)" },
Name = { Value = "Open" },
Status = { Value = new RoomStatusOpen() },
Category = { Value = RoomCategory.Realtime }
}) { MatchingFilter = true },

View File

@ -55,8 +55,14 @@ namespace osu.Game.Tests.Visual.Navigation
var secondimport = importBeatmap(3);
presentAndConfirm(secondimport);
// Test presenting same beatmap more than once
presentAndConfirm(secondimport);
presentSecondDifficultyAndConfirm(firstImport, 1);
presentSecondDifficultyAndConfirm(secondimport, 3);
// Test presenting same beatmap more than once
presentSecondDifficultyAndConfirm(secondimport, 3);
}
[Test]

View File

@ -11,7 +11,6 @@ using osu.Game.Beatmaps;
using osu.Game.Overlays;
using osu.Game.Overlays.Mods;
using osu.Game.Overlays.Toolbar;
using osu.Game.Screens.Multi.Timeshift;
using osu.Game.Screens.Play;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Options;
@ -108,14 +107,14 @@ namespace osu.Game.Tests.Visual.Navigation
[Test]
public void TestExitMultiWithEscape()
{
PushAndConfirm(() => new TimeshiftMultiplayer());
PushAndConfirm(() => new Screens.OnlinePlay.Playlists.Playlists());
exitViaEscapeAndConfirm();
}
[Test]
public void TestExitMultiWithBackButton()
{
PushAndConfirm(() => new TimeshiftMultiplayer());
PushAndConfirm(() => new Screens.OnlinePlay.Playlists.Playlists());
exitViaBackButtonAndConfirm();
}

View File

@ -1,6 +1,7 @@
// 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 NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -13,13 +14,12 @@ namespace osu.Game.Tests.Visual.Online
public class TestSceneAccountCreationOverlay : OsuTestScene
{
private readonly Container userPanelArea;
private readonly AccountCreationOverlay accountCreation;
private IBindable<User> localUser;
public TestSceneAccountCreationOverlay()
{
AccountCreationOverlay accountCreation;
Children = new Drawable[]
{
accountCreation = new AccountCreationOverlay(),
@ -31,8 +31,6 @@ namespace osu.Game.Tests.Visual.Online
Origin = Anchor.TopRight,
},
};
AddStep("show", () => accountCreation.Show());
}
[BackgroundDependencyLoader]
@ -42,8 +40,19 @@ namespace osu.Game.Tests.Visual.Online
localUser = API.LocalUser.GetBoundCopy();
localUser.BindValueChanged(user => { userPanelArea.Child = new UserGridPanel(user.NewValue) { Width = 200 }; }, true);
}
AddStep("logout", API.Logout);
[Test]
public void TestOverlayVisibility()
{
AddStep("start hidden", () => accountCreation.Hide());
AddStep("log out", API.Logout);
AddStep("show manually", () => accountCreation.Show());
AddUntilStep("overlay is visible", () => accountCreation.State.Value == Visibility.Visible);
AddStep("log back in", () => API.Login("dummy", "password"));
AddUntilStep("overlay is hidden", () => accountCreation.State.Value == Visibility.Hidden);
}
}
}

View File

@ -235,6 +235,17 @@ namespace osu.Game.Tests.Visual.Online
AddAssert("left-most beatmap selected", () => overlay.Header.Picker.Difficulties.First().State == BeatmapPicker.DifficultySelectorState.Selected);
}
[Test]
public void TestExplicitBeatmap()
{
AddStep("show explicit map", () =>
{
var beatmapSet = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
beatmapSet.OnlineInfo.HasExplicitContent = true;
overlay.ShowBeatmapSet(beatmapSet);
});
}
[Test]
public void TestHide()
{

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