Merge branch 'master' into add-spinner-bonus-score
@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="CatchRuleset (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Ruleset">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/netcoreapp3.0/osu.Game.Rulesets.Catch.Tests.dll" />
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/netcoreapp3.1/osu.Game.Rulesets.Catch.Tests.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
@ -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.0" />
|
||||
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v3.1" />
|
||||
<browser url="http://localhost:5000" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
|
@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="ManiaRuleset (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Ruleset">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/netcoreapp3.0/osu.Game.Rulesets.Mania.Tests.dll" />
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/netcoreapp3.1/osu.Game.Rulesets.Mania.Tests.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
@ -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.0" />
|
||||
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v3.1" />
|
||||
<browser url="http://localhost:5000" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
|
@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="OsuRuleset (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Ruleset">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/netcoreapp3.0/osu.Game.Rulesets.Osu.Tests.dll" />
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/netcoreapp3.1/osu.Game.Rulesets.Osu.Tests.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
@ -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.0" />
|
||||
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v3.1" />
|
||||
<browser url="http://localhost:5000" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
|
@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="TaikoRuleset (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Ruleset">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/netcoreapp3.0/osu.Game.Rulesets.Taiko.Tests.dll" />
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/netcoreapp3.1/osu.Game.Rulesets.Taiko.Tests.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
@ -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.0" />
|
||||
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v3.1" />
|
||||
<browser url="http://localhost:5000" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
|
@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Tournament" type="DotNetProject" factoryName=".NET Project" folderName="Tournament">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp3.0/osu!.dll" />
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp3.1/osu!.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="--tournament" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
@ -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.0" />
|
||||
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v3.1" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
</method>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Tournament (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Tournament">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tournament.Tests/bin/Debug/netcoreapp2.1/osu.Game.Tournament.Tests.dll" />
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.1/osu.Game.Tournament.Tests.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tournament.Tests" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
@ -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=v2.1" />
|
||||
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v3.1" />
|
||||
<browser url="http://localhost:5000" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
|
@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="osu!" type="DotNetProject" factoryName=".NET Project" folderName="osu!">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp3.0/osu!.dll" />
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp3.1/osu!.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
@ -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.0" />
|
||||
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v3.1" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
</method>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="osu! (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="osu!">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/netcoreapp3.0/osu.Game.Tests.dll" />
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/netcoreapp3.1/osu.Game.Tests.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
@ -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.0" />
|
||||
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v3.1" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
</method>
|
||||
|
32
.vscode/launch.json
vendored
@ -6,13 +6,13 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.0/osu!.dll"
|
||||
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.1/osu!.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build osu! (Debug)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.0:${env:LD_LIBRARY_PATH}"
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
@ -23,13 +23,13 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.0/osu!.dll"
|
||||
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.1/osu!.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build osu! (Release)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.0:${env:LD_LIBRARY_PATH}"
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
@ -40,13 +40,13 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp3.0/osu.Game.Tests.dll"
|
||||
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp3.1/osu.Game.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build tests (Debug)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp3.0:${env:LD_LIBRARY_PATH}"
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
@ -56,13 +56,13 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp3.0/osu.Game.Tests.dll"
|
||||
"${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp3.1/osu.Game.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build tests (Release)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp3.0:${env:LD_LIBRARY_PATH}"
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
@ -73,14 +73,14 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.0/osu!.dll",
|
||||
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.1/osu!.dll",
|
||||
"--tournament"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build osu! (Debug)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.0:${env:LD_LIBRARY_PATH}"
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
@ -91,14 +91,14 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.0/osu!.dll",
|
||||
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.1/osu!.dll",
|
||||
"--tournament"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build osu! (Release)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.0:${env:LD_LIBRARY_PATH}"
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
@ -109,14 +109,14 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.0/osu.Game.Tournament.Tests.dll",
|
||||
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.1/osu.Game.Tournament.Tests.dll",
|
||||
"--tournament"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build tournament tests (Debug)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.0:${env:LD_LIBRARY_PATH}"
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
@ -127,14 +127,14 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.0/osu.Game.Tournament.Tests.dll",
|
||||
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.1/osu.Game.Tournament.Tests.dll",
|
||||
"--tournament"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build tournament tests (Release)",
|
||||
"linux": {
|
||||
"env": {
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.0:${env:LD_LIBRARY_PATH}"
|
||||
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
|
||||
}
|
||||
},
|
||||
"console": "internalConsole"
|
||||
|
2
.vscode/tasks.json
vendored
@ -95,7 +95,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (netcoreapp3.0)",
|
||||
"label": "Restore (netcoreapp3.1)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
|
58
CodeAnalysis/osu.ruleset
Normal file
@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RuleSet Name="osu! Rule Set" Description=" " ToolsVersion="16.0">
|
||||
<Rules AnalyzerId="Microsoft.CodeQuality.Analyzers" RuleNamespace="Microsoft.CodeQuality.Analyzers">
|
||||
<Rule Id="CA1016" Action="None" />
|
||||
<Rule Id="CA1028" Action="None" />
|
||||
<Rule Id="CA1031" Action="None" />
|
||||
<Rule Id="CA1034" Action="None" />
|
||||
<Rule Id="CA1036" Action="None" />
|
||||
<Rule Id="CA1040" Action="None" />
|
||||
<Rule Id="CA1044" Action="None" />
|
||||
<Rule Id="CA1051" Action="None" />
|
||||
<Rule Id="CA1054" Action="None" />
|
||||
<Rule Id="CA1056" Action="None" />
|
||||
<Rule Id="CA1062" Action="None" />
|
||||
<Rule Id="CA1063" Action="None" />
|
||||
<Rule Id="CA1067" Action="None" />
|
||||
<Rule Id="CA1707" Action="None" />
|
||||
<Rule Id="CA1710" Action="None" />
|
||||
<Rule Id="CA1714" Action="None" />
|
||||
<Rule Id="CA1716" Action="None" />
|
||||
<Rule Id="CA1717" Action="None" />
|
||||
<Rule Id="CA1720" Action="None" />
|
||||
<Rule Id="CA1721" Action="None" />
|
||||
<Rule Id="CA1724" Action="None" />
|
||||
<Rule Id="CA1801" Action="None" />
|
||||
<Rule Id="CA1806" Action="None" />
|
||||
<Rule Id="CA1812" Action="None" />
|
||||
<Rule Id="CA1814" Action="None" />
|
||||
<Rule Id="CA1815" Action="None" />
|
||||
<Rule Id="CA1819" Action="None" />
|
||||
<Rule Id="CA1822" Action="None" />
|
||||
<Rule Id="CA1823" Action="None" />
|
||||
<Rule Id="CA2007" Action="None" />
|
||||
<Rule Id="CA2214" Action="None" />
|
||||
<Rule Id="CA2227" Action="None" />
|
||||
</Rules>
|
||||
<Rules AnalyzerId="Microsoft.CodeQuality.CSharp.Analyzers" RuleNamespace="Microsoft.CodeQuality.CSharp.Analyzers">
|
||||
<Rule Id="CA1001" Action="None" />
|
||||
<Rule Id="CA1032" Action="None" />
|
||||
</Rules>
|
||||
<Rules AnalyzerId="Microsoft.NetCore.Analyzers" RuleNamespace="Microsoft.NetCore.Analyzers">
|
||||
<Rule Id="CA1303" Action="None" />
|
||||
<Rule Id="CA1304" Action="None" />
|
||||
<Rule Id="CA1305" Action="None" />
|
||||
<Rule Id="CA1307" Action="None" />
|
||||
<Rule Id="CA1308" Action="None" />
|
||||
<Rule Id="CA1816" Action="None" />
|
||||
<Rule Id="CA1826" Action="None" />
|
||||
<Rule Id="CA2000" Action="None" />
|
||||
<Rule Id="CA2008" Action="None" />
|
||||
<Rule Id="CA2213" Action="None" />
|
||||
<Rule Id="CA2235" Action="None" />
|
||||
</Rules>
|
||||
<Rules AnalyzerId="Microsoft.NetCore.CSharp.Analyzers" RuleNamespace="Microsoft.NetCore.CSharp.Analyzers">
|
||||
<Rule Id="CA1309" Action="Warning" />
|
||||
<Rule Id="CA2201" Action="Warning" />
|
||||
</Rules>
|
||||
</RuleSet>
|
@ -18,7 +18,11 @@
|
||||
<ItemGroup Label="Code Analysis">
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="2.9.8" PrivateAssets="All" />
|
||||
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\BannedSymbols.txt" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Code Analysis">
|
||||
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)CodeAnalysis\osu.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Documentation">
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
|
@ -21,9 +21,9 @@ Detailed changelogs are published on the [official osu! site](https://osu.ppy.sh
|
||||
|
||||
## Requirements
|
||||
|
||||
- A desktop platform with the [.NET Core SDK 3.0](https://www.microsoft.com/net/learn/get-started) or higher installed.
|
||||
- A desktop platform with the [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download) or higher installed.
|
||||
- When running on Linux, please have a system-wide FFmpeg installation available to support video decoding.
|
||||
- When running on Windows 7 or 8.1, **[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/install/dependencies?tabs=netcore30&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/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 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/).
|
||||
|
||||
@ -35,7 +35,7 @@ If you are not interested in developing the game, you can still consume our [bin
|
||||
|
||||
**Latest build:**
|
||||
|
||||
| [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [iOS(iOS 10+)](https://testflight.apple.com/join/2tLcjWlF) | [Android (5+)](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
|
||||
| [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [iOS(iOS 10+)](https://osu.ppy.sh/home/testflight) | [Android (5+)](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
|
||||
| ------------- | ------------- | ------------- | ------------- |
|
||||
|
||||
- **Linux** users are recommended to self-compile until we have official deployment in place.
|
||||
|
@ -54,6 +54,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1215.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.1215.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.1219.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
119
osu.Desktop/DiscordRichPresence.cs
Normal file
@ -0,0 +1,119 @@
|
||||
// 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 DiscordRPC;
|
||||
using DiscordRPC.Message;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Users;
|
||||
using LogLevel = osu.Framework.Logging.LogLevel;
|
||||
using User = osu.Game.Users.User;
|
||||
|
||||
namespace osu.Desktop
|
||||
{
|
||||
internal class DiscordRichPresence : Component
|
||||
{
|
||||
private const string client_id = "367827983903490050";
|
||||
|
||||
private DiscordRpcClient client;
|
||||
|
||||
[Resolved]
|
||||
private IBindable<RulesetInfo> ruleset { get; set; }
|
||||
|
||||
private Bindable<User> user;
|
||||
|
||||
private readonly IBindable<UserStatus> status = new Bindable<UserStatus>();
|
||||
private readonly IBindable<UserActivity> activity = new Bindable<UserActivity>();
|
||||
|
||||
private readonly RichPresence presence = new RichPresence
|
||||
{
|
||||
Assets = new Assets { LargeImageKey = "osu_logo_lazer", }
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IAPIProvider provider)
|
||||
{
|
||||
client = new DiscordRpcClient(client_id)
|
||||
{
|
||||
SkipIdenticalPresence = false // handles better on discord IPC loss, see updateStatus call in onReady.
|
||||
};
|
||||
|
||||
client.OnReady += onReady;
|
||||
client.OnError += (_, e) => Logger.Log($"An error occurred with Discord RPC Client: {e.Code} {e.Message}", LoggingTarget.Network);
|
||||
|
||||
(user = provider.LocalUser.GetBoundCopy()).BindValueChanged(u =>
|
||||
{
|
||||
status.UnbindBindings();
|
||||
status.BindTo(u.NewValue.Status);
|
||||
|
||||
activity.UnbindBindings();
|
||||
activity.BindTo(u.NewValue.Activity);
|
||||
}, true);
|
||||
|
||||
ruleset.BindValueChanged(_ => updateStatus());
|
||||
status.BindValueChanged(_ => updateStatus());
|
||||
activity.BindValueChanged(_ => updateStatus());
|
||||
|
||||
client.Initialize();
|
||||
}
|
||||
|
||||
private void onReady(object _, ReadyMessage __)
|
||||
{
|
||||
Logger.Log("Discord RPC Client ready.", LoggingTarget.Network, LogLevel.Debug);
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
private void updateStatus()
|
||||
{
|
||||
if (status.Value is UserStatusOffline)
|
||||
{
|
||||
client.ClearPresence();
|
||||
return;
|
||||
}
|
||||
|
||||
if (status.Value is UserStatusOnline && activity.Value != null)
|
||||
{
|
||||
presence.State = activity.Value.Status;
|
||||
presence.Details = getDetails(activity.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
presence.State = "Idle";
|
||||
presence.Details = string.Empty;
|
||||
}
|
||||
|
||||
// update user information
|
||||
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";
|
||||
presence.Assets.SmallImageText = ruleset.Value.Name;
|
||||
|
||||
client.SetPresence(presence);
|
||||
}
|
||||
|
||||
private string getDetails(UserActivity activity)
|
||||
{
|
||||
switch (activity)
|
||||
{
|
||||
case UserActivity.SoloGame solo:
|
||||
return solo.Beatmap.ToString();
|
||||
|
||||
case UserActivity.Editing edit:
|
||||
return edit.Beatmap.ToString();
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
client.Dispose();
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
}
|
||||
}
|
@ -60,6 +60,8 @@ namespace osu.Desktop
|
||||
else
|
||||
Add(new SimpleUpdateManager());
|
||||
}
|
||||
|
||||
LoadComponentAsync(new DiscordRichPresence(), Add);
|
||||
}
|
||||
|
||||
protected override void ScreenChanged(IScreen lastScreen, IScreen newScreen)
|
||||
|
@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup Label="Project">
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Description>click the circles. to the beat.</Description>
|
||||
@ -29,6 +29,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.7.0" />
|
||||
<PackageReference Include="DiscordRichPresence" Version="1.0.121" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Resources">
|
||||
<EmbeddedResource Include="lazer.ico" />
|
||||
|
@ -5,7 +5,7 @@ using UIKit;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests.iOS
|
||||
{
|
||||
public class Application
|
||||
public static class Application
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
|
@ -7,7 +7,7 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp3.0/osu.Game.Rulesets.Catch.Tests.dll"
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp3.1/osu.Game.Rulesets.Catch.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
@ -20,7 +20,7 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Release/netcoreapp3.0/osu.Game.Rulesets.Catch.Tests.dll"
|
||||
"${workspaceRoot}/bin/Release/netcoreapp3.1/osu.Game.Rulesets.Catch.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
|
@ -9,7 +9,7 @@
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
|
||||
|
@ -16,14 +16,20 @@ using osu.Game.Rulesets.Replays.Types;
|
||||
using osu.Game.Beatmaps.Legacy;
|
||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Difficulty;
|
||||
using osu.Game.Rulesets.Catch.Scoring;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using System;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch
|
||||
{
|
||||
public class CatchRuleset : Ruleset
|
||||
{
|
||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableCatchRuleset(this, beatmap, mods);
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new CatchScoreProcessor(beatmap);
|
||||
|
||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap);
|
||||
public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap);
|
||||
|
||||
@ -51,7 +57,9 @@ namespace osu.Game.Rulesets.Catch
|
||||
else if (mods.HasFlag(LegacyMods.SuddenDeath))
|
||||
yield return new CatchModSuddenDeath();
|
||||
|
||||
if (mods.HasFlag(LegacyMods.Autoplay))
|
||||
if (mods.HasFlag(LegacyMods.Cinema))
|
||||
yield return new CatchModCinema();
|
||||
else if (mods.HasFlag(LegacyMods.Autoplay))
|
||||
yield return new CatchModAutoplay();
|
||||
|
||||
if (mods.HasFlag(LegacyMods.Easy))
|
||||
@ -101,7 +109,7 @@ namespace osu.Game.Rulesets.Catch
|
||||
case ModType.Automation:
|
||||
return new Mod[]
|
||||
{
|
||||
new MultiMod(new CatchModAutoplay(), new ModCinema()),
|
||||
new MultiMod(new CatchModAutoplay(), new CatchModCinema()),
|
||||
new CatchModRelax(),
|
||||
};
|
||||
|
||||
@ -112,7 +120,7 @@ namespace osu.Game.Rulesets.Catch
|
||||
};
|
||||
|
||||
default:
|
||||
return new Mod[] { };
|
||||
return Array.Empty<Mod>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,10 +137,5 @@ namespace osu.Game.Rulesets.Catch
|
||||
public override int? LegacyID => 2;
|
||||
|
||||
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new CatchReplayFrame();
|
||||
|
||||
public CatchRuleset(RulesetInfo rulesetInfo = null)
|
||||
: base(rulesetInfo)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
21
osu.Game.Rulesets.Catch/Mods/CatchModCinema.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// 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 osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Replays;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModCinema : ModCinema<CatchHitObject>
|
||||
{
|
||||
public override Score CreateReplayScore(IBeatmap beatmap) => new Score
|
||||
{
|
||||
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad!" } },
|
||||
Replay = new CatchAutoGenerator(beatmap).Generate(),
|
||||
};
|
||||
}
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
// 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 osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModNightcore : ModNightcore
|
||||
public class CatchModNightcore : ModNightcore<CatchHitObject>
|
||||
{
|
||||
public override double ScoreMultiplier => 1.06;
|
||||
}
|
||||
|
@ -10,10 +10,8 @@ using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||
using osu.Game.Rulesets.Catch.Replays;
|
||||
using osu.Game.Rulesets.Catch.Scoring;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
|
||||
@ -32,8 +30,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
TimeRange.Value = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450);
|
||||
}
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(Beatmap);
|
||||
|
||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
||||
|
||||
protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, CreateDrawableRepresentation);
|
||||
|
@ -5,7 +5,7 @@ using UIKit;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.iOS
|
||||
{
|
||||
public class Application
|
||||
public static class Application
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
|
@ -7,7 +7,7 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp3.0/osu.Game.Rulesets.Mania.Tests.dll"
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp3.1/osu.Game.Rulesets.Mania.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
@ -20,7 +20,7 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Release/netcoreapp3.0/osu.Game.Rulesets.Mania.Tests.dll"
|
||||
"${workspaceRoot}/bin/Release/netcoreapp3.1/osu.Game.Rulesets.Mania.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
|
@ -9,7 +9,7 @@
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
|
||||
|
@ -25,6 +25,8 @@ using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Difficulty;
|
||||
using osu.Game.Rulesets.Mania.Edit;
|
||||
using osu.Game.Rulesets.Mania.Scoring;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania
|
||||
@ -32,7 +34,11 @@ namespace osu.Game.Rulesets.Mania
|
||||
public class ManiaRuleset : Ruleset
|
||||
{
|
||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableManiaRuleset(this, beatmap, mods);
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new ManiaScoreProcessor(beatmap);
|
||||
|
||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap);
|
||||
|
||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score);
|
||||
|
||||
public const string SHORT_NAME = "mania";
|
||||
@ -51,7 +57,9 @@ namespace osu.Game.Rulesets.Mania
|
||||
else if (mods.HasFlag(LegacyMods.SuddenDeath))
|
||||
yield return new ManiaModSuddenDeath();
|
||||
|
||||
if (mods.HasFlag(LegacyMods.Autoplay))
|
||||
if (mods.HasFlag(LegacyMods.Cinema))
|
||||
yield return new ManiaModCinema();
|
||||
else if (mods.HasFlag(LegacyMods.Autoplay))
|
||||
yield return new ManiaModAutoplay();
|
||||
|
||||
if (mods.HasFlag(LegacyMods.Easy))
|
||||
@ -148,7 +156,7 @@ namespace osu.Game.Rulesets.Mania
|
||||
case ModType.Automation:
|
||||
return new Mod[]
|
||||
{
|
||||
new MultiMod(new ManiaModAutoplay(), new ModCinema()),
|
||||
new MultiMod(new ManiaModAutoplay(), new ManiaModCinema()),
|
||||
};
|
||||
|
||||
case ModType.Fun:
|
||||
@ -158,7 +166,7 @@ namespace osu.Game.Rulesets.Mania
|
||||
};
|
||||
|
||||
default:
|
||||
return new Mod[] { };
|
||||
return Array.Empty<Mod>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,11 +186,6 @@ namespace osu.Game.Rulesets.Mania
|
||||
|
||||
public override RulesetSettingsSubsection CreateSettings() => new ManiaSettingsSubsection(this);
|
||||
|
||||
public ManiaRuleset(RulesetInfo rulesetInfo = null)
|
||||
: base(rulesetInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override IEnumerable<int> AvailableVariants
|
||||
{
|
||||
get
|
||||
@ -268,7 +271,7 @@ namespace osu.Game.Rulesets.Mania
|
||||
return stage1Bindings.Concat(stage2Bindings);
|
||||
}
|
||||
|
||||
return new KeyBinding[0];
|
||||
return Array.Empty<KeyBinding>();
|
||||
}
|
||||
|
||||
public override string GetVariantName(int variant)
|
||||
|
22
osu.Game.Rulesets.Mania/Mods/ManiaModCinema.cs
Normal file
@ -0,0 +1,22 @@
|
||||
// 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 osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Replays;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModCinema : ModCinema<ManiaHitObject>
|
||||
{
|
||||
public override Score CreateReplayScore(IBeatmap beatmap) => new Score
|
||||
{
|
||||
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus!" } },
|
||||
Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
|
||||
};
|
||||
}
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
// 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 osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModNightcore : ModNightcore
|
||||
public class ManiaModNightcore : ModNightcore<ManiaHitObject>
|
||||
{
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
|
@ -14,11 +14,9 @@ using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Replays;
|
||||
using osu.Game.Rulesets.Mania.Scoring;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK;
|
||||
@ -67,8 +65,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
protected override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages);
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(Beatmap);
|
||||
|
||||
public override int Variant => (int)(Beatmap.Stages.Count == 1 ? PlayfieldType.Single : PlayfieldType.Dual) + Beatmap.TotalColumns;
|
||||
|
||||
protected override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant);
|
||||
|
@ -5,7 +5,7 @@ using UIKit;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests.iOS
|
||||
{
|
||||
public class Application
|
||||
public static class Application
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
|
@ -7,7 +7,7 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp3.0/osu.Game.Rulesets.Osu.Tests.dll"
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp3.1/osu.Game.Rulesets.Osu.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
@ -20,7 +20,7 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Release/netcoreapp3.0/osu.Game.Rulesets.Osu.Tests.dll"
|
||||
"${workspaceRoot}/bin/Release/netcoreapp3.1/osu.Game.Rulesets.Osu.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-0.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-1.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-2.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-3.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-4.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-5.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-6.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-7.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-8.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/default-9.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/hit0.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/hit100.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/hit300.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/hit50.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/hitcircle.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 6.9 KiB |
2
osu.Game.Rulesets.Osu.Tests/Resources/old-skin/skin.ini
Normal file
@ -0,0 +1,2 @@
|
||||
[General]
|
||||
Version: 1.0
|
@ -19,9 +19,10 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
private Skin metricsSkin;
|
||||
private Skin defaultSkin;
|
||||
private Skin specialSkin;
|
||||
private Skin oldSkin;
|
||||
|
||||
protected SkinnableTestScene()
|
||||
: base(2, 2)
|
||||
: base(2, 3)
|
||||
{
|
||||
}
|
||||
|
||||
@ -33,6 +34,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
metricsSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/metrics_skin"), audio, true);
|
||||
defaultSkin = skinManager.GetSkin(DefaultLegacySkin.Info);
|
||||
specialSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/special_skin"), audio, true);
|
||||
oldSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/old_skin"), audio, true);
|
||||
}
|
||||
|
||||
public void SetContents(Func<Drawable> creationFunction)
|
||||
@ -41,6 +43,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
Cell(1).Child = createProvider(metricsSkin, creationFunction);
|
||||
Cell(2).Child = createProvider(defaultSkin, creationFunction);
|
||||
Cell(3).Child = createProvider(specialSkin, creationFunction);
|
||||
Cell(4).Child = createProvider(oldSkin, creationFunction);
|
||||
}
|
||||
|
||||
private Drawable createProvider(Skin skin, Func<Drawable> creationFunction)
|
||||
|
@ -100,6 +100,21 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
AddAssert("player score is 0", () => ((ScoreExposedPlayer)Player).ScoreProcessor.TotalScore.Value == 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSpinPerMinuteOnRewind()
|
||||
{
|
||||
double estimatedSpm = 0;
|
||||
|
||||
addSeekStep(2500);
|
||||
AddStep("retrieve spm", () => estimatedSpm = drawableSpinner.SpmCounter.SpinsPerMinute);
|
||||
|
||||
addSeekStep(5000);
|
||||
AddAssert("spm still valid", () => Precision.AlmostEquals(drawableSpinner.SpmCounter.SpinsPerMinute, estimatedSpm, 1.0));
|
||||
|
||||
addSeekStep(2500);
|
||||
AddAssert("spm still valid", () => Precision.AlmostEquals(drawableSpinner.SpmCounter.SpinsPerMinute, estimatedSpm, 1.0));
|
||||
}
|
||||
|
||||
private void addSeekStep(double time)
|
||||
{
|
||||
AddStep($"seek to {time}", () => track.Seek(time));
|
||||
@ -114,7 +129,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
new Spinner
|
||||
{
|
||||
Position = new Vector2(256, 192),
|
||||
EndTime = 5000,
|
||||
EndTime = 6000,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
@ -9,7 +9,7 @@
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using JetBrains.Annotations;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Screens.Edit.Compose.Components;
|
||||
|
||||
@ -10,7 +11,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
public class OsuDistanceSnapGrid : CircularDistanceSnapGrid
|
||||
{
|
||||
public OsuDistanceSnapGrid(OsuHitObject hitObject, [CanBeNull] OsuHitObject nextHitObject = null)
|
||||
: base(hitObject.StackedPosition, hitObject.StartTime, nextHitObject?.StartTime)
|
||||
: base(hitObject.StackedEndPosition, hitObject.GetEndTime(), nextHitObject?.StartTime)
|
||||
{
|
||||
Masking = true;
|
||||
}
|
||||
|
@ -92,7 +92,24 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
return null;
|
||||
|
||||
OsuHitObject sourceObject = EditorBeatmap.HitObjects[sourceIndex];
|
||||
OsuHitObject targetObject = sourceIndex + targetOffset < EditorBeatmap.HitObjects.Count ? EditorBeatmap.HitObjects[sourceIndex + targetOffset] : null;
|
||||
|
||||
int targetIndex = sourceIndex + targetOffset;
|
||||
OsuHitObject targetObject = null;
|
||||
|
||||
// Keep advancing the target object while its start time falls before the end time of the source object
|
||||
while (true)
|
||||
{
|
||||
if (targetIndex >= EditorBeatmap.HitObjects.Count)
|
||||
break;
|
||||
|
||||
if (EditorBeatmap.HitObjects[targetIndex].StartTime >= sourceObject.GetEndTime())
|
||||
{
|
||||
targetObject = EditorBeatmap.HitObjects[targetIndex];
|
||||
break;
|
||||
}
|
||||
|
||||
targetIndex++;
|
||||
}
|
||||
|
||||
return new OsuDistanceSnapGrid(sourceObject, targetObject);
|
||||
}
|
||||
|
25
osu.Game.Rulesets.Osu/Mods/OsuModCinema.cs
Normal file
@ -0,0 +1,25 @@
|
||||
// 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 osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Replays;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public class OsuModCinema : ModCinema<OsuHitObject>
|
||||
{
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).Append(typeof(OsuModSpunOut)).ToArray();
|
||||
|
||||
public override Score CreateReplayScore(IBeatmap beatmap) => new Score
|
||||
{
|
||||
ScoreInfo = new ScoreInfo { User = new User { Username = "Autoplay" } },
|
||||
Replay = new OsuAutoGenerator(beatmap).Generate()
|
||||
};
|
||||
}
|
||||
}
|
@ -2,10 +2,11 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public class OsuModNightcore : ModNightcore
|
||||
public class OsuModNightcore : ModNightcore<OsuHitObject>
|
||||
{
|
||||
public override double ScoreMultiplier => 1.12;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
@ -54,13 +55,8 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
break;
|
||||
|
||||
case DrawableSlider slider:
|
||||
slider.AccentColour.BindValueChanged(_ =>
|
||||
{
|
||||
//will trigger on skin change.
|
||||
slider.Body.AccentColour = slider.AccentColour.Value.Opacity(0);
|
||||
slider.Body.BorderColour = slider.AccentColour.Value;
|
||||
}, true);
|
||||
|
||||
slider.Body.OnSkinChanged += () => applySliderState(slider);
|
||||
applySliderState(slider);
|
||||
break;
|
||||
|
||||
case DrawableSpinner spinner:
|
||||
@ -69,5 +65,11 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void applySliderState(DrawableSlider slider)
|
||||
{
|
||||
((PlaySliderBody)slider.Body.Drawable).AccentColour = slider.AccentColour.Value.Opacity(0);
|
||||
((PlaySliderBody)slider.Body.Drawable).BorderColour = slider.AccentColour.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osuTK;
|
||||
using osu.Game.Skinning;
|
||||
@ -98,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
public void UpdateSnakingPosition(Vector2 start, Vector2 end)
|
||||
{
|
||||
bool isRepeatAtEnd = repeatPoint.RepeatIndex % 2 == 0;
|
||||
List<Vector2> curve = drawableSlider.Body.CurrentCurve;
|
||||
List<Vector2> curve = ((PlaySliderBody)drawableSlider.Body.Drawable).CurrentCurve;
|
||||
|
||||
Position = isRepeatAtEnd ? end : start;
|
||||
|
||||
|
@ -11,7 +11,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Configuration;
|
||||
using osu.Game.Rulesets.Osu.Skinning;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osuTK.Graphics;
|
||||
@ -24,8 +23,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
public DrawableSliderHead HeadCircle => headContainer.Child;
|
||||
public DrawableSliderTail TailCircle => tailContainer.Child;
|
||||
|
||||
public readonly SnakingSliderBody Body;
|
||||
public readonly SliderBall Ball;
|
||||
public readonly SkinnableDrawable Body;
|
||||
|
||||
private PlaySliderBody sliderBody => Body.Drawable as PlaySliderBody;
|
||||
|
||||
private readonly Container<DrawableSliderHead> headContainer;
|
||||
private readonly Container<DrawableSliderTail> tailContainer;
|
||||
@ -37,10 +38,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();
|
||||
private readonly IBindable<int> stackHeightBindable = new Bindable<int>();
|
||||
private readonly IBindable<float> scaleBindable = new Bindable<float>();
|
||||
private readonly IBindable<int> pathVersion = new Bindable<int>();
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private OsuRulesetConfigManager config { get; set; }
|
||||
|
||||
public DrawableSlider(Slider s)
|
||||
: base(s)
|
||||
@ -51,7 +48,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
Body = new SnakingSliderBody(s),
|
||||
Body = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderBody), _ => new DefaultSliderBody(), confineMode: ConfineMode.NoScaling),
|
||||
tickContainer = new Container<DrawableSliderTick> { RelativeSizeAxes = Axes.Both },
|
||||
repeatContainer = new Container<DrawableRepeatPoint> { RelativeSizeAxes = Axes.Both },
|
||||
Ball = new SliderBall(s, this)
|
||||
@ -70,28 +67,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
config?.BindWith(OsuRulesetSetting.SnakingInSliders, Body.SnakingIn);
|
||||
config?.BindWith(OsuRulesetSetting.SnakingOutSliders, Body.SnakingOut);
|
||||
|
||||
positionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||
stackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||
scaleBindable.BindValueChanged(scale =>
|
||||
{
|
||||
updatePathRadius();
|
||||
Ball.Scale = new Vector2(scale.NewValue);
|
||||
});
|
||||
scaleBindable.BindValueChanged(scale => Ball.Scale = new Vector2(scale.NewValue));
|
||||
|
||||
positionBindable.BindTo(HitObject.PositionBindable);
|
||||
stackHeightBindable.BindTo(HitObject.StackHeightBindable);
|
||||
scaleBindable.BindTo(HitObject.ScaleBindable);
|
||||
pathVersion.BindTo(slider.Path.Version);
|
||||
|
||||
pathVersion.BindValueChanged(_ => Body.Refresh());
|
||||
|
||||
AccentColour.BindValueChanged(colour =>
|
||||
{
|
||||
Body.AccentColour = colour.NewValue;
|
||||
|
||||
foreach (var drawableHitObject in NestedHitObjects)
|
||||
drawableHitObject.AccentColour.Value = colour.NewValue;
|
||||
}, true);
|
||||
@ -169,16 +154,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
double completionProgress = Math.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);
|
||||
|
||||
Ball.UpdateProgress(completionProgress);
|
||||
Body.UpdateProgress(completionProgress);
|
||||
sliderBody?.UpdateProgress(completionProgress);
|
||||
|
||||
foreach (DrawableHitObject hitObject in NestedHitObjects)
|
||||
{
|
||||
if (hitObject is ITrackSnaking s) s.UpdateSnakingPosition(slider.Path.PositionAt(Body.SnakedStart ?? 0), slider.Path.PositionAt(Body.SnakedEnd ?? 0));
|
||||
if (hitObject is ITrackSnaking s) s.UpdateSnakingPosition(slider.Path.PositionAt(sliderBody?.SnakedStart ?? 0), slider.Path.PositionAt(sliderBody?.SnakedEnd ?? 0));
|
||||
if (hitObject is IRequireTracking t) t.Tracking = Ball.Tracking;
|
||||
}
|
||||
|
||||
Size = Body.Size;
|
||||
OriginPosition = Body.PathOffset;
|
||||
Size = sliderBody?.Size ?? Vector2.Zero;
|
||||
OriginPosition = sliderBody?.PathOffset ?? Vector2.Zero;
|
||||
|
||||
if (DrawSize != Vector2.Zero)
|
||||
{
|
||||
@ -192,28 +177,17 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
public override void OnKilled()
|
||||
{
|
||||
base.OnKilled();
|
||||
Body.RecyclePath();
|
||||
sliderBody?.RecyclePath();
|
||||
}
|
||||
|
||||
private float sliderPathRadius;
|
||||
|
||||
protected override void ApplySkin(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
base.ApplySkin(skin, allowFallback);
|
||||
|
||||
Body.BorderSize = skin.GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.SliderBorderSize)?.Value ?? SliderBody.DEFAULT_BORDER_SIZE;
|
||||
sliderPathRadius = skin.GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.SliderPathRadius)?.Value ?? OsuHitObject.OBJECT_RADIUS;
|
||||
updatePathRadius();
|
||||
|
||||
Body.AccentColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderTrackOverride)?.Value ?? AccentColour.Value;
|
||||
Body.BorderColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderBorder)?.Value ?? Color4.White;
|
||||
|
||||
bool allowBallTint = skin.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.AllowSliderBallTint)?.Value ?? false;
|
||||
Ball.Colour = allowBallTint ? AccentColour.Value : Color4.White;
|
||||
}
|
||||
|
||||
private void updatePathRadius() => Body.PathRadius = slider.Scale * sliderPathRadius;
|
||||
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (userTriggered || Time.Current < slider.EndTime)
|
||||
@ -264,6 +238,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
public Drawable ProxiedLayer => HeadCircle.ProxiedLayer;
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Body.ReceivePositionalInputAt(screenSpacePos);
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => sliderBody?.ReceivePositionalInputAt(screenSpacePos) ?? base.ReceivePositionalInputAt(screenSpacePos);
|
||||
|
||||
private class DefaultSliderBody : PlaySliderBody
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
public readonly SpinnerDisc Disc;
|
||||
public readonly SpinnerTicks Ticks;
|
||||
private readonly SpinnerSpmCounter spmCounter;
|
||||
public readonly SpinnerSpmCounter SpmCounter;
|
||||
|
||||
private readonly Container mainContainer;
|
||||
|
||||
@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
},
|
||||
}
|
||||
},
|
||||
spmCounter = new SpinnerSpmCounter
|
||||
SpmCounter = new SpinnerSpmCounter
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@ -220,8 +220,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
protected override void Update()
|
||||
{
|
||||
Disc.Tracking = OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false;
|
||||
if (!spmCounter.IsPresent && Disc.Tracking)
|
||||
spmCounter.FadeIn(HitObject.TimeFadeIn);
|
||||
if (!SpmCounter.IsPresent && Disc.Tracking)
|
||||
SpmCounter.FadeIn(HitObject.TimeFadeIn);
|
||||
|
||||
base.Update();
|
||||
}
|
||||
@ -234,7 +234,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
circle.Rotation = Disc.Rotation;
|
||||
Ticks.Rotation = Disc.Rotation;
|
||||
spmCounter.SetRotation(Disc.RotationAbsolute);
|
||||
SpmCounter.SetRotation(Disc.RotationAbsolute);
|
||||
|
||||
var newSpins = (int)(Disc.RotationAbsolute / 360) - currentSpins;
|
||||
|
||||
|
@ -0,0 +1,70 @@
|
||||
// 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 osu.Framework.Graphics.Lines;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
public abstract class DrawableSliderPath : SmoothPath
|
||||
{
|
||||
protected const float BORDER_PORTION = 0.128f;
|
||||
protected const float GRADIENT_PORTION = 1 - BORDER_PORTION;
|
||||
|
||||
private const float border_max_size = 8f;
|
||||
private const float border_min_size = 0f;
|
||||
|
||||
private Color4 borderColour = Color4.White;
|
||||
|
||||
public Color4 BorderColour
|
||||
{
|
||||
get => borderColour;
|
||||
set
|
||||
{
|
||||
if (borderColour == value)
|
||||
return;
|
||||
|
||||
borderColour = value;
|
||||
|
||||
InvalidateTexture();
|
||||
}
|
||||
}
|
||||
|
||||
private Color4 accentColour = Color4.White;
|
||||
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get => accentColour;
|
||||
set
|
||||
{
|
||||
if (accentColour == value)
|
||||
return;
|
||||
|
||||
accentColour = value;
|
||||
|
||||
InvalidateTexture();
|
||||
}
|
||||
}
|
||||
|
||||
private float borderSize = 1;
|
||||
|
||||
public float BorderSize
|
||||
{
|
||||
get => borderSize;
|
||||
set
|
||||
{
|
||||
if (borderSize == value)
|
||||
return;
|
||||
|
||||
if (value < border_min_size || value > border_max_size)
|
||||
return;
|
||||
|
||||
borderSize = value;
|
||||
|
||||
InvalidateTexture();
|
||||
}
|
||||
}
|
||||
|
||||
protected float CalculatedBorderPortion => BorderSize * BORDER_PORTION;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Configuration;
|
||||
using osu.Game.Rulesets.Osu.Skinning;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
public abstract class PlaySliderBody : SnakingSliderBody
|
||||
{
|
||||
private IBindable<float> scaleBindable;
|
||||
private IBindable<int> pathVersion;
|
||||
private IBindable<Color4> accentColour;
|
||||
|
||||
[Resolved]
|
||||
private DrawableHitObject drawableObject { get; set; }
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private OsuRulesetConfigManager config { get; set; }
|
||||
|
||||
private Slider slider;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin)
|
||||
{
|
||||
slider = (Slider)drawableObject.HitObject;
|
||||
|
||||
scaleBindable = slider.ScaleBindable.GetBoundCopy();
|
||||
scaleBindable.BindValueChanged(scale => PathRadius = OsuHitObject.OBJECT_RADIUS * scale.NewValue, true);
|
||||
|
||||
pathVersion = slider.Path.Version.GetBoundCopy();
|
||||
pathVersion.BindValueChanged(_ => Refresh());
|
||||
|
||||
accentColour = drawableObject.AccentColour.GetBoundCopy();
|
||||
accentColour.BindValueChanged(accent => updateAccentColour(skin, accent.NewValue), true);
|
||||
|
||||
config?.BindWith(OsuRulesetSetting.SnakingInSliders, SnakingIn);
|
||||
config?.BindWith(OsuRulesetSetting.SnakingOutSliders, SnakingOut);
|
||||
|
||||
BorderSize = skin.GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.SliderBorderSize)?.Value ?? 1;
|
||||
BorderColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderBorder)?.Value ?? Color4.White;
|
||||
}
|
||||
|
||||
private void updateAccentColour(ISkinSource skin, Color4 defaultAccentColour)
|
||||
=> AccentColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderTrackOverride)?.Value ?? defaultAccentColour;
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Lines;
|
||||
using osuTK;
|
||||
@ -12,9 +13,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
public abstract class SliderBody : CompositeDrawable
|
||||
{
|
||||
public const float DEFAULT_BORDER_SIZE = 1;
|
||||
|
||||
private SliderPath path;
|
||||
private DrawableSliderPath path;
|
||||
|
||||
protected Path Path => path;
|
||||
|
||||
@ -80,19 +79,19 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialises a new <see cref="SliderPath"/>, releasing all resources retained by the old one.
|
||||
/// Initialises a new <see cref="DrawableSliderPath"/>, releasing all resources retained by the old one.
|
||||
/// </summary>
|
||||
public virtual void RecyclePath()
|
||||
{
|
||||
InternalChild = path = new SliderPath
|
||||
InternalChild = path = CreateSliderPath().With(p =>
|
||||
{
|
||||
Position = path?.Position ?? Vector2.Zero,
|
||||
PathRadius = path?.PathRadius ?? 10,
|
||||
AccentColour = path?.AccentColour ?? Color4.White,
|
||||
BorderColour = path?.BorderColour ?? Color4.White,
|
||||
BorderSize = path?.BorderSize ?? DEFAULT_BORDER_SIZE,
|
||||
Vertices = path?.Vertices ?? Array.Empty<Vector2>()
|
||||
};
|
||||
p.Position = path?.Position ?? Vector2.Zero;
|
||||
p.PathRadius = path?.PathRadius ?? 10;
|
||||
p.AccentColour = path?.AccentColour ?? Color4.White;
|
||||
p.BorderColour = path?.BorderColour ?? Color4.White;
|
||||
p.BorderSize = path?.BorderSize ?? 1;
|
||||
p.Vertices = path?.Vertices ?? Array.Empty<Vector2>();
|
||||
});
|
||||
}
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => path.ReceivePositionalInputAt(screenSpacePos);
|
||||
@ -103,77 +102,20 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
/// <param name="vertices">The vertices</param>
|
||||
protected void SetVertices(IReadOnlyList<Vector2> vertices) => path.Vertices = vertices;
|
||||
|
||||
private class SliderPath : SmoothPath
|
||||
protected virtual DrawableSliderPath CreateSliderPath() => new DefaultDrawableSliderPath();
|
||||
|
||||
private class DefaultDrawableSliderPath : DrawableSliderPath
|
||||
{
|
||||
private const float border_max_size = 8f;
|
||||
private const float border_min_size = 0f;
|
||||
|
||||
private const float border_portion = 0.128f;
|
||||
private const float gradient_portion = 1 - border_portion;
|
||||
|
||||
private const float opacity_at_centre = 0.3f;
|
||||
private const float opacity_at_edge = 0.8f;
|
||||
|
||||
private Color4 borderColour = Color4.White;
|
||||
|
||||
public Color4 BorderColour
|
||||
{
|
||||
get => borderColour;
|
||||
set
|
||||
{
|
||||
if (borderColour == value)
|
||||
return;
|
||||
|
||||
borderColour = value;
|
||||
|
||||
InvalidateTexture();
|
||||
}
|
||||
}
|
||||
|
||||
private Color4 accentColour = Color4.White;
|
||||
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get => accentColour;
|
||||
set
|
||||
{
|
||||
if (accentColour == value)
|
||||
return;
|
||||
|
||||
accentColour = value;
|
||||
|
||||
InvalidateTexture();
|
||||
}
|
||||
}
|
||||
|
||||
private float borderSize = DEFAULT_BORDER_SIZE;
|
||||
|
||||
public float BorderSize
|
||||
{
|
||||
get => borderSize;
|
||||
set
|
||||
{
|
||||
if (borderSize == value)
|
||||
return;
|
||||
|
||||
if (value < border_min_size || value > border_max_size)
|
||||
return;
|
||||
|
||||
borderSize = value;
|
||||
|
||||
InvalidateTexture();
|
||||
}
|
||||
}
|
||||
|
||||
private float calculatedBorderPortion => BorderSize * border_portion;
|
||||
|
||||
protected override Color4 ColourAt(float position)
|
||||
{
|
||||
if (calculatedBorderPortion != 0f && position <= calculatedBorderPortion)
|
||||
if (CalculatedBorderPortion != 0f && position <= CalculatedBorderPortion)
|
||||
return BorderColour;
|
||||
|
||||
position -= calculatedBorderPortion;
|
||||
return new Color4(AccentColour.R, AccentColour.G, AccentColour.B, (opacity_at_edge - (opacity_at_edge - opacity_at_centre) * position / gradient_portion) * AccentColour.A);
|
||||
position -= CalculatedBorderPortion;
|
||||
return new Color4(AccentColour.R, AccentColour.G, AccentColour.B, (opacity_at_edge - (opacity_at_edge - opacity_at_centre) * position / GRADIENT_PORTION) * AccentColour.A);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osuTK;
|
||||
|
||||
@ -50,16 +51,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
/// </summary>
|
||||
private Vector2 snakedPathOffset;
|
||||
|
||||
private readonly Slider slider;
|
||||
|
||||
public SnakingSliderBody(Slider slider)
|
||||
{
|
||||
this.slider = slider;
|
||||
}
|
||||
private Slider slider;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
private void load(DrawableHitObject drawableObject)
|
||||
{
|
||||
slider = (Slider)drawableObject.HitObject;
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
@ -62,6 +63,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
|
||||
public void SetRotation(float currentRotation)
|
||||
{
|
||||
// Never calculate SPM by same time of record to avoid 0 / 0 = NaN or X / 0 = Infinity result.
|
||||
if (Precision.AlmostEquals(0, Time.Elapsed))
|
||||
return;
|
||||
|
||||
// If we've gone back in time, it's fine to work with a fresh set of records for now
|
||||
if (records.Count > 0 && Time.Current < records.Last().Time)
|
||||
records.Clear();
|
||||
@ -71,6 +76,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
var record = records.Peek();
|
||||
while (records.Count > 0 && Time.Current - records.Peek().Time > spm_count_duration)
|
||||
record = records.Dequeue();
|
||||
|
||||
SpinsPerMinute = (currentRotation - record.Rotation) / (Time.Current - record.Time) * 1000 * 60 / 360;
|
||||
}
|
||||
|
||||
|
@ -23,16 +23,23 @@ using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Configuration;
|
||||
using osu.Game.Rulesets.Osu.Difficulty;
|
||||
using osu.Game.Rulesets.Osu.Scoring;
|
||||
using osu.Game.Rulesets.Osu.Skinning;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using System;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu
|
||||
{
|
||||
public class OsuRuleset : Ruleset
|
||||
{
|
||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableOsuRuleset(this, beatmap, mods);
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new OsuScoreProcessor(beatmap);
|
||||
|
||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new OsuBeatmapConverter(beatmap);
|
||||
|
||||
public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new OsuBeatmapProcessor(beatmap);
|
||||
|
||||
public const string SHORT_NAME = "osu";
|
||||
@ -60,7 +67,9 @@ namespace osu.Game.Rulesets.Osu
|
||||
if (mods.HasFlag(LegacyMods.Autopilot))
|
||||
yield return new OsuModAutopilot();
|
||||
|
||||
if (mods.HasFlag(LegacyMods.Autoplay))
|
||||
if (mods.HasFlag(LegacyMods.Cinema))
|
||||
yield return new OsuModCinema();
|
||||
else if (mods.HasFlag(LegacyMods.Autoplay))
|
||||
yield return new OsuModAutoplay();
|
||||
|
||||
if (mods.HasFlag(LegacyMods.Easy))
|
||||
@ -126,7 +135,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
case ModType.Automation:
|
||||
return new Mod[]
|
||||
{
|
||||
new MultiMod(new OsuModAutoplay(), new ModCinema()),
|
||||
new MultiMod(new OsuModAutoplay(), new OsuModCinema()),
|
||||
new OsuModRelax(),
|
||||
new OsuModAutopilot(),
|
||||
};
|
||||
@ -149,7 +158,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
};
|
||||
|
||||
default:
|
||||
return new Mod[] { };
|
||||
return Array.Empty<Mod>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,10 +183,5 @@ namespace osu.Game.Rulesets.Osu
|
||||
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new OsuReplayFrame();
|
||||
|
||||
public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new OsuRulesetConfigManager(settings, RulesetInfo);
|
||||
|
||||
public OsuRuleset(RulesetInfo rulesetInfo = null)
|
||||
: base(rulesetInfo)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ namespace osu.Game.Rulesets.Osu
|
||||
ReverseArrow,
|
||||
HitCircleText,
|
||||
SliderFollowCircle,
|
||||
SliderBall
|
||||
SliderBall,
|
||||
SliderBody,
|
||||
}
|
||||
}
|
||||
|
56
osu.Game.Rulesets.Osu/Skinning/LegacySliderBody.cs
Normal file
@ -0,0 +1,56 @@
|
||||
// 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 osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Skinning
|
||||
{
|
||||
public class LegacySliderBody : PlaySliderBody
|
||||
{
|
||||
protected override DrawableSliderPath CreateSliderPath() => new LegacyDrawableSliderPath();
|
||||
|
||||
private class LegacyDrawableSliderPath : DrawableSliderPath
|
||||
{
|
||||
private const float shadow_portion = 1 - (OsuLegacySkinTransformer.LEGACY_CIRCLE_RADIUS / OsuHitObject.OBJECT_RADIUS);
|
||||
|
||||
public new Color4 AccentColour => new Color4(base.AccentColour.R, base.AccentColour.G, base.AccentColour.B, base.AccentColour.A * 0.70f);
|
||||
|
||||
protected override Color4 ColourAt(float position)
|
||||
{
|
||||
float realBorderPortion = shadow_portion + CalculatedBorderPortion;
|
||||
float realGradientPortion = 1 - realBorderPortion;
|
||||
|
||||
if (position <= shadow_portion)
|
||||
return new Color4(0f, 0f, 0f, 0.25f * position / shadow_portion);
|
||||
|
||||
if (position <= realBorderPortion)
|
||||
return BorderColour;
|
||||
|
||||
position -= realBorderPortion;
|
||||
|
||||
Color4 outerColour = AccentColour.Darken(0.1f);
|
||||
Color4 innerColour = lighten(AccentColour, 0.5f);
|
||||
|
||||
return Interpolation.ValueAt(position / realGradientPortion, outerColour, innerColour, 0, 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lightens a colour in a way more friendly to dark or strong colours.
|
||||
/// </summary>
|
||||
private static Color4 lighten(Color4 color, float amount)
|
||||
{
|
||||
amount *= 0.5f;
|
||||
return new Color4(
|
||||
Math.Min(1, color.R * (1 + 0.5f * amount) + 1 * amount),
|
||||
Math.Min(1, color.G * (1 + 0.5f * amount) + 1 * amount),
|
||||
Math.Min(1, color.B * (1 + 0.5f * amount) + 1 * amount),
|
||||
color.A);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
/// Their hittable area is 128px, but the actual circle portion is 118px.
|
||||
/// We must account for some gameplay elements such as slider bodies, where this padding is not present.
|
||||
/// </summary>
|
||||
private const float legacy_circle_radius = 64 - 5;
|
||||
public const float LEGACY_CIRCLE_RADIUS = 64 - 5;
|
||||
|
||||
public OsuLegacySkinTransformer(ISkinSource source)
|
||||
{
|
||||
@ -73,6 +73,12 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
|
||||
return null;
|
||||
|
||||
case OsuSkinComponents.SliderBody:
|
||||
if (hasHitCircle.Value)
|
||||
return new LegacySliderBody();
|
||||
|
||||
return null;
|
||||
|
||||
case OsuSkinComponents.HitCircle:
|
||||
if (hasHitCircle.Value)
|
||||
return new LegacyMainCirclePiece();
|
||||
@ -124,7 +130,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
{
|
||||
case OsuSkinConfiguration.SliderPathRadius:
|
||||
if (hasHitCircle.Value)
|
||||
return SkinUtils.As<TValue>(new BindableFloat(legacy_circle_radius));
|
||||
return SkinUtils.As<TValue>(new BindableFloat(LEGACY_CIRCLE_RADIUS));
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -14,8 +14,6 @@ using osu.Game.Rulesets.Osu.Configuration;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Replays;
|
||||
using osu.Game.Rulesets.Osu.Scoring;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Screens.Play;
|
||||
using osuTK;
|
||||
@ -33,8 +31,6 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; // always show the gameplay cursor
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor() => new OsuScoreProcessor(Beatmap);
|
||||
|
||||
protected override Playfield CreatePlayfield() => new OsuPlayfield();
|
||||
|
||||
protected override PassThroughInputManager CreateInputManager() => new OsuInputManager(Ruleset.RulesetInfo);
|
||||
|
@ -5,7 +5,7 @@ using UIKit;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Tests.iOS
|
||||
{
|
||||
public class Application
|
||||
public static class Application
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
|
@ -7,7 +7,7 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp3.0/osu.Game.Rulesets.Taiko.Tests.dll"
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp3.1/osu.Game.Rulesets.Taiko.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
@ -20,7 +20,7 @@
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Release/netcoreapp3.0/osu.Game.Rulesets.Taiko.Tests.dll"
|
||||
"${workspaceRoot}/bin/Release/netcoreapp3.1/osu.Game.Rulesets.Taiko.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
|
@ -9,7 +9,7 @@
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
|
||||
|
21
osu.Game.Rulesets.Taiko/Mods/TaikoModCinema.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// 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 osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Rulesets.Taiko.Replays;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Mods
|
||||
{
|
||||
public class TaikoModCinema : ModCinema<TaikoHitObject>
|
||||
{
|
||||
public override Score CreateReplayScore(IBeatmap beatmap) => new Score
|
||||
{
|
||||
ScoreInfo = new ScoreInfo { User = new User { Username = "mekkadosu!" } },
|
||||
Replay = new TaikoAutoGenerator(beatmap).Generate(),
|
||||
};
|
||||
}
|
||||
}
|
@ -2,10 +2,11 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Mods
|
||||
{
|
||||
public class TaikoModNightcore : ModNightcore
|
||||
public class TaikoModNightcore : ModNightcore<TaikoHitObject>
|
||||
{
|
||||
public override double ScoreMultiplier => 1.12;
|
||||
}
|
||||
|
@ -105,19 +105,19 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class DrawableTaikoHitObject<TaikoHitType> : DrawableTaikoHitObject
|
||||
where TaikoHitType : TaikoHitObject
|
||||
public abstract class DrawableTaikoHitObject<TTaikoHit> : DrawableTaikoHitObject
|
||||
where TTaikoHit : TaikoHitObject
|
||||
{
|
||||
public override Vector2 OriginPosition => new Vector2(DrawHeight / 2);
|
||||
|
||||
public new TaikoHitType HitObject;
|
||||
public new TTaikoHit HitObject;
|
||||
|
||||
protected readonly Vector2 BaseSize;
|
||||
protected readonly TaikoPiece MainPiece;
|
||||
|
||||
private readonly Container<DrawableStrongNestedHit> strongHitContainer;
|
||||
|
||||
protected DrawableTaikoHitObject(TaikoHitType hitObject)
|
||||
protected DrawableTaikoHitObject(TTaikoHit hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
HitObject = hitObject;
|
||||
|
@ -15,15 +15,21 @@ using osu.Game.Rulesets.Replays.Types;
|
||||
using osu.Game.Rulesets.Taiko.Replays;
|
||||
using osu.Game.Beatmaps.Legacy;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty;
|
||||
using osu.Game.Rulesets.Taiko.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using System;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko
|
||||
{
|
||||
public class TaikoRuleset : Ruleset
|
||||
{
|
||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new DrawableTaikoRuleset(this, beatmap, mods);
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new TaikoScoreProcessor(beatmap);
|
||||
|
||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap);
|
||||
|
||||
public const string SHORT_NAME = "taiko";
|
||||
@ -50,7 +56,9 @@ namespace osu.Game.Rulesets.Taiko
|
||||
else if (mods.HasFlag(LegacyMods.SuddenDeath))
|
||||
yield return new TaikoModSuddenDeath();
|
||||
|
||||
if (mods.HasFlag(LegacyMods.Autoplay))
|
||||
if (mods.HasFlag(LegacyMods.Cinema))
|
||||
yield return new TaikoModCinema();
|
||||
else if (mods.HasFlag(LegacyMods.Autoplay))
|
||||
yield return new TaikoModAutoplay();
|
||||
|
||||
if (mods.HasFlag(LegacyMods.Easy))
|
||||
@ -100,7 +108,7 @@ namespace osu.Game.Rulesets.Taiko
|
||||
case ModType.Automation:
|
||||
return new Mod[]
|
||||
{
|
||||
new MultiMod(new TaikoModAutoplay(), new ModCinema()),
|
||||
new MultiMod(new TaikoModAutoplay(), new TaikoModCinema()),
|
||||
new TaikoModRelax(),
|
||||
};
|
||||
|
||||
@ -111,7 +119,7 @@ namespace osu.Game.Rulesets.Taiko
|
||||
};
|
||||
|
||||
default:
|
||||
return new Mod[] { };
|
||||
return Array.Empty<Mod>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,10 +136,5 @@ namespace osu.Game.Rulesets.Taiko
|
||||
public override int? LegacyID => 1;
|
||||
|
||||
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new TaikoReplayFrame();
|
||||
|
||||
public TaikoRuleset(RulesetInfo rulesetInfo = null)
|
||||
: base(rulesetInfo)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,10 +5,8 @@ using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.Taiko.Replays;
|
||||
using osu.Framework.Input;
|
||||
@ -40,8 +38,6 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
new BarLineGenerator<BarLine>(Beatmap).BarLines.ForEach(bar => Playfield.Add(bar.Major ? new DrawableBarLineMajor(bar) : new DrawableBarLine(bar)));
|
||||
}
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(Beatmap);
|
||||
|
||||
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new TaikoPlayfieldAdjustmentContainer();
|
||||
|
||||
protected override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo);
|
||||
|
@ -5,7 +5,7 @@ using UIKit;
|
||||
|
||||
namespace osu.Game.Tests.iOS
|
||||
{
|
||||
public class Application
|
||||
public static class Application
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
|
54
osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs
Normal file
@ -0,0 +1,54 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.IO;
|
||||
using osu.Game.IO.Serialization;
|
||||
using osu.Game.Tests.Resources;
|
||||
|
||||
namespace osu.Game.Tests.Beatmaps.Formats
|
||||
{
|
||||
[TestFixture]
|
||||
public class LegacyBeatmapEncoderTest
|
||||
{
|
||||
private const string normal = "Soleily - Renatus (Gamu) [Insane].osu";
|
||||
|
||||
private static IEnumerable<string> allBeatmaps => TestResources.GetStore().GetAvailableResources().Where(res => res.EndsWith(".osu"));
|
||||
|
||||
[TestCaseSource(nameof(allBeatmaps))]
|
||||
public void TestDecodeEncodedBeatmap(string name)
|
||||
{
|
||||
var decoded = decode(normal, out var encoded);
|
||||
|
||||
Assert.That(decoded.HitObjects.Count, Is.EqualTo(encoded.HitObjects.Count));
|
||||
Assert.That(encoded.Serialize(), Is.EqualTo(decoded.Serialize()));
|
||||
}
|
||||
|
||||
private Beatmap decode(string filename, out Beatmap encoded)
|
||||
{
|
||||
using (var stream = TestResources.OpenResource(filename))
|
||||
using (var sr = new LineBufferedReader(stream))
|
||||
{
|
||||
var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr);
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
using (var sw = new StreamWriter(ms))
|
||||
using (var sr2 = new LineBufferedReader(ms))
|
||||
{
|
||||
new LegacyBeatmapEncoder(legacyDecoded).Encode(sw);
|
||||
sw.Flush();
|
||||
|
||||
ms.Position = 0;
|
||||
|
||||
encoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr2);
|
||||
return legacyDecoded;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -71,7 +71,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.AreEqual(new Vector2(320, 240), sprite.InitialPosition);
|
||||
Assert.IsTrue(sprite.IsDrawable);
|
||||
Assert.AreEqual(Anchor.Centre, sprite.Origin);
|
||||
Assert.AreEqual("SB/black.jpg", sprite.Path);
|
||||
Assert.AreEqual("SB/lyric/ja-21.png", sprite.Path);
|
||||
|
||||
var animation = background.Elements.OfType<StoryboardAnimation>().First();
|
||||
Assert.NotNull(animation);
|
||||
|
75
osu.Game.Tests/Gameplay/TestSceneHitObjectContainer.cs
Normal file
@ -0,0 +1,75 @@
|
||||
// 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 JetBrains.Annotations;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Tests.Gameplay
|
||||
{
|
||||
[HeadlessTest]
|
||||
public class TestSceneHitObjectContainer : OsuTestScene
|
||||
{
|
||||
private HitObjectContainer container;
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
Child = container = new HitObjectContainer();
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestLateHitObjectIsAddedEarlierInList()
|
||||
{
|
||||
DrawableHitObject hitObject = null;
|
||||
|
||||
AddStep("setup", () => container.Add(new TestDrawableHitObject(new HitObject { StartTime = 500 })));
|
||||
|
||||
AddStep("add late hitobject", () => container.Add(hitObject = new TestDrawableHitObject(new HitObject { StartTime = 1000 })));
|
||||
|
||||
AddAssert("hitobject index is 0", () => container.IndexOf(hitObject) == 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEarlyHitObjectIsAddedLaterInList()
|
||||
{
|
||||
DrawableHitObject hitObject = null;
|
||||
|
||||
AddStep("setup", () => container.Add(new TestDrawableHitObject(new HitObject { StartTime = 500 })));
|
||||
|
||||
AddStep("add early hitobject", () => container.Add(hitObject = new TestDrawableHitObject(new HitObject())));
|
||||
|
||||
AddAssert("hitobject index is 0", () => container.IndexOf(hitObject) == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHitObjectsResortedAfterStartTimeChange()
|
||||
{
|
||||
DrawableHitObject firstObject = null;
|
||||
DrawableHitObject secondObject = null;
|
||||
|
||||
AddStep("setup", () =>
|
||||
{
|
||||
container.Add(firstObject = new TestDrawableHitObject(new HitObject()));
|
||||
container.Add(secondObject = new TestDrawableHitObject(new HitObject { StartTime = 1000 }));
|
||||
});
|
||||
|
||||
AddStep("move first object after second", () => firstObject.HitObject.StartTime = 2000);
|
||||
|
||||
AddAssert("first object index is 1", () => container.IndexOf(firstObject) == 0);
|
||||
AddAssert("second object index is 0", () => container.IndexOf(secondObject) == 1);
|
||||
}
|
||||
|
||||
private class TestDrawableHitObject : DrawableHitObject
|
||||
{
|
||||
public TestDrawableHitObject([NotNull] HitObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
cpi.Add(1000, new DifficultyControlPoint()); // is redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.DifficultyPoints.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0));
|
||||
|
||||
cpi.Add(1000, new DifficultyControlPoint { SpeedMultiplier = 2 }); // is not redundant
|
||||
@ -60,18 +60,18 @@ namespace osu.Game.Tests.NonVisual
|
||||
{
|
||||
var cpi = new ControlPointInfo();
|
||||
|
||||
cpi.Add(0, new SampleControlPoint()); // is redundant
|
||||
cpi.Add(0, new SampleControlPoint()); // is *not* redundant, special exception for first sample point
|
||||
cpi.Add(1000, new SampleControlPoint()); // is redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0));
|
||||
|
||||
cpi.Add(1000, new SampleControlPoint { SampleVolume = 50 }); // is not redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.SamplePoints.Count, Is.EqualTo(1));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(1));
|
||||
|
||||
cpi.Add(1000, new SampleControlPoint { SampleVolume = 50 }); // is not redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(2));
|
||||
Assert.That(cpi.SamplePoints.Count, Is.EqualTo(2));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -83,7 +83,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
cpi.Add(1000, new EffectControlPoint()); // is redundant
|
||||
|
||||
Assert.That(cpi.Groups.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.EffectPoints.Count, Is.EqualTo(0));
|
||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0));
|
||||
|
||||
cpi.Add(1000, new EffectControlPoint { KiaiMode = true }); // is not redundant
|
||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
{
|
||||
Assert.AreEqual(0, stack.Count);
|
||||
|
||||
Assert.Throws<IndexOutOfRangeException>(() =>
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||
{
|
||||
int unused = stack[0];
|
||||
});
|
||||
@ -55,7 +55,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
// e.g. indices 3, 4, 5, 6 (out of range)
|
||||
for (int i = stack.Count; i < stack.Count + capacity; i++)
|
||||
{
|
||||
Assert.Throws<IndexOutOfRangeException>(() =>
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||
{
|
||||
int unused = stack[i];
|
||||
});
|
||||
@ -80,7 +80,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
// e.g. indices 3, 4, 5, 6 (out of range)
|
||||
for (int i = stack.Count; i < stack.Count + capacity; i++)
|
||||
{
|
||||
Assert.Throws<IndexOutOfRangeException>(() =>
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
||||
{
|
||||
int unused = stack[i];
|
||||
});
|
||||
|
@ -9,7 +9,9 @@ namespace osu.Game.Tests.Resources
|
||||
{
|
||||
public static class TestResources
|
||||
{
|
||||
public static Stream OpenResource(string name) => new DllResourceStore("osu.Game.Tests.dll").GetStream($"Resources/{name}");
|
||||
public static DllResourceStore GetStore() => new DllResourceStore("osu.Game.Tests.dll");
|
||||
|
||||
public static Stream OpenResource(string name) => GetStore().GetStream($"Resources/{name}");
|
||||
|
||||
public static Stream GetTestBeatmapStream(bool virtualTrack = false) => new DllResourceStore("osu.Game.Resources.dll").GetStream($"Beatmaps/241526 Soleily - Renatus{(virtualTrack ? "_virtual" : "")}.osz");
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -10,6 +11,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.IO.Archives;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
@ -154,7 +156,30 @@ namespace osu.Game.Tests.Scores.IO
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ScoreInfo> loadIntoOsu(OsuGameBase osu, ScoreInfo score)
|
||||
[Test]
|
||||
public async Task TestOnlineScoreIsAvailableLocally()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestOnlineScoreIsAvailableLocally"))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = await loadOsu(host);
|
||||
|
||||
await loadIntoOsu(osu, new ScoreInfo { OnlineScoreID = 2 }, new TestArchiveReader());
|
||||
|
||||
var scoreManager = osu.Dependencies.Get<ScoreManager>();
|
||||
|
||||
// Note: A new score reference is used here since the import process mutates the original object to set an ID
|
||||
Assert.That(scoreManager.IsAvailableLocally(new ScoreInfo { OnlineScoreID = 2 }));
|
||||
}
|
||||
finally
|
||||
{
|
||||
host.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ScoreInfo> loadIntoOsu(OsuGameBase osu, ScoreInfo score, ArchiveReader archive = null)
|
||||
{
|
||||
var beatmapManager = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
@ -165,7 +190,7 @@ namespace osu.Game.Tests.Scores.IO
|
||||
score.Ruleset = new OsuRuleset().RulesetInfo;
|
||||
|
||||
var scoreManager = osu.Dependencies.Get<ScoreManager>();
|
||||
await scoreManager.Import(score);
|
||||
await scoreManager.Import(score, archive);
|
||||
|
||||
return scoreManager.GetAllUsableScores().FirstOrDefault();
|
||||
}
|
||||
@ -196,5 +221,23 @@ namespace osu.Game.Tests.Scores.IO
|
||||
|
||||
Assert.IsTrue(task.Wait(timeout), failureMessage);
|
||||
}
|
||||
|
||||
private class TestArchiveReader : ArchiveReader
|
||||
{
|
||||
public TestArchiveReader()
|
||||
: base("test_archive")
|
||||
{
|
||||
}
|
||||
|
||||
public override Stream GetStream(string name) => new MemoryStream();
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Filenames => new[] { "test_file.osr" };
|
||||
|
||||
public override Stream GetUnderlyingStream() => new MemoryStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +88,20 @@ namespace osu.Game.Tests.Visual.Background
|
||||
AddUntilStep("not lightened", () => userDimContainer.DimEqual(test_user_dim));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestIgnoreUserSettings()
|
||||
{
|
||||
AddStep("set dim level 0.6", () => userDimContainer.UserDimLevel.Value = test_user_dim);
|
||||
AddUntilStep("dim reached", () => userDimContainer.DimEqual(test_user_dim));
|
||||
|
||||
AddStep("ignore settings", () => userDimContainer.IgnoreUserSettings.Value = true);
|
||||
AddUntilStep("no dim", () => userDimContainer.DimEqual(0));
|
||||
AddStep("set break", () => isBreakTime.Value = true);
|
||||
AddAssert("no dim", () => userDimContainer.DimEqual(0));
|
||||
AddStep("clear break", () => isBreakTime.Value = false);
|
||||
AddAssert("no dim", () => userDimContainer.DimEqual(0));
|
||||
}
|
||||
|
||||
private class TestUserDimContainer : UserDimContainer
|
||||
{
|
||||
public bool DimEqual(float expectedDimLevel) => Content.Colour == OsuColour.Gray(1f - expectedDimLevel);
|
||||
|
@ -68,8 +68,11 @@ namespace osu.Game.Tests.Visual.Editor
|
||||
{
|
||||
private readonly Drawable marker;
|
||||
|
||||
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
||||
private IAdjustableClock adjustableClock;
|
||||
[Resolved]
|
||||
private IBindable<WorkingBeatmap> beatmap { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IAdjustableClock adjustableClock { get; set; }
|
||||
|
||||
public AudioVisualiser()
|
||||
{
|
||||
@ -91,13 +94,6 @@ namespace osu.Game.Tests.Visual.Editor
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IAdjustableClock adjustableClock, IBindable<WorkingBeatmap> beatmap)
|
||||
{
|
||||
this.adjustableClock = adjustableClock;
|
||||
this.beatmap.BindTo(beatmap);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
@ -194,11 +194,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
private class TestScrollingRuleset : Ruleset
|
||||
{
|
||||
public TestScrollingRuleset(RulesetInfo rulesetInfo = null)
|
||||
: base(rulesetInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override IEnumerable<Mod> GetModsFor(ModType type) => throw new NotImplementedException();
|
||||
|
||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => new TestDrawableScrollingRuleset(this, beatmap, mods);
|
||||
|
@ -0,0 +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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Tests.Visual.UserInterface;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneNightcoreBeatContainer : TestSceneBeatSyncedContainer
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(ModNightcore<>)
|
||||
};
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||
|
||||
Beatmap.Value.Track.Start();
|
||||
Beatmap.Value.Track.Seek(Beatmap.Value.Beatmap.HitObjects.First().StartTime - 1000);
|
||||
|
||||
Add(new ModNightcore<HitObject>.NightcoreBeatContainer());
|
||||
|
||||
AddStep("change signature to quadruple", () => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.ForEach(p => p.TimeSignature = TimeSignatures.SimpleQuadruple));
|
||||
AddStep("change signature to triple", () => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.ForEach(p => p.TimeSignature = TimeSignatures.SimpleTriple));
|
||||
}
|
||||
}
|
||||
}
|
@ -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 System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
@ -31,7 +32,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
requestCount = 0;
|
||||
increment = skip_time;
|
||||
|
||||
Child = gameplayClockContainer = new GameplayClockContainer(CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)), new Mod[] { }, 0)
|
||||
Child = gameplayClockContainer = new GameplayClockContainer(CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)), Array.Empty<Mod>(), 0)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
});
|
||||
|
||||
AddStep(@"set max", () => Room.MaxParticipants.Value = 10);
|
||||
AddStep(@"clear users", () => Room.Participants.Value = new User[] { });
|
||||
AddStep(@"clear users", () => Room.Participants.Value = System.Array.Empty<User>());
|
||||
AddStep(@"set max to null", () => Room.MaxParticipants.Value = null);
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,66 @@
|
||||
// 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 osu.Framework.Graphics;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.News;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneNewsOverlay : OsuTestScene
|
||||
{
|
||||
private NewsOverlay news;
|
||||
private TestNewsOverlay news;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
Add(news = new NewsOverlay());
|
||||
Add(news = new TestNewsOverlay());
|
||||
AddStep(@"Show", news.Show);
|
||||
AddStep(@"Hide", news.Hide);
|
||||
|
||||
AddStep(@"Show front page", () => news.ShowFrontPage());
|
||||
AddStep(@"Custom article", () => news.Current.Value = "Test Article 101");
|
||||
|
||||
AddStep(@"Article covers", () => news.LoadAndShowContent(new NewsCoverTest()));
|
||||
}
|
||||
|
||||
private class TestNewsOverlay : NewsOverlay
|
||||
{
|
||||
public new void LoadAndShowContent(NewsContent content) => base.LoadAndShowContent(content);
|
||||
}
|
||||
|
||||
private class NewsCoverTest : NewsContent
|
||||
{
|
||||
public NewsCoverTest()
|
||||
{
|
||||
Spacing = new osuTK.Vector2(0, 10);
|
||||
|
||||
var article = new NewsArticleCover.ArticleInfo
|
||||
{
|
||||
Author = "Ephemeral",
|
||||
CoverUrl = "https://assets.ppy.sh/artists/58/header.jpg",
|
||||
Time = new DateTime(2019, 12, 4),
|
||||
Title = "New Featured Artist: Kurokotei"
|
||||
};
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new NewsArticleCover(article)
|
||||
{
|
||||
Height = 200
|
||||
},
|
||||
new NewsArticleCover(article)
|
||||
{
|
||||
Height = 120
|
||||
},
|
||||
new NewsArticleCover(article)
|
||||
{
|
||||
RelativeSizeAxes = Axes.None,
|
||||
Size = new osuTK.Vector2(400, 200),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
42
osu.Game.Tests/Visual/Online/TestSceneProfileCounterPill.cs
Normal file
@ -0,0 +1,42 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Overlays.Profile.Sections;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneProfileCounterPill : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(CounterPill)
|
||||
};
|
||||
|
||||
private readonly CounterPill pill;
|
||||
private readonly BindableInt value = new BindableInt();
|
||||
|
||||
public TestSceneProfileCounterPill()
|
||||
{
|
||||
Child = pill = new CounterPill
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Current = { BindTarget = value }
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestVisibility()
|
||||
{
|
||||
AddStep("Set value to 0", () => value.Value = 0);
|
||||
AddAssert("Check hidden", () => !pill.IsPresent);
|
||||
AddStep("Set value to 10", () => value.Value = 10);
|
||||
AddAssert("Check visible", () => pill.IsPresent);
|
||||
}
|
||||
}
|
||||
}
|
@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
},
|
||||
Title = "osu!volunteer",
|
||||
Colour = "ff0000",
|
||||
Achievements = new User.UserAchievement[0],
|
||||
Achievements = Array.Empty<User.UserAchievement>(),
|
||||
};
|
||||
|
||||
public TestSceneUserProfileOverlay()
|
||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
new User { PreviousUsernames = new[] { "longusername", "longerusername" } },
|
||||
new User { PreviousUsernames = new[] { "test", "angelsim", "verylongusername" } },
|
||||
new User { PreviousUsernames = new[] { "ihavenoidea", "howcani", "makethistext", "anylonger" } },
|
||||
new User { PreviousUsernames = new string[0] },
|
||||
new User { PreviousUsernames = Array.Empty<string>() },
|
||||
null
|
||||
};
|
||||
|
||||
|
@ -8,6 +8,9 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osuTK;
|
||||
@ -20,8 +23,10 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(BeatmapDetails) };
|
||||
|
||||
private ModDisplay modDisplay;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGameBase game)
|
||||
private void load(OsuGameBase game, RulesetStore rulesets)
|
||||
{
|
||||
BeatmapDetailArea detailsArea;
|
||||
Add(detailsArea = new BeatmapDetailArea
|
||||
@ -31,6 +36,16 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
Size = new Vector2(550f, 450f),
|
||||
});
|
||||
|
||||
Add(modDisplay = new ModDisplay
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Position = new Vector2(0, 25),
|
||||
});
|
||||
|
||||
modDisplay.Current.BindTo(SelectedMods);
|
||||
|
||||
AddStep("all metrics", () => detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
|
||||
{
|
||||
BeatmapInfo =
|
||||
@ -163,6 +178,60 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
}));
|
||||
|
||||
AddStep("null beatmap", () => detailsArea.Beatmap = null);
|
||||
|
||||
Ruleset ruleset = rulesets.AvailableRulesets.First().CreateInstance();
|
||||
|
||||
AddStep("with EZ mod", () =>
|
||||
{
|
||||
detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
Version = "Has Easy Mod",
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Source = "osu!lazer",
|
||||
Tags = "this beatmap has the easy mod enabled",
|
||||
},
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 3,
|
||||
DrainRate = 3,
|
||||
OverallDifficulty = 3,
|
||||
ApproachRate = 3,
|
||||
},
|
||||
StarDifficulty = 1f,
|
||||
}
|
||||
});
|
||||
|
||||
SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModEasy) };
|
||||
});
|
||||
|
||||
AddStep("with HR mod", () =>
|
||||
{
|
||||
detailsArea.Beatmap = new TestWorkingBeatmap(new Beatmap
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
Version = "Has Hard Rock Mod",
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Source = "osu!lazer",
|
||||
Tags = "this beatmap has the hard rock mod enabled",
|
||||
},
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 3,
|
||||
DrainRate = 3,
|
||||
OverallDifficulty = 3,
|
||||
ApproachRate = 3,
|
||||
},
|
||||
StarDifficulty = 1f,
|
||||
}
|
||||
});
|
||||
|
||||
SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModHardRock) };
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual
|
||||
foreach (var type in requiredGameDependencies)
|
||||
{
|
||||
if (game.Dependencies.Get(type) == null)
|
||||
throw new Exception($"{type} has not been cached");
|
||||
throw new InvalidOperationException($"{type} has not been cached");
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -121,7 +121,7 @@ namespace osu.Game.Tests.Visual
|
||||
foreach (var type in requiredGameBaseDependencies)
|
||||
{
|
||||
if (gameBase.Dependencies.Get(type) == null)
|
||||
throw new Exception($"{type} has not been cached");
|
||||
throw new InvalidOperationException($"{type} has not been cached");
|
||||
}
|
||||
|
||||
return true;
|
||||
|