mirror of
https://github.com/osukey/osukey.git
synced 2025-07-02 00:40:09 +09:00
Merge remote-tracking branch 'upstream/master' into Joehuu-score-multiplier-edits
This commit is contained in:
41
.gitattributes
vendored
41
.gitattributes
vendored
@ -1,19 +1,24 @@
|
|||||||
# This won't normalise line endings, but it will ensure that merge drivers use CRLF
|
# Autodetect text files and ensure that we normalise their
|
||||||
* -text eol=crlf
|
# line endings to lf internally. When checked out they may
|
||||||
|
# use different line endings.
|
||||||
|
* text=auto
|
||||||
|
|
||||||
# Currently in-use binary file extensions
|
# Check out with crlf (Windows) line endings
|
||||||
*.blend binary
|
*.sln text eol=crlf
|
||||||
*.bmp binary
|
*.csproj text eol=crlf
|
||||||
*.dll binary
|
*.cs text diff=csharp eol=crlf
|
||||||
*.exe binary
|
*.resx text eol=crlf
|
||||||
*.icns binary
|
*.vsixmanifest text eol=crlf
|
||||||
*.ico binary
|
packages.config text eol=crlf
|
||||||
*.jpg binary
|
App.config text eol=crlf
|
||||||
*.osz2 binary
|
*.bat text eol=crlf
|
||||||
*.pdn binary
|
*.cmd text eol=crlf
|
||||||
*.psd binary
|
*.snippet text eol=crlf
|
||||||
*.PSD binary
|
*.manifest text eol=crlf
|
||||||
*.tga binary
|
|
||||||
*.ttf binary
|
# Check out with lf (UNIX) line endings
|
||||||
*.wav binary
|
*.sh text eol=lf
|
||||||
*.xnb binary
|
.gitignore text eol=lf
|
||||||
|
.gitattributes text eol=lf
|
||||||
|
*.md text eol=lf
|
||||||
|
.travis.yml text eol=lf
|
22
.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml
generated
Normal file
22
.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml
generated
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="RulesetTests (catch)" type="DotNetProject" factoryName=".NET Project">
|
||||||
|
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/net471/osu.Game.Rulesets.Catch.Tests.exe" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests" />
|
||||||
|
<option name="PASS_PARENT_ENVS" value="1" />
|
||||||
|
<envs>
|
||||||
|
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
|
||||||
|
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
|
||||||
|
</envs>
|
||||||
|
<option name="USE_MONO" value="0" />
|
||||||
|
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||||
|
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj" />
|
||||||
|
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
||||||
|
<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=".NETFramework,Version=v4.7.1" />
|
||||||
|
<browser url="http://localhost:5000" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
22
.idea/.idea.osu/.idea/runConfigurations/RulesetTests__mania_.xml
generated
Normal file
22
.idea/.idea.osu/.idea/runConfigurations/RulesetTests__mania_.xml
generated
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="RulesetTests (mania)" type="DotNetProject" factoryName=".NET Project">
|
||||||
|
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/net471/osu.Game.Rulesets.Mania.Tests.exe" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests" />
|
||||||
|
<option name="PASS_PARENT_ENVS" value="1" />
|
||||||
|
<envs>
|
||||||
|
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
|
||||||
|
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
|
||||||
|
</envs>
|
||||||
|
<option name="USE_MONO" value="0" />
|
||||||
|
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||||
|
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj" />
|
||||||
|
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
||||||
|
<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=".NETFramework,Version=v4.7.1" />
|
||||||
|
<browser url="http://localhost:5000" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
22
.idea/.idea.osu/.idea/runConfigurations/RulesetTests__osu__.xml
generated
Normal file
22
.idea/.idea.osu/.idea/runConfigurations/RulesetTests__osu__.xml
generated
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="RulesetTests (osu!)" type="DotNetProject" factoryName=".NET Project">
|
||||||
|
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/net471/osu.Game.Rulesets.Osu.Tests.exe" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests" />
|
||||||
|
<option name="PASS_PARENT_ENVS" value="1" />
|
||||||
|
<envs>
|
||||||
|
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
|
||||||
|
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
|
||||||
|
</envs>
|
||||||
|
<option name="USE_MONO" value="0" />
|
||||||
|
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||||
|
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj" />
|
||||||
|
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
||||||
|
<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=".NETFramework,Version=v4.7.1" />
|
||||||
|
<browser url="http://localhost:5000" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
22
.idea/.idea.osu/.idea/runConfigurations/RulesetTests__taiko_.xml
generated
Normal file
22
.idea/.idea.osu/.idea/runConfigurations/RulesetTests__taiko_.xml
generated
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="RulesetTests (taiko)" type="DotNetProject" factoryName=".NET Project">
|
||||||
|
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/net471/osu.Game.Rulesets.Taiko.Tests.exe" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests" />
|
||||||
|
<option name="PASS_PARENT_ENVS" value="1" />
|
||||||
|
<envs>
|
||||||
|
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
|
||||||
|
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
|
||||||
|
</envs>
|
||||||
|
<option name="USE_MONO" value="0" />
|
||||||
|
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||||
|
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj" />
|
||||||
|
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
||||||
|
<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=".NETFramework,Version=v4.7.1" />
|
||||||
|
<browser url="http://localhost:5000" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
@ -1,6 +1,6 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="VisualTests (net461)" type="DotNetProject" factoryName=".NET Project" singleton="true">
|
<configuration default="false" name="VisualTests (net471)" type="DotNetProject" factoryName=".NET Project" singleton="true">
|
||||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/net461/osu.Game.Tests.exe" />
|
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/net471/osu.Game.Tests.exe" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="" />
|
<option name="PROGRAM_PARAMETERS" value="" />
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests" />
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests" />
|
||||||
<option name="PASS_PARENT_ENVS" value="1" />
|
<option name="PASS_PARENT_ENVS" value="1" />
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||||
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||||
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.6.1" />
|
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" />
|
||||||
<method />
|
<method />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
@ -1,6 +1,6 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="osu! (net461)" type="DotNetProject" factoryName=".NET Project" singleton="true">
|
<configuration default="false" name="osu! (net471)" type="DotNetProject" factoryName=".NET Project" singleton="true">
|
||||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net461/osu!.exe" />
|
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net471/osu!.exe" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="" />
|
<option name="PROGRAM_PARAMETERS" value="" />
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop" />
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop" />
|
||||||
<option name="PASS_PARENT_ENVS" value="1" />
|
<option name="PASS_PARENT_ENVS" value="1" />
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||||
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||||
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.6.1" />
|
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" />
|
||||||
<method />
|
<method />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
26
.vscode/launch.json
vendored
26
.vscode/launch.json
vendored
@ -2,13 +2,13 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "VisualTests (Debug, net461)",
|
"name": "VisualTests (Debug, net471)",
|
||||||
"windows": {
|
"windows": {
|
||||||
"type": "clr"
|
"type": "clr"
|
||||||
},
|
},
|
||||||
"type": "mono",
|
"type": "mono",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net461/osu.Game.Tests.exe",
|
"program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net471/osu.Game.Tests.exe",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Debug, msbuild)",
|
"preLaunchTask": "Build (Debug, msbuild)",
|
||||||
"runtimeExecutable": null,
|
"runtimeExecutable": null,
|
||||||
@ -16,13 +16,13 @@
|
|||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "VisualTests (Release, net461)",
|
"name": "VisualTests (Release, net471)",
|
||||||
"windows": {
|
"windows": {
|
||||||
"type": "clr"
|
"type": "clr"
|
||||||
},
|
},
|
||||||
"type": "mono",
|
"type": "mono",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net461/osu.Game.Tests.exe",
|
"program": "${workspaceRoot}/osu.Game.Tests/bin/Release/net471/osu.Game.Tests.exe",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Release, msbuild)",
|
"preLaunchTask": "Build (Release, msbuild)",
|
||||||
"runtimeExecutable": null,
|
"runtimeExecutable": null,
|
||||||
@ -30,13 +30,13 @@
|
|||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "osu! (Debug, net461)",
|
"name": "osu! (Debug, net471)",
|
||||||
"windows": {
|
"windows": {
|
||||||
"type": "clr"
|
"type": "clr"
|
||||||
},
|
},
|
||||||
"type": "mono",
|
"type": "mono",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/net461/osu!.exe",
|
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/net471/osu!.exe",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Debug, msbuild)",
|
"preLaunchTask": "Build (Debug, msbuild)",
|
||||||
"runtimeExecutable": null,
|
"runtimeExecutable": null,
|
||||||
@ -44,13 +44,13 @@
|
|||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "osu! (Release, net461)",
|
"name": "osu! (Release, net471)",
|
||||||
"windows": {
|
"windows": {
|
||||||
"type": "clr"
|
"type": "clr"
|
||||||
},
|
},
|
||||||
"type": "mono",
|
"type": "mono",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceRoot}/osu.Desktop/bin/Release/net461/osu!.exe",
|
"program": "${workspaceRoot}/osu.Desktop/bin/Release/net471/osu!.exe",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Release, msbuild)",
|
"preLaunchTask": "Build (Release, msbuild)",
|
||||||
"runtimeExecutable": null,
|
"runtimeExecutable": null,
|
||||||
@ -66,7 +66,7 @@
|
|||||||
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll"
|
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll"
|
||||||
],
|
],
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Debug, dotnet)",
|
"preLaunchTask": "Build tests (Debug, dotnet)",
|
||||||
"env": {},
|
"env": {},
|
||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
@ -76,10 +76,10 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "dotnet",
|
"program": "dotnet",
|
||||||
"args": [
|
"args": [
|
||||||
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll"
|
"${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.0/osu.Game.Tests.dll"
|
||||||
],
|
],
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Release, dotnet)",
|
"preLaunchTask": "Build tests (Release, dotnet)",
|
||||||
"env": {},
|
"env": {},
|
||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
@ -92,7 +92,7 @@
|
|||||||
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.0/osu!.dll",
|
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.0/osu!.dll",
|
||||||
],
|
],
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Debug, dotnet)",
|
"preLaunchTask": "Build osu! (Debug, dotnet)",
|
||||||
"env": {},
|
"env": {},
|
||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
@ -105,7 +105,7 @@
|
|||||||
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.0/osu!.dll",
|
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.0/osu!.dll",
|
||||||
],
|
],
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Release, dotnet)",
|
"preLaunchTask": "Build osu! (Release, dotnet)",
|
||||||
"env": {},
|
"env": {},
|
||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
}
|
}
|
||||||
|
43
.vscode/tasks.json
vendored
43
.vscode/tasks.json
vendored
@ -8,7 +8,7 @@
|
|||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "msbuild",
|
"command": "msbuild",
|
||||||
"args": [
|
"args": [
|
||||||
"/p:TargetFramework=net461",
|
"/p:TargetFramework=net471",
|
||||||
"/p:GenerateFullPaths=true",
|
"/p:GenerateFullPaths=true",
|
||||||
"/m",
|
"/m",
|
||||||
"/verbosity:m"
|
"/verbosity:m"
|
||||||
@ -22,7 +22,7 @@
|
|||||||
"command": "msbuild",
|
"command": "msbuild",
|
||||||
"args": [
|
"args": [
|
||||||
"/p:Configuration=Release",
|
"/p:Configuration=Release",
|
||||||
"/p:TargetFramework=net461",
|
"/p:TargetFramework=net471",
|
||||||
"/p:GenerateFullPaths=true",
|
"/p:GenerateFullPaths=true",
|
||||||
"/m",
|
"/m",
|
||||||
"/verbosity:m"
|
"/verbosity:m"
|
||||||
@ -31,7 +31,7 @@
|
|||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Build (Debug, dotnet)",
|
"label": "Build osu! (Debug, dotnet)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "dotnet",
|
"command": "dotnet",
|
||||||
"args": [
|
"args": [
|
||||||
@ -47,7 +47,7 @@
|
|||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Build (Release, dotnet)",
|
"label": "Build osu! (Release, dotnet)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "dotnet",
|
"command": "dotnet",
|
||||||
"args": [
|
"args": [
|
||||||
@ -64,7 +64,40 @@
|
|||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Restore (net461)",
|
"label": "Build tests (Debug, dotnet)",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "dotnet",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--no-restore",
|
||||||
|
"osu.Game.Tests",
|
||||||
|
"/p:TargetFramework=netcoreapp2.0",
|
||||||
|
"/p:GenerateFullPaths=true",
|
||||||
|
"/m",
|
||||||
|
"/verbosity:m"
|
||||||
|
],
|
||||||
|
"group": "build",
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Build tests (Release, dotnet)",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "dotnet",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--no-restore",
|
||||||
|
"osu.Game.Tests",
|
||||||
|
"/p:TargetFramework=netcoreapp2.0",
|
||||||
|
"/p:Configuration=Release",
|
||||||
|
"/p:GenerateFullPaths=true",
|
||||||
|
"/m",
|
||||||
|
"/verbosity:m"
|
||||||
|
],
|
||||||
|
"group": "build",
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Restore (net471)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "nuget",
|
"command": "nuget",
|
||||||
"args": [
|
"args": [
|
||||||
|
@ -8,7 +8,7 @@ This is still heavily under development and is not intended for end-user use. Th
|
|||||||
|
|
||||||
# Requirements
|
# Requirements
|
||||||
|
|
||||||
- A desktop platform that can compile .NET 4.6.1. We recommend using [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio for Mac](https://www.visualstudio.com/vs/visual-studio-mac/) (macOS) or [MonoDevelop](http://www.monodevelop.com/download/) (Linux), all of which are free. [Visual Studio Code](https://code.visualstudio.com/) may also be used but requires further setup steps which are not covered here.
|
- A desktop platform that can compile .NET 4.7.1. We recommend using [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio for Mac](https://www.visualstudio.com/vs/visual-studio-mac/) (macOS) or [MonoDevelop](http://www.monodevelop.com/download/) (Linux), all of which are free. [Visual Studio Code](https://code.visualstudio.com/) may also be used but requires further setup steps which are not covered here.
|
||||||
|
|
||||||
# Getting Started
|
# Getting Started
|
||||||
- Clone the repository including submodules (`git clone --recurse-submodules https://github.com/ppy/osu`)
|
- Clone the repository including submodules (`git clone --recurse-submodules https://github.com/ppy/osu`)
|
||||||
|
46
app.manifest
Normal file
46
app.manifest
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<assemblyIdentity version="1.0.0.0" name="osu!" />
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
</requestedPrivileges>
|
||||||
|
<applicationRequestMinimum>
|
||||||
|
<defaultAssemblyRequest permissionSetReference="Custom" />
|
||||||
|
<PermissionSet class="System.Security.PermissionSet" version="1" Unrestricted="true" ID="Custom" SameSite="site" />
|
||||||
|
</applicationRequestMinimum>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<!-- Windows Vista -->
|
||||||
|
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
|
||||||
|
<!-- Windows 7 -->
|
||||||
|
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
|
||||||
|
<!-- Windows 8 -->
|
||||||
|
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
|
||||||
|
<!-- Windows 8.1 -->
|
||||||
|
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
|
||||||
|
<!-- Windows 10 -->
|
||||||
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
<asmv3:application>
|
||||||
|
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
|
||||||
|
<dpiAware>true</dpiAware>
|
||||||
|
</asmv3:windowsSettings>
|
||||||
|
</asmv3:application>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity
|
||||||
|
type="win32"
|
||||||
|
name="Microsoft.Windows.Common-Controls"
|
||||||
|
version="6.0.0.0"
|
||||||
|
processorArchitecture="*"
|
||||||
|
publicKeyToken="6595b64144ccf1df"
|
||||||
|
language="*"
|
||||||
|
/>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
</asmv1:assembly>
|
@ -1,4 +1,3 @@
|
|||||||
# 2017-09-14
|
|
||||||
clone_depth: 1
|
clone_depth: 1
|
||||||
version: '{branch}-{build}'
|
version: '{branch}-{build}'
|
||||||
image: Visual Studio 2017
|
image: Visual Studio 2017
|
||||||
@ -12,12 +11,12 @@ install:
|
|||||||
- cmd: git submodule update --init --recursive --depth=5
|
- cmd: git submodule update --init --recursive --depth=5
|
||||||
- cmd: choco install resharper-clt -y
|
- cmd: choco install resharper-clt -y
|
||||||
- cmd: choco install nvika -y
|
- cmd: choco install nvika -y
|
||||||
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.4/CodeFileSanity.exe
|
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.5/CodeFileSanity.exe
|
||||||
before_build:
|
before_build:
|
||||||
- cmd: CodeFileSanity.exe
|
- cmd: CodeFileSanity.exe
|
||||||
- cmd: nuget restore -verbosity quiet
|
- cmd: nuget restore -verbosity quiet
|
||||||
environment:
|
environment:
|
||||||
TargetFramework: net461
|
TargetFramework: net471
|
||||||
build:
|
build:
|
||||||
project: osu.sln
|
project: osu.sln
|
||||||
parallel: true
|
parallel: true
|
||||||
|
34
appveyor_deploy.yml
Normal file
34
appveyor_deploy.yml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- release
|
||||||
|
skip_tags: true
|
||||||
|
skip_branch_with_pr: true
|
||||||
|
clone_depth: 1
|
||||||
|
version: '{branch}-{build}'
|
||||||
|
image: Visual Studio 2017
|
||||||
|
configuration: Debug
|
||||||
|
cache:
|
||||||
|
- packages -> **\packages.config
|
||||||
|
install:
|
||||||
|
- cmd: git submodule update --init --recursive --depth=5
|
||||||
|
before_build:
|
||||||
|
- cmd: nuget restore -verbosity quiet
|
||||||
|
build:
|
||||||
|
project: osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
|
||||||
|
verbosity: minimal
|
||||||
|
after_build:
|
||||||
|
- ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1'))
|
||||||
|
- appveyor DownloadFile https://puu.sh/A6g5K/4d08705438.enc # signing certificate
|
||||||
|
- cmd: appveyor-tools\secure-file -decrypt 4d08705438.enc -secret %decode_secret% -out %HOMEPATH%\deanherbert.pfx
|
||||||
|
- appveyor DownloadFile https://puu.sh/A6g75/fdc6f19b04.enc # deploy configuration
|
||||||
|
- cmd: appveyor-tools\secure-file -decrypt fdc6f19b04.enc -secret %decode_secret% -out osu.Desktop.Deploy\bin\Debug\net471\osu.Desktop.Deploy.exe.config
|
||||||
|
- cd osu.Desktop.Deploy\bin\Debug\net471\
|
||||||
|
- osu.Desktop.Deploy.exe %code_signing_password%
|
||||||
|
environment:
|
||||||
|
TargetFramework: net471
|
||||||
|
decode_secret:
|
||||||
|
secure: i67IC2xj6DjjxmA6Oj2jing3+MwzLkq6CbGsjfZ7rdY=
|
||||||
|
code_signing_password:
|
||||||
|
secure: 34tLNqvjmmZEi97MLKfrnQ==
|
||||||
|
artifacts:
|
||||||
|
- path: 'Releases\*'
|
Submodule osu-framework updated: 85b3494117...aebfa5bc5c
4
osu.Desktop.Deploy/.vscode/launch.json
vendored
4
osu.Desktop.Deploy/.vscode/launch.json
vendored
@ -7,7 +7,7 @@
|
|||||||
"name": "Deploy (Debug)",
|
"name": "Deploy (Debug)",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "mono",
|
"type": "mono",
|
||||||
"program": "${workspaceRoot}/bin/Debug/net461/osu.Desktop.Deploy.exe",
|
"program": "${workspaceRoot}/bin/Debug/net471/osu.Desktop.Deploy.exe",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Debug)",
|
"preLaunchTask": "Build (Debug)",
|
||||||
"runtimeExecutable": null,
|
"runtimeExecutable": null,
|
||||||
@ -18,7 +18,7 @@
|
|||||||
"name": "Deploy (Release)",
|
"name": "Deploy (Release)",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "clr",
|
"type": "clr",
|
||||||
"program": "${workspaceRoot}/bin/Release/net461/osu.Desktop.Deploy.exe",
|
"program": "${workspaceRoot}/bin/Release/net471/osu.Desktop.Deploy.exe",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Release)",
|
"preLaunchTask": "Build (Release)",
|
||||||
"runtimeExecutable": null,
|
"runtimeExecutable": null,
|
||||||
|
@ -7,6 +7,7 @@ using System.Configuration;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Management.Automation;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Framework.IO.Network;
|
using osu.Framework.IO.Network;
|
||||||
using FileWebRequest = osu.Framework.IO.Network.FileWebRequest;
|
using FileWebRequest = osu.Framework.IO.Network.FileWebRequest;
|
||||||
@ -18,7 +19,7 @@ namespace osu.Desktop.Deploy
|
|||||||
{
|
{
|
||||||
private static string packages => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages");
|
private static string packages => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages");
|
||||||
private static string nugetPath => Path.Combine(packages, @"nuget.commandline\4.5.1\tools\NuGet.exe");
|
private static string nugetPath => Path.Combine(packages, @"nuget.commandline\4.5.1\tools\NuGet.exe");
|
||||||
private static string squirrelPath => Path.Combine(packages, @"squirrel.windows\1.7.8\tools\Squirrel.exe");
|
private static string squirrelPath => Path.Combine(packages, @"squirrel.windows\1.8.0\tools\Squirrel.exe");
|
||||||
private const string msbuild_path = @"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe";
|
private const string msbuild_path = @"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe";
|
||||||
|
|
||||||
public static string StagingFolder = ConfigurationManager.AppSettings["StagingFolder"];
|
public static string StagingFolder = ConfigurationManager.AppSettings["StagingFolder"];
|
||||||
@ -57,8 +58,12 @@ namespace osu.Desktop.Deploy
|
|||||||
|
|
||||||
private static string codeSigningPassword;
|
private static string codeSigningPassword;
|
||||||
|
|
||||||
|
private static bool interactive;
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
interactive = args.Length == 0;
|
||||||
|
|
||||||
displayHeader();
|
displayHeader();
|
||||||
|
|
||||||
findSolutionPath();
|
findSolutionPath();
|
||||||
@ -82,19 +87,20 @@ namespace osu.Desktop.Deploy
|
|||||||
string version = $"{verBase}{increment}";
|
string version = $"{verBase}{increment}";
|
||||||
|
|
||||||
Console.ForegroundColor = ConsoleColor.White;
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
Console.Write($"Ready to deploy {version}: ");
|
Console.Write($"Ready to deploy {version}!");
|
||||||
Console.ReadLine();
|
pauseIfInteractive();
|
||||||
|
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(CodeSigningCertificate))
|
if (!string.IsNullOrEmpty(CodeSigningCertificate))
|
||||||
{
|
{
|
||||||
Console.Write("Enter code signing password: ");
|
Console.Write("Enter code signing password: ");
|
||||||
codeSigningPassword = readLineMasked();
|
codeSigningPassword = args.Length > 0 ? args[0] : readLineMasked();
|
||||||
}
|
}
|
||||||
|
|
||||||
write("Updating AssemblyInfo...");
|
write("Updating AssemblyInfo...");
|
||||||
updateCsprojVersion(version);
|
updateCsprojVersion(version);
|
||||||
|
updateAppveyorVersion(version);
|
||||||
|
|
||||||
write("Running build process...");
|
write("Running build process...");
|
||||||
foreach (string targetName in TargetNames.Split(','))
|
foreach (string targetName in TargetNames.Split(','))
|
||||||
@ -109,7 +115,7 @@ namespace osu.Desktop.Deploy
|
|||||||
checkReleaseFiles();
|
checkReleaseFiles();
|
||||||
|
|
||||||
write("Running squirrel build...");
|
write("Running squirrel build...");
|
||||||
runCommand(squirrelPath, $"--releasify {stagingPath}\\{nupkgFilename(version)} --setupIcon {iconPath} --icon {iconPath} {codeSigningCmd} --no-msi");
|
runCommand(squirrelPath, $"--releasify {stagingPath}\\{nupkgFilename(version)} --framework-version=net471 --setupIcon {iconPath} --icon {iconPath} {codeSigningCmd} --no-msi");
|
||||||
|
|
||||||
//prune again to clean up before upload.
|
//prune again to clean up before upload.
|
||||||
pruneReleases();
|
pruneReleases();
|
||||||
@ -124,7 +130,7 @@ namespace osu.Desktop.Deploy
|
|||||||
updateCsprojVersion("0.0.0");
|
updateCsprojVersion("0.0.0");
|
||||||
|
|
||||||
write("Done!", ConsoleColor.White);
|
write("Done!", ConsoleColor.White);
|
||||||
Console.ReadLine();
|
pauseIfInteractive();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void displayHeader()
|
private static void displayHeader()
|
||||||
@ -388,10 +394,37 @@ namespace osu.Desktop.Deploy
|
|||||||
Console.ForegroundColor = ConsoleColor.Red;
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
Console.WriteLine($"FATAL ERROR: {message}");
|
Console.WriteLine($"FATAL ERROR: {message}");
|
||||||
|
|
||||||
Console.ReadLine();
|
pauseIfInteractive();
|
||||||
Environment.Exit(-1);
|
Environment.Exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void pauseIfInteractive()
|
||||||
|
{
|
||||||
|
if (interactive)
|
||||||
|
Console.ReadLine();
|
||||||
|
else
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool updateAppveyorVersion(string version)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (PowerShell ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.AddScript($"Update-AppveyorBuild -Version \"{version}\"");
|
||||||
|
ps.Invoke();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// we don't have appveyor and don't care
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static void write(string message, ConsoleColor col = ConsoleColor.Gray)
|
private static void write(string message, ConsoleColor col = ConsoleColor.Gray)
|
||||||
{
|
{
|
||||||
if (sw.ElapsedMilliseconds > 0)
|
if (sw.ElapsedMilliseconds > 0)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Import Project="..\osu.Game.props" />
|
<Import Project="..\osu.Game.props" />
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
<TargetFrameworks>net461</TargetFrameworks>
|
<TargetFrameworks>net471</TargetFrameworks>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
@ -11,8 +11,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="NuGet.CommandLine" Version="4.5.1" />
|
<PackageReference Include="NuGet.CommandLine" Version="4.5.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.8.1" />
|
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||||
<PackageReference Include="squirrel.windows" Version="1.7.8" Condition="'$(TargetFramework)' == 'net461'" />
|
<PackageReference Include="squirrel.windows" Version="1.8.0" Condition="'$(TargetFramework)' == 'net471'" />
|
||||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.4.0" />
|
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.4.0" />
|
||||||
|
<PackageReference Include="System.Management.Automation.dll" Version="10.0.10586" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Import Project="..\osu.Game.props" />
|
<Import Project="..\osu.Game.props" />
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
<TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
|
<TargetFrameworks>net471;netcoreapp2.0</TargetFrameworks>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
@ -10,11 +10,11 @@
|
|||||||
<Title>osu!lazer</Title>
|
<Title>osu!lazer</Title>
|
||||||
<Product>osu!lazer</Product>
|
<Product>osu!lazer</Product>
|
||||||
<ApplicationIcon>lazer.ico</ApplicationIcon>
|
<ApplicationIcon>lazer.ico</ApplicationIcon>
|
||||||
<Version>0.0.0.0</Version>
|
<Version>0.0.0</Version>
|
||||||
<FileVersion>0.0.0.0</FileVersion>
|
<FileVersion>0.0.0</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Label="Defines">
|
<PropertyGroup Label="Defines">
|
||||||
<DefineConstants Condition="'$(TargetFramework)' == 'net461'">$(DefineConstants);NET_FRAMEWORK</DefineConstants>
|
<DefineConstants Condition="'$(TargetFramework)' == 'net471'">$(DefineConstants);NET_FRAMEWORK</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<StartupObject>osu.Desktop.Program</StartupObject>
|
<StartupObject>osu.Desktop.Program</StartupObject>
|
||||||
@ -31,7 +31,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
|
||||||
<PackageReference Include="squirrel.windows" Version="1.7.8" Condition="'$(TargetFramework)' == 'net461'" />
|
<PackageReference Include="squirrel.windows" Version="1.8.0" Condition="'$(TargetFramework)' == 'net471'" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Resources">
|
<ItemGroup Label="Resources">
|
||||||
<EmbeddedResource Include="lazer.ico" />
|
<EmbeddedResource Include="lazer.ico" />
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "VisualTests (Debug, net461)",
|
"name": "VisualTests (Debug, net471)",
|
||||||
"windows": {
|
"windows": {
|
||||||
"type": "clr"
|
"type": "clr"
|
||||||
},
|
},
|
||||||
"type": "mono",
|
"type": "mono",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Catch.Tests.exe",
|
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Catch.Tests.exe",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Debug, msbuild)",
|
"preLaunchTask": "Build (Debug, msbuild)",
|
||||||
"runtimeExecutable": null,
|
"runtimeExecutable": null,
|
||||||
@ -16,13 +16,13 @@
|
|||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "VisualTests (Release, net461)",
|
"name": "VisualTests (Release, net471)",
|
||||||
"windows": {
|
"windows": {
|
||||||
"type": "clr"
|
"type": "clr"
|
||||||
},
|
},
|
||||||
"type": "mono",
|
"type": "mono",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Catch.Tests.exe",
|
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Catch.Tests.exe",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Release, msbuild)",
|
"preLaunchTask": "Build (Release, msbuild)",
|
||||||
"runtimeExecutable": null,
|
"runtimeExecutable": null,
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"command": "msbuild",
|
"command": "msbuild",
|
||||||
"args": [
|
"args": [
|
||||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||||
"/p:TargetFramework=net461",
|
"/p:TargetFramework=net471",
|
||||||
"/p:GenerateFullPaths=true",
|
"/p:GenerateFullPaths=true",
|
||||||
"/m",
|
"/m",
|
||||||
"/verbosity:m"
|
"/verbosity:m"
|
||||||
@ -24,7 +24,7 @@
|
|||||||
"args": [
|
"args": [
|
||||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||||
"/p:Configuration=Release",
|
"/p:Configuration=Release",
|
||||||
"/p:TargetFramework=net461",
|
"/p:TargetFramework=net471",
|
||||||
"/p:GenerateFullPaths=true",
|
"/p:GenerateFullPaths=true",
|
||||||
"/m",
|
"/m",
|
||||||
"/verbosity:m"
|
"/verbosity:m"
|
||||||
@ -66,7 +66,7 @@
|
|||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Restore (net461)",
|
"label": "Restore (net471)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "nuget",
|
"command": "nuget",
|
||||||
"args": [
|
"args": [
|
||||||
|
@ -5,8 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -14,7 +12,7 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Tests
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
{
|
{
|
||||||
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
internal class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
||||||
|
|
||||||
@ -47,10 +45,10 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IBeatmapConverter CreateConverter(Beatmap beatmap) => new CatchBeatmapConverter();
|
protected override Ruleset CreateRuleset() => new CatchRuleset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ConvertValue : IEquatable<ConvertValue>
|
internal struct ConvertValue : IEquatable<ConvertValue>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A sane value to account for osu!stable using ints everwhere.
|
/// A sane value to account for osu!stable using ints everwhere.
|
||||||
|
62
osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs
Normal file
62
osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
|
{
|
||||||
|
public class TestCaseAutoJuiceStream : TestCasePlayer
|
||||||
|
{
|
||||||
|
public TestCaseAutoJuiceStream()
|
||||||
|
: base(new CatchRuleset())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IBeatmap CreateBeatmap(Ruleset ruleset)
|
||||||
|
{
|
||||||
|
var beatmap = new Beatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo = new BeatmapInfo
|
||||||
|
{
|
||||||
|
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6, SliderMultiplier = 3 },
|
||||||
|
Ruleset = ruleset.RulesetInfo
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
float width = (i % 10 + 1) / 20f;
|
||||||
|
|
||||||
|
beatmap.HitObjects.Add(new JuiceStream
|
||||||
|
{
|
||||||
|
X = 0.5f - width / 2,
|
||||||
|
ControlPoints = new List<Vector2>
|
||||||
|
{
|
||||||
|
Vector2.Zero,
|
||||||
|
new Vector2(width * CatchPlayfield.BASE_WIDTH, 0)
|
||||||
|
},
|
||||||
|
CurveType = CurveType.Linear,
|
||||||
|
Distance = width * CatchPlayfield.BASE_WIDTH,
|
||||||
|
StartTime = i * 2000,
|
||||||
|
NewCombo = i % 8 == 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return beatmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
|
||||||
|
{
|
||||||
|
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
|
||||||
|
return base.CreatePlayer(beatmap, ruleset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Beatmap CreateBeatmap(Ruleset ruleset)
|
protected override IBeatmap CreateBeatmap(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap
|
var beatmap = new Beatmap
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Beatmap CreateBeatmap(Ruleset ruleset)
|
protected override IBeatmap CreateBeatmap(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap
|
var beatmap = new Beatmap
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Beatmap CreateBeatmap(Ruleset ruleset)
|
protected override IBeatmap CreateBeatmap(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap { BeatmapInfo = { Ruleset = ruleset.RulesetInfo } };
|
var beatmap = new Beatmap { BeatmapInfo = { Ruleset = ruleset.RulesetInfo } };
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Import Project="..\osu.TestProject.props" />
|
<Import Project="..\osu.TestProject.props" />
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
<TargetFrameworks>netcoreapp2.0;net471</TargetFrameworks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="Project References">
|
<ItemGroup Label="Project References">
|
||||||
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
|
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
|
||||||
|
43
osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs
Normal file
43
osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmap.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||||
|
{
|
||||||
|
public class CatchBeatmap : Beatmap<CatchHitObject>
|
||||||
|
{
|
||||||
|
public override IEnumerable<BeatmapStatistic> GetStatistics()
|
||||||
|
{
|
||||||
|
int fruits = HitObjects.Count(s => s is Fruit);
|
||||||
|
int juiceStreams = HitObjects.Count(s => s is JuiceStream);
|
||||||
|
int bananaShowers = HitObjects.Count(s => s is BananaShower);
|
||||||
|
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
new BeatmapStatistic
|
||||||
|
{
|
||||||
|
Name = @"Fruit Count",
|
||||||
|
Content = fruits.ToString(),
|
||||||
|
Icon = FontAwesome.fa_circle_o
|
||||||
|
},
|
||||||
|
new BeatmapStatistic
|
||||||
|
{
|
||||||
|
Name = @"Juice Stream Count",
|
||||||
|
Content = juiceStreams.ToString(),
|
||||||
|
Icon = FontAwesome.fa_circle
|
||||||
|
},
|
||||||
|
new BeatmapStatistic
|
||||||
|
{
|
||||||
|
Name = @"Banana Shower Count",
|
||||||
|
Content = bananaShowers.ToString(),
|
||||||
|
Icon = FontAwesome.fa_circle
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,9 +13,14 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
{
|
{
|
||||||
public class CatchBeatmapConverter : BeatmapConverter<CatchHitObject>
|
public class CatchBeatmapConverter : BeatmapConverter<CatchHitObject>
|
||||||
{
|
{
|
||||||
|
public CatchBeatmapConverter(IBeatmap beatmap)
|
||||||
|
: base(beatmap)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) };
|
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) };
|
||||||
|
|
||||||
protected override IEnumerable<CatchHitObject> ConvertHitObject(HitObject obj, Beatmap beatmap)
|
protected override IEnumerable<CatchHitObject> ConvertHitObject(HitObject obj, IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
var curveData = obj as IHasCurve;
|
var curveData = obj as IHasCurve;
|
||||||
var positionData = obj as IHasXPosition;
|
var positionData = obj as IHasXPosition;
|
||||||
@ -23,7 +28,20 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
var endTime = obj as IHasEndTime;
|
var endTime = obj as IHasEndTime;
|
||||||
|
|
||||||
if (positionData == null)
|
if (positionData == null)
|
||||||
|
{
|
||||||
|
if (endTime != null)
|
||||||
|
{
|
||||||
|
yield return new BananaShower
|
||||||
|
{
|
||||||
|
StartTime = obj.StartTime,
|
||||||
|
Samples = obj.Samples,
|
||||||
|
Duration = endTime.Duration,
|
||||||
|
NewCombo = comboData?.NewCombo ?? false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
yield break;
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
if (curveData != null)
|
if (curveData != null)
|
||||||
{
|
{
|
||||||
@ -43,19 +61,6 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endTime != null)
|
|
||||||
{
|
|
||||||
yield return new BananaShower
|
|
||||||
{
|
|
||||||
StartTime = obj.StartTime,
|
|
||||||
Samples = obj.Samples,
|
|
||||||
Duration = endTime.Duration,
|
|
||||||
NewCombo = comboData?.NewCombo ?? false
|
|
||||||
};
|
|
||||||
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return new Fruit
|
yield return new Fruit
|
||||||
{
|
{
|
||||||
StartTime = obj.StartTime,
|
StartTime = obj.StartTime,
|
||||||
@ -64,5 +69,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
X = positionData.X / CatchPlayfield.BASE_WIDTH
|
X = positionData.X / CatchPlayfield.BASE_WIDTH
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override Beatmap<CatchHitObject> CreateBeatmap() => new CatchBeatmap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,16 +12,21 @@ using OpenTK;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Beatmaps
|
namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||||
{
|
{
|
||||||
public class CatchBeatmapProcessor : BeatmapProcessor<CatchHitObject>
|
public class CatchBeatmapProcessor : BeatmapProcessor
|
||||||
{
|
{
|
||||||
public override void PostProcess(Beatmap<CatchHitObject> beatmap)
|
public CatchBeatmapProcessor(IBeatmap beatmap)
|
||||||
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
initialiseHyperDash(beatmap.HitObjects);
|
}
|
||||||
|
|
||||||
base.PostProcess(beatmap);
|
public override void PostProcess()
|
||||||
|
{
|
||||||
|
initialiseHyperDash((List<CatchHitObject>)Beatmap.HitObjects);
|
||||||
|
|
||||||
|
base.PostProcess();
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
foreach (var obj in beatmap.HitObjects)
|
foreach (var obj in Beatmap.HitObjects.OfType<CatchHitObject>())
|
||||||
obj.IndexInBeatmap = index++;
|
obj.IndexInBeatmap = index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,12 +12,18 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Catch.Replays;
|
using osu.Game.Rulesets.Catch.Replays;
|
||||||
using osu.Game.Rulesets.Replays.Types;
|
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.Difficulty;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch
|
namespace osu.Game.Rulesets.Catch
|
||||||
{
|
{
|
||||||
public class CatchRuleset : Ruleset
|
public class CatchRuleset : Ruleset
|
||||||
{
|
{
|
||||||
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new CatchRulesetContainer(this, beatmap, isForCurrentRuleset);
|
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap) => new CatchRulesetContainer(this, beatmap);
|
||||||
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap);
|
||||||
|
public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap);
|
||||||
|
|
||||||
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[]
|
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[]
|
||||||
{
|
{
|
||||||
@ -29,6 +35,44 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
new KeyBinding(InputKey.Shift, CatchAction.Dash),
|
new KeyBinding(InputKey.Shift, CatchAction.Dash),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
||||||
|
{
|
||||||
|
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||||
|
yield return new CatchModNightcore();
|
||||||
|
else if (mods.HasFlag(LegacyMods.DoubleTime))
|
||||||
|
yield return new CatchModDoubleTime();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Autoplay))
|
||||||
|
yield return new CatchModAutoplay();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Easy))
|
||||||
|
yield return new CatchModEasy();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Flashlight))
|
||||||
|
yield return new CatchModFlashlight();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.HalfTime))
|
||||||
|
yield return new CatchModHalfTime();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.HardRock))
|
||||||
|
yield return new CatchModHardRock();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Hidden))
|
||||||
|
yield return new CatchModHidden();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.NoFail))
|
||||||
|
yield return new CatchModNoFail();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Perfect))
|
||||||
|
yield return new CatchModPerfect();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Relax))
|
||||||
|
yield return new CatchModRelax();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.SuddenDeath))
|
||||||
|
yield return new CatchModSuddenDeath();
|
||||||
|
}
|
||||||
|
|
||||||
public override IEnumerable<Mod> GetModsFor(ModType type)
|
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
@ -99,7 +143,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
|
|
||||||
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o };
|
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o };
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap);
|
||||||
|
|
||||||
public override int? LegacyID => 2;
|
public override int? LegacyID => 2;
|
||||||
|
|
||||||
|
@ -1,21 +1,18 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch
|
namespace osu.Game.Rulesets.Catch.Difficulty
|
||||||
{
|
{
|
||||||
public class CatchDifficultyCalculator : DifficultyCalculator<CatchHitObject>
|
public class CatchDifficultyCalculator : DifficultyCalculator
|
||||||
{
|
{
|
||||||
public CatchDifficultyCalculator(Beatmap beatmap) : base(beatmap)
|
public CatchDifficultyCalculator(IBeatmap beatmap) : base(beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) => 0;
|
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) => 0;
|
||||||
|
|
||||||
protected override BeatmapConverter<CatchHitObject> CreateBeatmapConverter(Beatmap beatmap) => new CatchBeatmapConverter();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,13 +1,91 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Framework.MathUtils;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using System;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Mods
|
namespace osu.Game.Rulesets.Catch.Mods
|
||||||
{
|
{
|
||||||
public class CatchModHardRock : ModHardRock
|
public class CatchModHardRock : ModHardRock, IApplicableToHitObject
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => 1.12;
|
||||||
public override bool Ranked => true;
|
public override bool Ranked => true;
|
||||||
|
|
||||||
|
private float lastStartX;
|
||||||
|
private int lastStartTime;
|
||||||
|
|
||||||
|
public void ApplyToHitObject(HitObject hitObject)
|
||||||
|
{
|
||||||
|
var catchObject = (CatchHitObject)hitObject;
|
||||||
|
|
||||||
|
float position = catchObject.X;
|
||||||
|
int startTime = (int)hitObject.StartTime;
|
||||||
|
|
||||||
|
if (lastStartX == 0)
|
||||||
|
{
|
||||||
|
lastStartX = position;
|
||||||
|
lastStartTime = startTime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float diff = lastStartX - position;
|
||||||
|
int timeDiff = startTime - lastStartTime;
|
||||||
|
|
||||||
|
if (timeDiff > 1000)
|
||||||
|
{
|
||||||
|
lastStartX = position;
|
||||||
|
lastStartTime = startTime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diff == 0)
|
||||||
|
{
|
||||||
|
bool right = RNG.NextBool();
|
||||||
|
|
||||||
|
float rand = Math.Min(20, (float)RNG.NextDouble(0, timeDiff / 4d)) / CatchPlayfield.BASE_WIDTH;
|
||||||
|
|
||||||
|
if (right)
|
||||||
|
{
|
||||||
|
if (position + rand <= 1)
|
||||||
|
position += rand;
|
||||||
|
else
|
||||||
|
position -= rand;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (position - rand >= 0)
|
||||||
|
position -= rand;
|
||||||
|
else
|
||||||
|
position += rand;
|
||||||
|
}
|
||||||
|
|
||||||
|
catchObject.X = position;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.Abs(diff) < timeDiff / 3d)
|
||||||
|
{
|
||||||
|
if (diff > 0)
|
||||||
|
{
|
||||||
|
if (position - diff > 0)
|
||||||
|
position -= diff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (position - diff < 1)
|
||||||
|
position -= diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catchObject.X = position;
|
||||||
|
|
||||||
|
lastStartX = position;
|
||||||
|
lastStartTime = startTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,8 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
|
|
||||||
Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
|
Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum FruitVisualRepresentation
|
public enum FruitVisualRepresentation
|
||||||
|
@ -2,11 +2,10 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using osu.Framework.Testing;
|
|
||||||
|
|
||||||
// We publish our internal attributes to other sub-projects of the framework.
|
// We publish our internal attributes to other sub-projects of the framework.
|
||||||
// Note, that we omit visual tests as they are meant to test the framework
|
// Note, that we omit visual tests as they are meant to test the framework
|
||||||
// behavior "in the wild".
|
// behavior "in the wild".
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Catch.Tests")]
|
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Catch.Tests")]
|
||||||
[assembly: InternalsVisibleTo(DynamicClassCompiler.DYNAMIC_ASSEMBLY_NAME)]
|
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Catch.Tests.Dynamic")]
|
||||||
|
@ -108,6 +108,7 @@ namespace osu.Game.Rulesets.Catch.Replays
|
|||||||
case BananaShower.Banana _:
|
case BananaShower.Banana _:
|
||||||
case TinyDroplet _:
|
case TinyDroplet _:
|
||||||
case Droplet _:
|
case Droplet _:
|
||||||
|
case Fruit _:
|
||||||
moveToNext(nestedObj);
|
moveToNext(nestedObj);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.Replays
|
|||||||
Dashing = dashing;
|
Dashing = dashing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ConvertFrom(LegacyReplayFrame legacyFrame, Beatmap beatmap)
|
public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
Position = legacyFrame.Position.X / CatchPlayfield.BASE_WIDTH;
|
Position = legacyFrame.Position.X / CatchPlayfield.BASE_WIDTH;
|
||||||
Dashing = legacyFrame.ButtonState == ReplayButtonState.Left1;
|
Dashing = legacyFrame.ButtonState == ReplayButtonState.Left1;
|
||||||
|
@ -30,10 +30,10 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
Anchor = Anchor.TopCentre;
|
Anchor = Anchor.TopCentre;
|
||||||
Origin = Anchor.TopCentre;
|
Origin = Anchor.TopCentre;
|
||||||
|
|
||||||
ScaledContent.Anchor = Anchor.BottomLeft;
|
base.Content.Anchor = Anchor.BottomLeft;
|
||||||
ScaledContent.Origin = Anchor.BottomLeft;
|
base.Content.Origin = Anchor.BottomLeft;
|
||||||
|
|
||||||
ScaledContent.AddRange(new Drawable[]
|
base.Content.AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
explodingFruitContainer = new Container
|
explodingFruitContainer = new Container
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Input.Handlers;
|
using osu.Game.Input.Handlers;
|
||||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||||
using osu.Game.Rulesets.Catch.Replays;
|
using osu.Game.Rulesets.Catch.Replays;
|
||||||
@ -20,8 +19,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
{
|
{
|
||||||
public class CatchRulesetContainer : ScrollingRulesetContainer<CatchPlayfield, CatchHitObject>
|
public class CatchRulesetContainer : ScrollingRulesetContainer<CatchPlayfield, CatchHitObject>
|
||||||
{
|
{
|
||||||
public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||||
: base(ruleset, beatmap, isForCurrentRuleset)
|
: base(ruleset, beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,10 +28,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
||||||
|
|
||||||
protected override BeatmapProcessor<CatchHitObject> CreateBeatmapProcessor() => new CatchBeatmapProcessor();
|
|
||||||
|
|
||||||
protected override BeatmapConverter<CatchHitObject> CreateBeatmapConverter() => new CatchBeatmapConverter();
|
|
||||||
|
|
||||||
protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, GetVisualRepresentation);
|
protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, GetVisualRepresentation);
|
||||||
|
|
||||||
public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
|
public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "VisualTests (Debug, net461)",
|
"name": "VisualTests (Debug, net471)",
|
||||||
"windows": {
|
"windows": {
|
||||||
"type": "clr"
|
"type": "clr"
|
||||||
},
|
},
|
||||||
"type": "mono",
|
"type": "mono",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Mania.Tests.exe",
|
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Mania.Tests.exe",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Debug, msbuild)",
|
"preLaunchTask": "Build (Debug, msbuild)",
|
||||||
"runtimeExecutable": null,
|
"runtimeExecutable": null,
|
||||||
@ -16,13 +16,13 @@
|
|||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "VisualTests (Release, net461)",
|
"name": "VisualTests (Release, net471)",
|
||||||
"windows": {
|
"windows": {
|
||||||
"type": "clr"
|
"type": "clr"
|
||||||
},
|
},
|
||||||
"type": "mono",
|
"type": "mono",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Mania.Tests.exe",
|
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Mania.Tests.exe",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Release, msbuild)",
|
"preLaunchTask": "Build (Release, msbuild)",
|
||||||
"runtimeExecutable": null,
|
"runtimeExecutable": null,
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"command": "msbuild",
|
"command": "msbuild",
|
||||||
"args": [
|
"args": [
|
||||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||||
"/p:TargetFramework=net461",
|
"/p:TargetFramework=net471",
|
||||||
"/p:GenerateFullPaths=true",
|
"/p:GenerateFullPaths=true",
|
||||||
"/m",
|
"/m",
|
||||||
"/verbosity:m"
|
"/verbosity:m"
|
||||||
@ -24,7 +24,7 @@
|
|||||||
"args": [
|
"args": [
|
||||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||||
"/p:Configuration=Release",
|
"/p:Configuration=Release",
|
||||||
"/p:TargetFramework=net461",
|
"/p:TargetFramework=net471",
|
||||||
"/p:GenerateFullPaths=true",
|
"/p:GenerateFullPaths=true",
|
||||||
"/m",
|
"/m",
|
||||||
"/verbosity:m"
|
"/verbosity:m"
|
||||||
@ -66,7 +66,7 @@
|
|||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Restore (net461)",
|
"label": "Restore (net471)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "nuget",
|
"command": "nuget",
|
||||||
"args": [
|
"args": [
|
||||||
|
@ -5,8 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
@ -14,17 +12,14 @@ using osu.Game.Tests.Beatmaps;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Tests
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
{
|
{
|
||||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
internal class ManiaBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
||||||
|
|
||||||
private bool isForCurrentRuleset;
|
|
||||||
|
|
||||||
[NonParallelizable]
|
[NonParallelizable]
|
||||||
[TestCase("basic", false)]
|
[TestCase("basic")]
|
||||||
public void Test(string name, bool isForCurrentRuleset)
|
public new void Test(string name)
|
||||||
{
|
{
|
||||||
this.isForCurrentRuleset = isForCurrentRuleset;
|
|
||||||
base.Test(name);
|
base.Test(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,10 +33,10 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IBeatmapConverter CreateConverter(Beatmap beatmap) => new ManiaBeatmapConverter(isForCurrentRuleset, beatmap);
|
protected override Ruleset CreateRuleset() => new ManiaRuleset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ConvertValue : IEquatable<ConvertValue>
|
internal struct ConvertValue : IEquatable<ConvertValue>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A sane value to account for osu!stable using ints everwhere.
|
/// A sane value to account for osu!stable using ints everwhere.
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
@ -17,6 +19,14 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
{
|
{
|
||||||
public TestCaseManiaHitObjects()
|
public TestCaseManiaHitObjects()
|
||||||
{
|
{
|
||||||
|
Note note1 = new Note();
|
||||||
|
Note note2 = new Note();
|
||||||
|
HoldNote holdNote = new HoldNote { StartTime = 1000 };
|
||||||
|
|
||||||
|
note1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
note2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
holdNote.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
Add(new FillFlowContainer
|
Add(new FillFlowContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
@ -43,14 +53,14 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
RelativeChildSize = new Vector2(1, 10000),
|
RelativeChildSize = new Vector2(1, 10000),
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new DrawableNote(new Note(), ManiaAction.Key1)
|
new DrawableNote(note1, ManiaAction.Key1)
|
||||||
{
|
{
|
||||||
Y = 5000,
|
Y = 5000,
|
||||||
LifetimeStart = double.MinValue,
|
LifetimeStart = double.MinValue,
|
||||||
LifetimeEnd = double.MaxValue,
|
LifetimeEnd = double.MaxValue,
|
||||||
AccentColour = Color4.Red
|
AccentColour = Color4.Red
|
||||||
},
|
},
|
||||||
new DrawableNote(new Note(), ManiaAction.Key1)
|
new DrawableNote(note2, ManiaAction.Key1)
|
||||||
{
|
{
|
||||||
Y = 6000,
|
Y = 6000,
|
||||||
LifetimeStart = double.MinValue,
|
LifetimeStart = double.MinValue,
|
||||||
@ -77,13 +87,13 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
RelativeChildSize = new Vector2(1, 10000),
|
RelativeChildSize = new Vector2(1, 10000),
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new DrawableHoldNote(new HoldNote { Duration = 1000 } , ManiaAction.Key1)
|
new DrawableHoldNote(holdNote, ManiaAction.Key1)
|
||||||
{
|
{
|
||||||
Y = 5000,
|
Y = 5000,
|
||||||
Height = 1000,
|
Height = 1000,
|
||||||
LifetimeStart = double.MinValue,
|
LifetimeStart = double.MinValue,
|
||||||
LifetimeEnd = double.MaxValue,
|
LifetimeEnd = double.MaxValue,
|
||||||
AccentColour = Color4.Red
|
AccentColour = Color4.Red,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@ using NUnit.Framework;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Configuration;
|
using osu.Game.Rulesets.Mania.Configuration;
|
||||||
@ -83,13 +85,16 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
|
|
||||||
int col = rng.Next(0, 4);
|
int col = rng.Next(0, 4);
|
||||||
|
|
||||||
var note = new DrawableNote(new Note { Column = col }, ManiaAction.Key1)
|
var note = new Note { Column = col };
|
||||||
|
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
|
var drawableNote = new DrawableNote(note, ManiaAction.Key1)
|
||||||
{
|
{
|
||||||
AccentColour = playfield.Columns.ElementAt(col).AccentColour
|
AccentColour = playfield.Columns.ElementAt(col).AccentColour
|
||||||
};
|
};
|
||||||
|
|
||||||
playfield.OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
|
playfield.OnJudgement(drawableNote, new ManiaJudgement { Result = HitResult.Perfect });
|
||||||
playfield.Columns[col].OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
|
playfield.Columns[col].OnJudgement(drawableNote, new ManiaJudgement { Result = HitResult.Perfect });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,32 +167,24 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
|
|
||||||
for (double t = start_time; t <= start_time + duration; t += 100)
|
for (double t = start_time; t <= start_time + duration; t += 100)
|
||||||
{
|
{
|
||||||
playfield.Add(new DrawableNote(new Note
|
var note1 = new Note { StartTime = t, Column = 0 };
|
||||||
{
|
var note2 = new Note { StartTime = t, Column = 3 };
|
||||||
StartTime = t,
|
|
||||||
Column = 0
|
|
||||||
}, ManiaAction.Key1));
|
|
||||||
|
|
||||||
playfield.Add(new DrawableNote(new Note
|
note1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
{
|
note2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
StartTime = t,
|
|
||||||
Column = 3
|
playfield.Add(new DrawableNote(note1, ManiaAction.Key1));
|
||||||
}, ManiaAction.Key4));
|
playfield.Add(new DrawableNote(note2, ManiaAction.Key4));
|
||||||
}
|
}
|
||||||
|
|
||||||
playfield.Add(new DrawableHoldNote(new HoldNote
|
var holdNote1 = new HoldNote { StartTime = start_time, Duration = duration, Column = 1 };
|
||||||
{
|
var holdNote2 = new HoldNote { StartTime = start_time, Duration = duration, Column = 2 };
|
||||||
StartTime = start_time,
|
|
||||||
Duration = duration,
|
|
||||||
Column = 1
|
|
||||||
}, ManiaAction.Key2));
|
|
||||||
|
|
||||||
playfield.Add(new DrawableHoldNote(new HoldNote
|
holdNote1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
{
|
holdNote2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
StartTime = start_time,
|
|
||||||
Duration = duration,
|
playfield.Add(new DrawableHoldNote(holdNote1, ManiaAction.Key2));
|
||||||
Column = 2
|
playfield.Add(new DrawableHoldNote(holdNote2, ManiaAction.Key3));
|
||||||
}, ManiaAction.Key3));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Import Project="..\osu.TestProject.props" />
|
<Import Project="..\osu.TestProject.props" />
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
<TargetFrameworks>netcoreapp2.0;net471</TargetFrameworks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="Project References">
|
<ItemGroup Label="Project References">
|
||||||
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
|
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
|
||||||
@ -29,5 +30,27 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
{
|
{
|
||||||
Stages.Add(defaultStage);
|
Stages.Add(defaultStage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<BeatmapStatistic> GetStatistics()
|
||||||
|
{
|
||||||
|
int notes = HitObjects.Count(s => s is Note);
|
||||||
|
int holdnotes = HitObjects.Count(s => s is HoldNote);
|
||||||
|
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
new BeatmapStatistic
|
||||||
|
{
|
||||||
|
Name = @"Note Count",
|
||||||
|
Content = notes.ToString(),
|
||||||
|
Icon = FontAwesome.fa_circle_o
|
||||||
|
},
|
||||||
|
new BeatmapStatistic
|
||||||
|
{
|
||||||
|
Name = @"Hold Note Count",
|
||||||
|
Content = holdnotes.ToString(),
|
||||||
|
Icon = FontAwesome.fa_circle
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,18 +33,19 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
|
|
||||||
private ManiaBeatmap beatmap;
|
private ManiaBeatmap beatmap;
|
||||||
|
|
||||||
public ManiaBeatmapConverter(bool isForCurrentRuleset, Beatmap original)
|
public ManiaBeatmapConverter(IBeatmap beatmap)
|
||||||
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
IsForCurrentRuleset = isForCurrentRuleset;
|
IsForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(new ManiaRuleset().RulesetInfo);
|
||||||
|
|
||||||
var roundedCircleSize = Math.Round(original.BeatmapInfo.BaseDifficulty.CircleSize);
|
var roundedCircleSize = Math.Round(beatmap.BeatmapInfo.BaseDifficulty.CircleSize);
|
||||||
var roundedOverallDifficulty = Math.Round(original.BeatmapInfo.BaseDifficulty.OverallDifficulty);
|
var roundedOverallDifficulty = Math.Round(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
|
||||||
|
|
||||||
if (isForCurrentRuleset)
|
if (IsForCurrentRuleset)
|
||||||
TargetColumns = (int)Math.Max(1, roundedCircleSize);
|
TargetColumns = (int)Math.Max(1, roundedCircleSize);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float percentSliderOrSpinner = (float)original.HitObjects.Count(h => h is IHasEndTime) / original.HitObjects.Count;
|
float percentSliderOrSpinner = (float)beatmap.HitObjects.Count(h => h is IHasEndTime) / beatmap.HitObjects.Count();
|
||||||
if (percentSliderOrSpinner < 0.2)
|
if (percentSliderOrSpinner < 0.2)
|
||||||
TargetColumns = 7;
|
TargetColumns = 7;
|
||||||
else if (percentSliderOrSpinner < 0.3 || roundedCircleSize >= 5)
|
else if (percentSliderOrSpinner < 0.3 || roundedCircleSize >= 5)
|
||||||
@ -56,7 +57,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Beatmap<ManiaHitObject> ConvertBeatmap(Beatmap original)
|
protected override Beatmap<ManiaHitObject> ConvertBeatmap(IBeatmap original)
|
||||||
{
|
{
|
||||||
BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty;
|
BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty;
|
||||||
|
|
||||||
@ -68,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
|
|
||||||
protected override Beatmap<ManiaHitObject> CreateBeatmap() => beatmap = new ManiaBeatmap(new StageDefinition { Columns = TargetColumns });
|
protected override Beatmap<ManiaHitObject> CreateBeatmap() => beatmap = new ManiaBeatmap(new StageDefinition { Columns = TargetColumns });
|
||||||
|
|
||||||
protected override IEnumerable<ManiaHitObject> ConvertHitObject(HitObject original, Beatmap beatmap)
|
protected override IEnumerable<ManiaHitObject> ConvertHitObject(HitObject original, IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
var maniaOriginal = original as ManiaHitObject;
|
var maniaOriginal = original as ManiaHitObject;
|
||||||
if (maniaOriginal != null)
|
if (maniaOriginal != null)
|
||||||
@ -112,7 +113,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
/// <param name="original">The original hit object.</param>
|
/// <param name="original">The original hit object.</param>
|
||||||
/// <param name="originalBeatmap">The original beatmap. This is used to look-up any values dependent on a fully-loaded beatmap.</param>
|
/// <param name="originalBeatmap">The original beatmap. This is used to look-up any values dependent on a fully-loaded beatmap.</param>
|
||||||
/// <returns>The hit objects generated.</returns>
|
/// <returns>The hit objects generated.</returns>
|
||||||
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original, Beatmap originalBeatmap)
|
private IEnumerable<ManiaHitObject> generateSpecific(HitObject original, IBeatmap originalBeatmap)
|
||||||
{
|
{
|
||||||
var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern, originalBeatmap);
|
var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern, originalBeatmap);
|
||||||
|
|
||||||
@ -128,7 +129,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
/// <param name="original">The original hit object.</param>
|
/// <param name="original">The original hit object.</param>
|
||||||
/// <param name="originalBeatmap">The original beatmap. This is used to look-up any values dependent on a fully-loaded beatmap.</param>
|
/// <param name="originalBeatmap">The original beatmap. This is used to look-up any values dependent on a fully-loaded beatmap.</param>
|
||||||
/// <returns>The hit objects generated.</returns>
|
/// <returns>The hit objects generated.</returns>
|
||||||
private IEnumerable<ManiaHitObject> generateConverted(HitObject original, Beatmap originalBeatmap)
|
private IEnumerable<ManiaHitObject> generateConverted(HitObject original, IBeatmap originalBeatmap)
|
||||||
{
|
{
|
||||||
var endTimeData = original as IHasEndTime;
|
var endTimeData = original as IHasEndTime;
|
||||||
var distanceData = original as IHasDistance;
|
var distanceData = original as IHasDistance;
|
||||||
@ -165,7 +166,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator
|
private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator
|
||||||
{
|
{
|
||||||
public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, Beatmap originalBeatmap)
|
public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap)
|
||||||
: base(random, hitObject, beatmap, previousPattern, originalBeatmap)
|
: base(random, hitObject, beatmap, previousPattern, originalBeatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
private PatternType convertType;
|
private PatternType convertType;
|
||||||
|
|
||||||
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, Beatmap originalBeatmap)
|
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap)
|
||||||
: base(random, hitObject, beatmap, previousPattern, originalBeatmap)
|
: base(random, hitObject, beatmap, previousPattern, originalBeatmap)
|
||||||
{
|
{
|
||||||
convertType = PatternType.None;
|
convertType = PatternType.None;
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
{
|
{
|
||||||
private readonly double endTime;
|
private readonly double endTime;
|
||||||
|
|
||||||
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Beatmap originalBeatmap)
|
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, IBeatmap originalBeatmap)
|
||||||
: base(random, hitObject, beatmap, new Pattern(), originalBeatmap)
|
: base(random, hitObject, beatmap, new Pattern(), originalBeatmap)
|
||||||
{
|
{
|
||||||
var endtimeData = HitObject as IHasEndTime;
|
var endtimeData = HitObject as IHasEndTime;
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
private readonly PatternType convertType;
|
private readonly PatternType convertType;
|
||||||
|
|
||||||
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair, Beatmap originalBeatmap)
|
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair, IBeatmap originalBeatmap)
|
||||||
: base(random, hitObject, beatmap, previousPattern, originalBeatmap)
|
: base(random, hitObject, beatmap, previousPattern, originalBeatmap)
|
||||||
{
|
{
|
||||||
if (previousTime > hitObject.StartTime) throw new ArgumentOutOfRangeException(nameof(previousTime));
|
if (previousTime > hitObject.StartTime) throw new ArgumentOutOfRangeException(nameof(previousTime));
|
||||||
|
@ -28,9 +28,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The beatmap which <see cref="HitObject"/> is being converted from.
|
/// The beatmap which <see cref="HitObject"/> is being converted from.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly Beatmap OriginalBeatmap;
|
protected readonly IBeatmap OriginalBeatmap;
|
||||||
|
|
||||||
protected PatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, Beatmap originalBeatmap)
|
protected PatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap)
|
||||||
: base(hitObject, beatmap, previousPattern)
|
: base(hitObject, beatmap, previousPattern)
|
||||||
{
|
{
|
||||||
if (random == null) throw new ArgumentNullException(nameof(random));
|
if (random == null) throw new ArgumentNullException(nameof(random));
|
||||||
@ -113,7 +113,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
drainTime /= 1000;
|
drainTime /= 1000;
|
||||||
|
|
||||||
BeatmapDifficulty difficulty = OriginalBeatmap.BeatmapInfo.BaseDifficulty;
|
BeatmapDifficulty difficulty = OriginalBeatmap.BeatmapInfo.BaseDifficulty;
|
||||||
conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + OriginalBeatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15;
|
conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + OriginalBeatmap.HitObjects.Count() / drainTime * 9f) / 38f * 5f / 1.15;
|
||||||
conversionDifficulty = Math.Min(conversionDifficulty.Value, 12);
|
conversionDifficulty = Math.Min(conversionDifficulty.Value, 12);
|
||||||
|
|
||||||
return conversionDifficulty.Value;
|
return conversionDifficulty.Value;
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania
|
namespace osu.Game.Rulesets.Mania.Difficulty
|
||||||
{
|
{
|
||||||
internal class ManiaDifficultyCalculator : DifficultyCalculator<ManiaHitObject>
|
internal class ManiaDifficultyCalculator : DifficultyCalculator
|
||||||
{
|
{
|
||||||
private const double star_scaling_factor = 0.018;
|
private const double star_scaling_factor = 0.018;
|
||||||
|
|
||||||
@ -31,12 +33,12 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly List<ManiaHitObjectDifficulty> difficultyHitObjects = new List<ManiaHitObjectDifficulty>();
|
private readonly List<ManiaHitObjectDifficulty> difficultyHitObjects = new List<ManiaHitObjectDifficulty>();
|
||||||
|
|
||||||
public ManiaDifficultyCalculator(Beatmap beatmap)
|
public ManiaDifficultyCalculator(IBeatmap beatmap)
|
||||||
: base(beatmap)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public ManiaDifficultyCalculator(Beatmap beatmap, Mod[] mods)
|
public ManiaDifficultyCalculator(IBeatmap beatmap, Mod[] mods)
|
||||||
: base(beatmap, mods)
|
: base(beatmap, mods)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -48,18 +50,17 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
int columnCount = (Beatmap as ManiaBeatmap)?.TotalColumns ?? 7;
|
int columnCount = (Beatmap as ManiaBeatmap)?.TotalColumns ?? 7;
|
||||||
|
|
||||||
foreach (var hitObject in Beatmap.HitObjects)
|
|
||||||
difficultyHitObjects.Add(new ManiaHitObjectDifficulty(hitObject, columnCount));
|
|
||||||
|
|
||||||
// Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure.
|
// Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure.
|
||||||
difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime));
|
// Note: Stable sort is done so that the ordering of hitobjects with equal start times doesn't change
|
||||||
|
difficultyHitObjects.AddRange(Beatmap.HitObjects.Select(h => new ManiaHitObjectDifficulty((ManiaHitObject)h, columnCount)).OrderBy(h => h.BaseHitObject.StartTime));
|
||||||
|
|
||||||
if (!calculateStrainValues())
|
if (!calculateStrainValues())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
double starRating = calculateDifficulty() * star_scaling_factor;
|
double starRating = calculateDifficulty() * star_scaling_factor;
|
||||||
|
|
||||||
categoryDifficulty?.Add("Strain", starRating);
|
if (categoryDifficulty != null)
|
||||||
|
categoryDifficulty["Strain"] = starRating;
|
||||||
|
|
||||||
return starRating;
|
return starRating;
|
||||||
}
|
}
|
||||||
@ -140,7 +141,5 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
return difficulty;
|
return difficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter(Beatmap beatmap) => new ManiaBeatmapConverter(true, beatmap);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
127
osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs
Normal file
127
osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Difficulty
|
||||||
|
{
|
||||||
|
public class ManiaPerformanceCalculator : PerformanceCalculator
|
||||||
|
{
|
||||||
|
private Mod[] mods;
|
||||||
|
|
||||||
|
// Score after being scaled by non-difficulty-increasing mods
|
||||||
|
private double scaledScore;
|
||||||
|
|
||||||
|
private int countPerfect;
|
||||||
|
private int countGreat;
|
||||||
|
private int countGood;
|
||||||
|
private int countOk;
|
||||||
|
private int countMeh;
|
||||||
|
private int countMiss;
|
||||||
|
|
||||||
|
public ManiaPerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score)
|
||||||
|
: base(ruleset, beatmap, score)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
|
||||||
|
{
|
||||||
|
mods = Score.Mods;
|
||||||
|
scaledScore = Score.TotalScore;
|
||||||
|
countPerfect = Convert.ToInt32(Score.Statistics[HitResult.Perfect]);
|
||||||
|
countGreat = Convert.ToInt32(Score.Statistics[HitResult.Great]);
|
||||||
|
countGood = Convert.ToInt32(Score.Statistics[HitResult.Good]);
|
||||||
|
countOk = Convert.ToInt32(Score.Statistics[HitResult.Ok]);
|
||||||
|
countMeh = Convert.ToInt32(Score.Statistics[HitResult.Meh]);
|
||||||
|
countMiss = Convert.ToInt32(Score.Statistics[HitResult.Miss]);
|
||||||
|
|
||||||
|
if (mods.Any(m => !m.Ranked))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
IEnumerable<Mod> scoreIncreaseMods = Ruleset.GetModsFor(ModType.DifficultyIncrease);
|
||||||
|
|
||||||
|
double scoreMultiplier = 1.0;
|
||||||
|
foreach (var m in mods.Where(m => !scoreIncreaseMods.Contains(m)))
|
||||||
|
scoreMultiplier *= m.ScoreMultiplier;
|
||||||
|
|
||||||
|
// Scale score up, so it's comparable to other keymods
|
||||||
|
scaledScore *= 1.0 / scoreMultiplier;
|
||||||
|
|
||||||
|
// Arbitrary initial value for scaling pp in order to standardize distributions across game modes.
|
||||||
|
// The specific number has no intrinsic meaning and can be adjusted as needed.
|
||||||
|
double multiplier = 0.8;
|
||||||
|
|
||||||
|
if (mods.Any(m => m is ModNoFail))
|
||||||
|
multiplier *= 0.9;
|
||||||
|
if (mods.Any(m => m is ModEasy))
|
||||||
|
multiplier *= 0.5;
|
||||||
|
|
||||||
|
double strainValue = computeStrainValue();
|
||||||
|
double accValue = computeAccuracyValue(strainValue);
|
||||||
|
double totalValue =
|
||||||
|
Math.Pow(
|
||||||
|
Math.Pow(strainValue, 1.1) +
|
||||||
|
Math.Pow(accValue, 1.1), 1.0 / 1.1
|
||||||
|
) * multiplier;
|
||||||
|
|
||||||
|
if (categoryDifficulty != null)
|
||||||
|
{
|
||||||
|
categoryDifficulty["Strain"] = strainValue;
|
||||||
|
categoryDifficulty["Accuracy"] = accValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeStrainValue()
|
||||||
|
{
|
||||||
|
// Obtain strain difficulty
|
||||||
|
double strainValue = Math.Pow(5 * Math.Max(1, Attributes["Strain"] / 0.2) - 4.0, 2.2) / 135.0;
|
||||||
|
|
||||||
|
// Longer maps are worth more
|
||||||
|
strainValue *= 1.0 + 0.1 * Math.Min(1.0, totalHits / 1500.0);
|
||||||
|
|
||||||
|
if (scaledScore <= 500000)
|
||||||
|
strainValue = 0;
|
||||||
|
else if (scaledScore <= 600000)
|
||||||
|
strainValue *= (scaledScore - 500000) / 100000 * 0.3;
|
||||||
|
else if (scaledScore <= 700000)
|
||||||
|
strainValue *= 0.3 + (scaledScore - 600000) / 100000 * 0.25;
|
||||||
|
else if (scaledScore <= 800000)
|
||||||
|
strainValue *= 0.55 + (scaledScore - 700000) / 100000 * 0.20;
|
||||||
|
else if (scaledScore <= 900000)
|
||||||
|
strainValue *= 0.75 + (scaledScore - 800000) / 100000 * 0.15;
|
||||||
|
else
|
||||||
|
strainValue *= 0.90 + (scaledScore - 900000) / 100000 * 0.1;
|
||||||
|
|
||||||
|
return strainValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeAccuracyValue(double strainValue)
|
||||||
|
{
|
||||||
|
// Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future
|
||||||
|
double hitWindowGreat = (int)(Beatmap.HitObjects.First().HitWindows.Great / 2) / TimeRate;
|
||||||
|
if (hitWindowGreat <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Lots of arbitrary values from testing.
|
||||||
|
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
|
||||||
|
double accuracyValue = Math.Max(0.0, 0.2 - (hitWindowGreat - 34) * 0.006667)
|
||||||
|
* strainValue
|
||||||
|
* Math.Pow(Math.Max(0.0, scaledScore - 960000) / 40000, 1.1);
|
||||||
|
|
||||||
|
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer
|
||||||
|
// accuracyValue *= Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
|
||||||
|
|
||||||
|
return accuracyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double totalHits => countPerfect + countOk + countGreat + countGood + countMeh + countMiss;
|
||||||
|
}
|
||||||
|
}
|
13
osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs
Normal file
13
osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Judgements
|
||||||
|
{
|
||||||
|
public class HoldNoteJudgement : ManiaJudgement
|
||||||
|
{
|
||||||
|
public override bool AffectsCombo => false;
|
||||||
|
protected override int NumericResultFor(HitResult result) => 0;
|
||||||
|
}
|
||||||
|
}
|
@ -14,12 +14,87 @@ using osu.Framework.Input.Bindings;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Replays;
|
using osu.Game.Rulesets.Mania.Replays;
|
||||||
using osu.Game.Rulesets.Replays.Types;
|
using osu.Game.Rulesets.Replays.Types;
|
||||||
|
using osu.Game.Beatmaps.Legacy;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania
|
namespace osu.Game.Rulesets.Mania
|
||||||
{
|
{
|
||||||
public class ManiaRuleset : Ruleset
|
public class ManiaRuleset : Ruleset
|
||||||
{
|
{
|
||||||
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new ManiaRulesetContainer(this, beatmap, isForCurrentRuleset);
|
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap) => new ManiaRulesetContainer(this, beatmap);
|
||||||
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap);
|
||||||
|
public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new ManiaPerformanceCalculator(this, beatmap, score);
|
||||||
|
|
||||||
|
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
||||||
|
{
|
||||||
|
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||||
|
yield return new ManiaModNightcore();
|
||||||
|
else if (mods.HasFlag(LegacyMods.DoubleTime))
|
||||||
|
yield return new ManiaModDoubleTime();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Autoplay))
|
||||||
|
yield return new ManiaModAutoplay();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Easy))
|
||||||
|
yield return new ManiaModEasy();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.FadeIn))
|
||||||
|
yield return new ManiaModFadeIn();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Flashlight))
|
||||||
|
yield return new ManiaModFlashlight();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.HalfTime))
|
||||||
|
yield return new ManiaModHalfTime();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.HardRock))
|
||||||
|
yield return new ManiaModHardRock();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Hidden))
|
||||||
|
yield return new ManiaModHidden();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Key1))
|
||||||
|
yield return new ManiaModKey1();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Key2))
|
||||||
|
yield return new ManiaModKey2();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Key3))
|
||||||
|
yield return new ManiaModKey3();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Key4))
|
||||||
|
yield return new ManiaModKey4();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Key5))
|
||||||
|
yield return new ManiaModKey5();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Key6))
|
||||||
|
yield return new ManiaModKey6();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Key7))
|
||||||
|
yield return new ManiaModKey7();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Key8))
|
||||||
|
yield return new ManiaModKey8();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Key9))
|
||||||
|
yield return new ManiaModKey9();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.NoFail))
|
||||||
|
yield return new ManiaModNoFail();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Perfect))
|
||||||
|
yield return new ManiaModPerfect();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Random))
|
||||||
|
yield return new ManiaModRandom();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.SuddenDeath))
|
||||||
|
yield return new ManiaModSuddenDeath();
|
||||||
|
}
|
||||||
|
|
||||||
public override IEnumerable<Mod> GetModsFor(ModType type)
|
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||||
{
|
{
|
||||||
@ -113,7 +188,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o };
|
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o };
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap, mods);
|
public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap, mods);
|
||||||
|
|
||||||
public override int? LegacyID => 3;
|
public override int? LegacyID => 3;
|
||||||
|
|
||||||
|
@ -3,19 +3,18 @@
|
|||||||
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Mods
|
namespace osu.Game.Rulesets.Mania.Mods
|
||||||
{
|
{
|
||||||
public abstract class ManiaKeyMod : Mod, IApplicableToBeatmapConverter<ManiaHitObject>
|
public abstract class ManiaKeyMod : Mod, IApplicableToBeatmapConverter
|
||||||
{
|
{
|
||||||
public override string ShortenedName => Name;
|
public override string ShortenedName => Name;
|
||||||
public abstract int KeyCount { get; }
|
public abstract int KeyCount { get; }
|
||||||
public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier
|
public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier
|
||||||
public override bool Ranked => true;
|
public override bool Ranked => true;
|
||||||
|
|
||||||
public void ApplyToBeatmapConverter(BeatmapConverter<ManiaHitObject> beatmapConverter)
|
public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter)
|
||||||
{
|
{
|
||||||
var mbc = (ManiaBeatmapConverter)beatmapConverter;
|
var mbc = (ManiaBeatmapConverter)beatmapConverter;
|
||||||
|
|
||||||
|
@ -11,19 +11,23 @@ using osu.Game.Rulesets.UI;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Mods
|
namespace osu.Game.Rulesets.Mania.Mods
|
||||||
{
|
{
|
||||||
public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter<ManiaHitObject>, IApplicableToRulesetContainer<ManiaHitObject>
|
public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter, IApplicableToRulesetContainer<ManiaHitObject>
|
||||||
{
|
{
|
||||||
public override string Name => "Dual Stages";
|
public override string Name => "Dual Stages";
|
||||||
public override string ShortenedName => "DS";
|
public override string ShortenedName => "DS";
|
||||||
public override string Description => @"Double the stages, double the fun!";
|
public override string Description => @"Double the stages, double the fun!";
|
||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
|
|
||||||
public void ApplyToBeatmapConverter(BeatmapConverter<ManiaHitObject> beatmapConverter)
|
private bool isForCurrentRuleset;
|
||||||
|
|
||||||
|
public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter)
|
||||||
{
|
{
|
||||||
var mbc = (ManiaBeatmapConverter)beatmapConverter;
|
var mbc = (ManiaBeatmapConverter)beatmapConverter;
|
||||||
|
|
||||||
|
isForCurrentRuleset = mbc.IsForCurrentRuleset;
|
||||||
|
|
||||||
// Although this can work, for now let's not allow keymods for mania-specific beatmaps
|
// Although this can work, for now let's not allow keymods for mania-specific beatmaps
|
||||||
if (mbc.IsForCurrentRuleset)
|
if (isForCurrentRuleset)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mbc.TargetColumns *= 2;
|
mbc.TargetColumns *= 2;
|
||||||
@ -34,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
var mrc = (ManiaRulesetContainer)rulesetContainer;
|
var mrc = (ManiaRulesetContainer)rulesetContainer;
|
||||||
|
|
||||||
// Although this can work, for now let's not allow keymods for mania-specific beatmaps
|
// Although this can work, for now let's not allow keymods for mania-specific beatmaps
|
||||||
if (mrc.IsForCurrentRuleset)
|
if (isForCurrentRuleset)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var newDefinitions = new List<StageDefinition>();
|
var newDefinitions = new List<StageDefinition>();
|
||||||
|
@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>, IKeyBindingHandler<ManiaAction>
|
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>, IKeyBindingHandler<ManiaAction>
|
||||||
{
|
{
|
||||||
|
public override bool DisplayJudgement => false;
|
||||||
|
|
||||||
private readonly DrawableNote head;
|
private readonly DrawableNote head;
|
||||||
private readonly DrawableNote tail;
|
private readonly DrawableNote tail;
|
||||||
|
|
||||||
@ -99,6 +101,19 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
|
|
||||||
protected override void UpdateState(ArmedState state)
|
protected override void UpdateState(ArmedState state)
|
||||||
{
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case ArmedState.Hit:
|
||||||
|
// Good enough for now, we just want them to have a lifetime end
|
||||||
|
this.Delay(2000).Expire();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||||
|
{
|
||||||
|
if (tail.AllJudged)
|
||||||
|
AddJudgement(new HoldNoteJudgement { Result = HitResult.Perfect });
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -191,6 +206,13 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private class DrawableTailNote : DrawableNote
|
private class DrawableTailNote : DrawableNote
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Lenience of release hit windows. This is to make cases where the hold note release
|
||||||
|
/// is timed alongside presses of other hit objects less awkward.
|
||||||
|
/// Todo: This shouldn't exist for non-LegacyBeatmapDecoder beatmaps
|
||||||
|
/// </summary>
|
||||||
|
private const double release_window_lenience = 1.5;
|
||||||
|
|
||||||
private readonly DrawableHoldNote holdNote;
|
private readonly DrawableHoldNote holdNote;
|
||||||
|
|
||||||
public DrawableTailNote(DrawableHoldNote holdNote, ManiaAction action)
|
public DrawableTailNote(DrawableHoldNote holdNote, ManiaAction action)
|
||||||
@ -203,6 +225,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
|
// Factor in the release lenience
|
||||||
|
timeOffset /= release_window_lenience;
|
||||||
|
|
||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
{
|
{
|
||||||
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||||
|
@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The tail note of the hold.
|
/// The tail note of the hold.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Note Tail = new TailNote();
|
public readonly Note Tail = new Note();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time between ticks of this hold.
|
/// The time between ticks of this hold.
|
||||||
@ -94,24 +94,5 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The tail of the hold note.
|
|
||||||
/// </summary>
|
|
||||||
private class TailNote : Note
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Lenience of release hit windows. This is to make cases where the hold note release
|
|
||||||
/// is timed alongside presses of other hit objects less awkward.
|
|
||||||
/// </summary>
|
|
||||||
private const double release_window_lenience = 1.5;
|
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
|
||||||
{
|
|
||||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
|
||||||
|
|
||||||
HitWindows *= release_window_lenience;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
|
||||||
using osu.Game.Rulesets.Mania.Objects.Types;
|
using osu.Game.Rulesets.Mania.Objects.Types;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
@ -12,12 +10,6 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
{
|
{
|
||||||
public virtual int Column { get; set; }
|
public virtual int Column { get; set; }
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
protected override HitWindows CreateHitWindows() => new ManiaHitWindows();
|
||||||
{
|
|
||||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
|
||||||
|
|
||||||
HitWindows.AllowsPerfect = true;
|
|
||||||
HitWindows.AllowsOk = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
36
osu.Game.Rulesets.Mania/Objects/ManiaHitWindows.cs
Normal file
36
osu.Game.Rulesets.Mania/Objects/ManiaHitWindows.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Objects
|
||||||
|
{
|
||||||
|
public class ManiaHitWindows : HitWindows
|
||||||
|
{
|
||||||
|
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
|
||||||
|
{
|
||||||
|
{ HitResult.Perfect, (44.8, 38.8, 27.8) },
|
||||||
|
{ HitResult.Great, (128, 98, 68 ) },
|
||||||
|
{ HitResult.Good, (194, 164, 134) },
|
||||||
|
{ HitResult.Ok, (254, 224, 194) },
|
||||||
|
{ HitResult.Meh, (302, 272, 242) },
|
||||||
|
{ HitResult.Miss, (376, 346, 316) },
|
||||||
|
};
|
||||||
|
|
||||||
|
public override void SetDifficulty(double difficulty)
|
||||||
|
{
|
||||||
|
AllowsPerfect = true;
|
||||||
|
AllowsOk = true;
|
||||||
|
|
||||||
|
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Perfect]);
|
||||||
|
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
|
||||||
|
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);
|
||||||
|
Ok = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Ok]);
|
||||||
|
Meh = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Meh]);
|
||||||
|
Miss = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Miss]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,11 +2,10 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using osu.Framework.Testing;
|
|
||||||
|
|
||||||
// We publish our internal attributes to other sub-projects of the framework.
|
// We publish our internal attributes to other sub-projects of the framework.
|
||||||
// Note, that we omit visual tests as they are meant to test the framework
|
// Note, that we omit visual tests as they are meant to test the framework
|
||||||
// behavior "in the wild".
|
// behavior "in the wild".
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Mania.Tests")]
|
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Mania.Tests")]
|
||||||
[assembly: InternalsVisibleTo(DynamicClassCompiler.DYNAMIC_ASSEMBLY_NAME)]
|
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Mania.Tests.Dynamic")]
|
||||||
|
@ -24,10 +24,10 @@ namespace osu.Game.Rulesets.Mania.Replays
|
|||||||
Actions.AddRange(actions);
|
Actions.AddRange(actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ConvertFrom(LegacyReplayFrame legacyFrame, Beatmap beatmap)
|
public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
// We don't need to fully convert, just create the converter
|
// We don't need to fully convert, just create the converter
|
||||||
var converter = new ManiaBeatmapConverter(beatmap.BeatmapInfo.RulesetID == 3, beatmap);
|
var converter = new ManiaBeatmapConverter(beatmap);
|
||||||
|
|
||||||
// NB: Via co-op mod, osu-stable can have two stages with floor(col/2) and ceil(col/2) columns. This will need special handling
|
// NB: Via co-op mod, osu-stable can have two stages with floor(col/2) and ceil(col/2) columns. This will need special handling
|
||||||
// elsewhere in the game if we do choose to support the old co-op mod anyway. For now, assume that there is only one stage.
|
// elsewhere in the game if we do choose to support the old co-op mod anyway. For now, assume that there is only one stage.
|
||||||
|
@ -213,7 +213,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||||
{
|
{
|
||||||
if (!judgement.IsHit)
|
if (!judgement.IsHit || !judgedObject.DisplayJudgement)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
explosionContainer.Add(new HitExplosion(judgedObject));
|
explosionContainer.Add(new HitExplosion(judgedObject));
|
||||||
|
@ -36,8 +36,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
public IEnumerable<BarLine> BarLines;
|
public IEnumerable<BarLine> BarLines;
|
||||||
|
|
||||||
public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||||
: base(ruleset, beatmap, isForCurrentRuleset)
|
: base(ruleset, beatmap)
|
||||||
{
|
{
|
||||||
// Generate the bar lines
|
// Generate the bar lines
|
||||||
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
|
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
|
||||||
@ -85,8 +85,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant);
|
public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant);
|
||||||
|
|
||||||
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter(IsForCurrentRuleset, WorkingBeatmap.Beatmap);
|
|
||||||
|
|
||||||
protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h)
|
protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h)
|
||||||
{
|
{
|
||||||
ManiaAction action = Playfield.Columns.ElementAt(h.Column).Action;
|
ManiaAction action = Playfield.Columns.ElementAt(h.Column).Action;
|
||||||
|
@ -171,6 +171,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||||
{
|
{
|
||||||
|
if (!judgedObject.DisplayJudgement)
|
||||||
|
return;
|
||||||
|
|
||||||
judgements.Clear();
|
judgements.Clear();
|
||||||
judgements.Add(new DrawableManiaJudgement(judgement, judgedObject)
|
judgements.Add(new DrawableManiaJudgement(judgement, judgedObject)
|
||||||
{
|
{
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "VisualTests (Debug, net461)",
|
"name": "VisualTests (Debug, net471)",
|
||||||
"windows": {
|
"windows": {
|
||||||
"type": "clr"
|
"type": "clr"
|
||||||
},
|
},
|
||||||
"type": "mono",
|
"type": "mono",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Osu.Tests.exe",
|
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Osu.Tests.exe",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Debug, msbuild)",
|
"preLaunchTask": "Build (Debug, msbuild)",
|
||||||
"runtimeExecutable": null,
|
"runtimeExecutable": null,
|
||||||
@ -16,13 +16,13 @@
|
|||||||
"console": "internalConsole"
|
"console": "internalConsole"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "VisualTests (Release, net461)",
|
"name": "VisualTests (Release, net471)",
|
||||||
"windows": {
|
"windows": {
|
||||||
"type": "clr"
|
"type": "clr"
|
||||||
},
|
},
|
||||||
"type": "mono",
|
"type": "mono",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Osu.Tests.exe",
|
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Osu.Tests.exe",
|
||||||
"cwd": "${workspaceRoot}",
|
"cwd": "${workspaceRoot}",
|
||||||
"preLaunchTask": "Build (Release, msbuild)",
|
"preLaunchTask": "Build (Release, msbuild)",
|
||||||
"runtimeExecutable": null,
|
"runtimeExecutable": null,
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"command": "msbuild",
|
"command": "msbuild",
|
||||||
"args": [
|
"args": [
|
||||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||||
"/p:TargetFramework=net461",
|
"/p:TargetFramework=net471",
|
||||||
"/p:GenerateFullPaths=true",
|
"/p:GenerateFullPaths=true",
|
||||||
"/m",
|
"/m",
|
||||||
"/verbosity:m"
|
"/verbosity:m"
|
||||||
@ -24,7 +24,7 @@
|
|||||||
"args": [
|
"args": [
|
||||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||||
"/p:Configuration=Release",
|
"/p:Configuration=Release",
|
||||||
"/p:TargetFramework=net461",
|
"/p:TargetFramework=net471",
|
||||||
"/p:GenerateFullPaths=true",
|
"/p:GenerateFullPaths=true",
|
||||||
"/m",
|
"/m",
|
||||||
"/verbosity:m"
|
"/verbosity:m"
|
||||||
@ -66,7 +66,7 @@
|
|||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Restore (net461)",
|
"label": "Restore (net471)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "nuget",
|
"command": "nuget",
|
||||||
"args": [
|
"args": [
|
||||||
|
@ -5,17 +5,15 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Tests.Beatmaps;
|
using osu.Game.Tests.Beatmaps;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
{
|
{
|
||||||
public class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
internal class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||||
|
|
||||||
@ -42,10 +40,10 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IBeatmapConverter CreateConverter(Beatmap beatmap) => new OsuBeatmapConverter();
|
protected override Ruleset CreateRuleset() => new OsuRuleset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ConvertValue : IEquatable<ConvertValue>
|
internal struct ConvertValue : IEquatable<ConvertValue>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A sane value to account for osu!stable using ints everwhere.
|
/// A sane value to account for osu!stable using ints everwhere.
|
||||||
|
@ -93,12 +93,36 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
AddStep("Big Single, Large StackOffset", () => testSimpleBigLargeStackOffset());
|
AddStep("Big Single, Large StackOffset", () => testSimpleBigLargeStackOffset());
|
||||||
AddStep("Big 1 Repeat, Large StackOffset", () => testSimpleBigLargeStackOffset(1));
|
AddStep("Big 1 Repeat, Large StackOffset", () => testSimpleBigLargeStackOffset(1));
|
||||||
|
|
||||||
|
AddStep("Distance Overflow", () => testDistanceOverflow());
|
||||||
|
AddStep("Distance Overflow 1 Repeat", () => testDistanceOverflow(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testSimpleBig(int repeats = 0) => createSlider(2, repeats: repeats);
|
private void testSimpleBig(int repeats = 0) => createSlider(2, repeats: repeats);
|
||||||
|
|
||||||
private void testSimpleBigLargeStackOffset(int repeats = 0) => createSlider(2, repeats: repeats, stackHeight: 10);
|
private void testSimpleBigLargeStackOffset(int repeats = 0) => createSlider(2, repeats: repeats, stackHeight: 10);
|
||||||
|
|
||||||
|
private void testDistanceOverflow(int repeats = 0)
|
||||||
|
{
|
||||||
|
var slider = new Slider
|
||||||
|
{
|
||||||
|
StartTime = Time.Current + 1000,
|
||||||
|
Position = new Vector2(239, 176),
|
||||||
|
ControlPoints = new List<Vector2>
|
||||||
|
{
|
||||||
|
Vector2.Zero,
|
||||||
|
new Vector2(154, 28),
|
||||||
|
new Vector2(52, -34)
|
||||||
|
},
|
||||||
|
Distance = 700,
|
||||||
|
RepeatCount = repeats,
|
||||||
|
RepeatSamples = createEmptySamples(repeats),
|
||||||
|
StackHeight = 10
|
||||||
|
};
|
||||||
|
|
||||||
|
addSlider(slider, 2, 2);
|
||||||
|
}
|
||||||
|
|
||||||
private void testSimpleMedium(int repeats = 0) => createSlider(5, repeats: repeats);
|
private void testSimpleMedium(int repeats = 0) => createSlider(5, repeats: repeats);
|
||||||
|
|
||||||
private void testSimpleSmall(int repeats = 0) => createSlider(7, repeats: repeats);
|
private void testSimpleSmall(int repeats = 0) => createSlider(7, repeats: repeats);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Import Project="..\osu.TestProject.props" />
|
<Import Project="..\osu.TestProject.props" />
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
<TargetFrameworks>netcoreapp2.0;net471</TargetFrameworks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="Project References">
|
<ItemGroup Label="Project References">
|
||||||
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
|
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
|
||||||
|
43
osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmap.cs
Normal file
43
osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmap.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||||
|
{
|
||||||
|
public class OsuBeatmap : Beatmap<OsuHitObject>
|
||||||
|
{
|
||||||
|
public override IEnumerable<BeatmapStatistic> GetStatistics()
|
||||||
|
{
|
||||||
|
int circles = HitObjects.Count(c => c is HitCircle);
|
||||||
|
int sliders = HitObjects.Count(s => s is Slider);
|
||||||
|
int spinners = HitObjects.Count(s => s is Spinner);
|
||||||
|
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
new BeatmapStatistic
|
||||||
|
{
|
||||||
|
Name = @"Circle Count",
|
||||||
|
Content = circles.ToString(),
|
||||||
|
Icon = FontAwesome.fa_circle_o
|
||||||
|
},
|
||||||
|
new BeatmapStatistic
|
||||||
|
{
|
||||||
|
Name = @"Slider Count",
|
||||||
|
Content = sliders.ToString(),
|
||||||
|
Icon = FontAwesome.fa_circle
|
||||||
|
},
|
||||||
|
new BeatmapStatistic
|
||||||
|
{
|
||||||
|
Name = @"Spinner Count",
|
||||||
|
Content = spinners.ToString(),
|
||||||
|
Icon = FontAwesome.fa_circle
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,9 +14,14 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
{
|
{
|
||||||
internal class OsuBeatmapConverter : BeatmapConverter<OsuHitObject>
|
internal class OsuBeatmapConverter : BeatmapConverter<OsuHitObject>
|
||||||
{
|
{
|
||||||
|
public OsuBeatmapConverter(IBeatmap beatmap)
|
||||||
|
: base(beatmap)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasPosition) };
|
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasPosition) };
|
||||||
|
|
||||||
protected override IEnumerable<OsuHitObject> ConvertHitObject(HitObject original, Beatmap beatmap)
|
protected override IEnumerable<OsuHitObject> ConvertHitObject(HitObject original, IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
var curveData = original as IHasCurve;
|
var curveData = original as IHasCurve;
|
||||||
var endTimeData = original as IHasEndTime;
|
var endTimeData = original as IHasEndTime;
|
||||||
@ -45,8 +50,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
StartTime = original.StartTime,
|
StartTime = original.StartTime,
|
||||||
Samples = original.Samples,
|
Samples = original.Samples,
|
||||||
EndTime = endTimeData.EndTime,
|
EndTime = endTimeData.EndTime,
|
||||||
|
Position = positionData?.Position ?? OsuPlayfield.BASE_SIZE / 2
|
||||||
Position = positionData?.Position ?? OsuPlayfield.BASE_SIZE / 2,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -60,5 +64,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override Beatmap<OsuHitObject> CreateBeatmap() => new OsuBeatmap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,17 @@ using osu.Game.Rulesets.Osu.Objects;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Beatmaps
|
namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||||
{
|
{
|
||||||
internal class OsuBeatmapProcessor : BeatmapProcessor<OsuHitObject>
|
internal class OsuBeatmapProcessor : BeatmapProcessor
|
||||||
{
|
{
|
||||||
public override void PostProcess(Beatmap<OsuHitObject> beatmap)
|
public OsuBeatmapProcessor(IBeatmap beatmap)
|
||||||
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
applyStacking(beatmap);
|
}
|
||||||
base.PostProcess(beatmap);
|
|
||||||
|
public override void PostProcess()
|
||||||
|
{
|
||||||
|
applyStacking((Beatmap<OsuHitObject>)Beatmap);
|
||||||
|
base.PostProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyStacking(Beatmap<OsuHitObject> beatmap)
|
private void applyStacking(Beatmap<OsuHitObject> beatmap)
|
||||||
|
@ -4,55 +4,54 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||||
|
using osu.Game.Rulesets.Osu.Difficulty.Skills;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;
|
|
||||||
using osu.Game.Rulesets.Osu.OsuDifficulty.Skills;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty
|
namespace osu.Game.Rulesets.Osu.Difficulty
|
||||||
{
|
{
|
||||||
public class OsuDifficultyCalculator : DifficultyCalculator<OsuHitObject>
|
public class OsuDifficultyCalculator : DifficultyCalculator
|
||||||
{
|
{
|
||||||
private const int section_length = 400;
|
private const int section_length = 400;
|
||||||
private const double difficulty_multiplier = 0.0675;
|
private const double difficulty_multiplier = 0.0675;
|
||||||
|
|
||||||
public OsuDifficultyCalculator(Beatmap beatmap)
|
public OsuDifficultyCalculator(IBeatmap beatmap)
|
||||||
: base(beatmap)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public OsuDifficultyCalculator(Beatmap beatmap, Mod[] mods)
|
public OsuDifficultyCalculator(IBeatmap beatmap, Mod[] mods)
|
||||||
: base(beatmap, mods)
|
: base(beatmap, mods)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PreprocessHitObjects()
|
|
||||||
{
|
|
||||||
new OsuBeatmapProcessor().PostProcess(Beatmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
|
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
|
||||||
{
|
{
|
||||||
OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Beatmap.HitObjects, TimeRate);
|
OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap((List<OsuHitObject>)Beatmap.HitObjects, TimeRate);
|
||||||
Skill[] skills =
|
Skill[] skills =
|
||||||
{
|
{
|
||||||
new Aim(),
|
new Aim(),
|
||||||
new Speed()
|
new Speed()
|
||||||
};
|
};
|
||||||
|
|
||||||
double sectionEnd = section_length / TimeRate;
|
double sectionLength = section_length * TimeRate;
|
||||||
|
|
||||||
|
// The first object doesn't generate a strain, so we begin with an incremented section end
|
||||||
|
double currentSectionEnd = 2 * sectionLength;
|
||||||
|
|
||||||
foreach (OsuDifficultyHitObject h in beatmap)
|
foreach (OsuDifficultyHitObject h in beatmap)
|
||||||
{
|
{
|
||||||
while (h.BaseObject.StartTime > sectionEnd)
|
while (h.BaseObject.StartTime > currentSectionEnd)
|
||||||
{
|
{
|
||||||
foreach (Skill s in skills)
|
foreach (Skill s in skills)
|
||||||
{
|
{
|
||||||
s.SaveCurrentPeak();
|
s.SaveCurrentPeak();
|
||||||
s.StartNewSectionFrom(sectionEnd);
|
s.StartNewSectionFrom(currentSectionEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
sectionEnd += section_length;
|
currentSectionEnd += sectionLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Skill s in skills)
|
foreach (Skill s in skills)
|
||||||
@ -72,7 +71,5 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty
|
|||||||
|
|
||||||
return starRating;
|
return starRating;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override BeatmapConverter<OsuHitObject> CreateBeatmapConverter(Beatmap beatmap) => new OsuBeatmapConverter();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,35 +5,46 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Scoring
|
namespace osu.Game.Rulesets.Osu.Difficulty
|
||||||
{
|
{
|
||||||
public class OsuPerformanceCalculator : PerformanceCalculator<OsuHitObject>
|
public class OsuPerformanceCalculator : PerformanceCalculator
|
||||||
{
|
{
|
||||||
private readonly int countHitCircles;
|
private readonly int countHitCircles;
|
||||||
private readonly int beatmapMaxCombo;
|
private readonly int beatmapMaxCombo;
|
||||||
|
|
||||||
private Mod[] mods;
|
private Mod[] mods;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Approach rate adjusted by mods.
|
||||||
|
/// </summary>
|
||||||
private double realApproachRate;
|
private double realApproachRate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overall difficulty adjusted by mods.
|
||||||
|
/// </summary>
|
||||||
|
private double realOverallDifficulty;
|
||||||
|
|
||||||
private double accuracy;
|
private double accuracy;
|
||||||
private int scoreMaxCombo;
|
private int scoreMaxCombo;
|
||||||
private int count300;
|
private int countGreat;
|
||||||
private int count100;
|
private int countGood;
|
||||||
private int count50;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
public OsuPerformanceCalculator(Ruleset ruleset, Beatmap beatmap, Score score)
|
public OsuPerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score)
|
||||||
: base(ruleset, beatmap, score)
|
: base(ruleset, beatmap, score)
|
||||||
{
|
{
|
||||||
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);
|
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);
|
||||||
|
|
||||||
beatmapMaxCombo = Beatmap.HitObjects.Count;
|
beatmapMaxCombo = Beatmap.HitObjects.Count();
|
||||||
beatmapMaxCombo += Beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count) + 1;
|
// Add the ticks + tail of the slider. 1 is subtracted because the "headcircle" would be counted twice (once for the slider itself in the line above)
|
||||||
|
beatmapMaxCombo += Beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double Calculate(Dictionary<string, double> categoryRatings = null)
|
public override double Calculate(Dictionary<string, double> categoryRatings = null)
|
||||||
@ -41,25 +52,21 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
mods = Score.Mods;
|
mods = Score.Mods;
|
||||||
accuracy = Score.Accuracy;
|
accuracy = Score.Accuracy;
|
||||||
scoreMaxCombo = Score.MaxCombo;
|
scoreMaxCombo = Score.MaxCombo;
|
||||||
count300 = Convert.ToInt32(Score.Statistics[HitResult.Great]);
|
countGreat = Convert.ToInt32(Score.Statistics[HitResult.Great]);
|
||||||
count100 = Convert.ToInt32(Score.Statistics[HitResult.Good]);
|
countGood = Convert.ToInt32(Score.Statistics[HitResult.Good]);
|
||||||
count50 = Convert.ToInt32(Score.Statistics[HitResult.Meh]);
|
countMeh = Convert.ToInt32(Score.Statistics[HitResult.Meh]);
|
||||||
countMiss = Convert.ToInt32(Score.Statistics[HitResult.Miss]);
|
countMiss = Convert.ToInt32(Score.Statistics[HitResult.Miss]);
|
||||||
|
|
||||||
// Don't count scores made with supposedly unranked mods
|
// Don't count scores made with supposedly unranked mods
|
||||||
if (mods.Any(m => !m.Ranked))
|
if (mods.Any(m => !m.Ranked))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Todo: In the future we should apply changes to PreEmpt/AR at an OsuHitObject/BaseDifficulty level, but this is done
|
// Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future
|
||||||
// locally for now as doing so would modify animations and other things unexpectedly
|
double hitWindowGreat = (int)(Beatmap.HitObjects.First().HitWindows.Great / 2) / TimeRate;
|
||||||
// DO NOT MODIFY THIS
|
double preEmpt = (int)BeatmapDifficulty.DifficultyRange(Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / TimeRate;
|
||||||
double ar = Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate;
|
|
||||||
if (mods.Any(m => m is OsuModHardRock))
|
|
||||||
ar = Math.Min(10, ar * 1.4);
|
|
||||||
if (mods.Any(m => m is OsuModEasy))
|
|
||||||
ar = Math.Max(0, ar / 2);
|
|
||||||
double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450);
|
|
||||||
realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5;
|
realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5;
|
||||||
|
realOverallDifficulty = (80 - hitWindowGreat) / 6;
|
||||||
|
|
||||||
// Custom multipliers for NoFail and SpunOut.
|
// Custom multipliers for NoFail and SpunOut.
|
||||||
double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things
|
double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things
|
||||||
@ -85,6 +92,9 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
categoryRatings.Add("Aim", aimValue);
|
categoryRatings.Add("Aim", aimValue);
|
||||||
categoryRatings.Add("Speed", speedValue);
|
categoryRatings.Add("Speed", speedValue);
|
||||||
categoryRatings.Add("Accuracy", accuracyValue);
|
categoryRatings.Add("Accuracy", accuracyValue);
|
||||||
|
categoryRatings.Add("OD", realOverallDifficulty);
|
||||||
|
categoryRatings.Add("AR", realApproachRate);
|
||||||
|
categoryRatings.Add("Max Combo", beatmapMaxCombo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalValue;
|
return totalValue;
|
||||||
@ -121,8 +131,9 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
|
|
||||||
aimValue *= approachRateFactor;
|
aimValue *= approachRateFactor;
|
||||||
|
|
||||||
|
// We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR.
|
||||||
if (mods.Any(h => h is OsuModHidden))
|
if (mods.Any(h => h is OsuModHidden))
|
||||||
aimValue *= 1.18f;
|
aimValue *= 1.02 + (11.0f - realApproachRate) / 50.0; // Gives a 1.04 bonus for AR10, a 1.06 bonus for AR9, a 1.02 bonus for AR11.
|
||||||
|
|
||||||
if (mods.Any(h => h is OsuModFlashlight))
|
if (mods.Any(h => h is OsuModFlashlight))
|
||||||
{
|
{
|
||||||
@ -133,7 +144,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
// Scale the aim value with accuracy _slightly_
|
// Scale the aim value with accuracy _slightly_
|
||||||
aimValue *= 0.5f + accuracy / 2.0f;
|
aimValue *= 0.5f + accuracy / 2.0f;
|
||||||
// It is important to also consider accuracy difficulty when doing that
|
// It is important to also consider accuracy difficulty when doing that
|
||||||
aimValue *= 0.98f + Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500;
|
aimValue *= 0.98f + Math.Pow(realOverallDifficulty, 2) / 2500;
|
||||||
|
|
||||||
return aimValue;
|
return aimValue;
|
||||||
}
|
}
|
||||||
@ -153,10 +164,13 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
if (beatmapMaxCombo > 0)
|
if (beatmapMaxCombo > 0)
|
||||||
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f);
|
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f);
|
||||||
|
|
||||||
|
if (mods.Any(m => m is OsuModHidden))
|
||||||
|
speedValue *= 1.18f;
|
||||||
|
|
||||||
// Scale the speed value with accuracy _slightly_
|
// Scale the speed value with accuracy _slightly_
|
||||||
speedValue *= 0.5f + accuracy / 2.0f;
|
speedValue *= 0.5f + accuracy / 2.0f;
|
||||||
// It is important to also consider accuracy difficulty when doing that
|
// It is important to also consider accuracy difficulty when doing that
|
||||||
speedValue *= 0.98f + Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500;
|
speedValue *= 0.98f + Math.Pow(realOverallDifficulty, 2) / 2500;
|
||||||
|
|
||||||
return speedValue;
|
return speedValue;
|
||||||
}
|
}
|
||||||
@ -168,7 +182,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
int amountHitObjectsWithAccuracy = countHitCircles;
|
int amountHitObjectsWithAccuracy = countHitCircles;
|
||||||
|
|
||||||
if (amountHitObjectsWithAccuracy > 0)
|
if (amountHitObjectsWithAccuracy > 0)
|
||||||
betterAccuracyPercentage = ((count300 - (totalHits - amountHitObjectsWithAccuracy)) * 6 + count100 * 2 + count50) / (amountHitObjectsWithAccuracy * 6);
|
betterAccuracyPercentage = ((countGreat - (totalHits - amountHitObjectsWithAccuracy)) * 6 + countGood * 2 + countMeh) / (amountHitObjectsWithAccuracy * 6);
|
||||||
else
|
else
|
||||||
betterAccuracyPercentage = 0;
|
betterAccuracyPercentage = 0;
|
||||||
|
|
||||||
@ -178,7 +192,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
|
|
||||||
// Lots of arbitrary values from testing.
|
// Lots of arbitrary values from testing.
|
||||||
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
|
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
|
||||||
double accuracyValue = Math.Pow(1.52163f, Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83f;
|
double accuracyValue = Math.Pow(1.52163f, realOverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83f;
|
||||||
|
|
||||||
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer
|
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer
|
||||||
accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f));
|
accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f));
|
||||||
@ -191,9 +205,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
return accuracyValue;
|
return accuracyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double totalHits => count300 + count100 + count50 + countMiss;
|
private double totalHits => countGreat + countGood + countMeh + countMiss;
|
||||||
private double totalSuccessfulHits => count300 + count100 + count50;
|
private double totalSuccessfulHits => countGreat + countGood + countMeh;
|
||||||
|
|
||||||
protected override BeatmapConverter<OsuHitObject> CreateBeatmapConverter() => new OsuBeatmapConverter();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An enumerable container wrapping <see cref="OsuHitObject"/> input as <see cref="OsuDifficultyHitObject"/>
|
||||||
|
/// which contains extra data required for difficulty calculation.
|
||||||
|
/// </summary>
|
||||||
|
public class OsuDifficultyBeatmap : IEnumerable<OsuDifficultyHitObject>
|
||||||
|
{
|
||||||
|
private readonly IEnumerator<OsuDifficultyHitObject> difficultyObjects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an enumerator, which preprocesses a list of <see cref="OsuHitObject"/>s recieved as input, wrapping them as
|
||||||
|
/// <see cref="OsuDifficultyHitObject"/> which contains extra data required for difficulty calculation.
|
||||||
|
/// </summary>
|
||||||
|
public OsuDifficultyBeatmap(List<OsuHitObject> objects, double timeRate)
|
||||||
|
{
|
||||||
|
// Sort OsuHitObjects by StartTime - they are not correctly ordered in some cases.
|
||||||
|
// This should probably happen before the objects reach the difficulty calculator.
|
||||||
|
objects.Sort((a, b) => a.StartTime.CompareTo(b.StartTime));
|
||||||
|
difficultyObjects = createDifficultyObjectEnumerator(objects, timeRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an enumerator that enumerates all <see cref="OsuDifficultyHitObject"/>s in the <see cref="OsuDifficultyBeatmap"/>.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerator<OsuDifficultyHitObject> GetEnumerator() => difficultyObjects;
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
|
private IEnumerator<OsuDifficultyHitObject> createDifficultyObjectEnumerator(List<OsuHitObject> objects, double timeRate)
|
||||||
|
{
|
||||||
|
// The first jump is formed by the first two hitobjects of the map.
|
||||||
|
// If the map has less than two OsuHitObjects, the enumerator will not return anything.
|
||||||
|
for (int i = 1; i < objects.Count; i++)
|
||||||
|
yield return new OsuDifficultyHitObject(objects[i], objects[i - 1], timeRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,16 +3,18 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenTK;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A wrapper around <see cref="OsuHitObject"/> extending it with additional data required for difficulty calculation.
|
/// A wrapper around <see cref="OsuHitObject"/> extending it with additional data required for difficulty calculation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OsuDifficultyHitObject
|
public class OsuDifficultyHitObject
|
||||||
{
|
{
|
||||||
|
private const int normalized_radius = 52;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="OsuHitObject"/> this <see cref="OsuDifficultyHitObject"/> refers to.
|
/// The <see cref="OsuHitObject"/> this <see cref="OsuDifficultyHitObject"/> refers to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -28,26 +30,19 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public double DeltaTime { get; private set; }
|
public double DeltaTime { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
private readonly OsuHitObject lastObject;
|
||||||
/// Number of milliseconds until the <see cref="OsuDifficultyHitObject"/> has to be hit.
|
|
||||||
/// </summary>
|
|
||||||
public double TimeUntilHit { get; set; }
|
|
||||||
|
|
||||||
private const int normalized_radius = 52;
|
|
||||||
|
|
||||||
private readonly double timeRate;
|
private readonly double timeRate;
|
||||||
|
|
||||||
private readonly OsuHitObject[] t;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes the object calculating extra data required for difficulty calculation.
|
/// Initializes the object calculating extra data required for difficulty calculation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public OsuDifficultyHitObject(OsuHitObject[] triangle, double timeRate)
|
public OsuDifficultyHitObject(OsuHitObject currentObject, OsuHitObject lastObject, double timeRate)
|
||||||
{
|
{
|
||||||
|
this.lastObject = lastObject;
|
||||||
this.timeRate = timeRate;
|
this.timeRate = timeRate;
|
||||||
|
|
||||||
t = triangle;
|
BaseObject = currentObject;
|
||||||
BaseObject = t[0];
|
|
||||||
setDistances();
|
setDistances();
|
||||||
setTimingValues();
|
setTimingValues();
|
||||||
// Calculate angle here
|
// Calculate angle here
|
||||||
@ -63,10 +58,10 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
|||||||
scalingFactor *= 1 + smallCircleBonus;
|
scalingFactor *= 1 + smallCircleBonus;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 lastCursorPosition = t[1].StackedPosition;
|
Vector2 lastCursorPosition = lastObject.StackedPosition;
|
||||||
float lastTravelDistance = 0;
|
float lastTravelDistance = 0;
|
||||||
|
|
||||||
var lastSlider = t[1] as Slider;
|
var lastSlider = lastObject as Slider;
|
||||||
if (lastSlider != null)
|
if (lastSlider != null)
|
||||||
{
|
{
|
||||||
computeSliderCursorPosition(lastSlider);
|
computeSliderCursorPosition(lastSlider);
|
||||||
@ -80,8 +75,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
|||||||
private void setTimingValues()
|
private void setTimingValues()
|
||||||
{
|
{
|
||||||
// Every timing inverval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure.
|
// Every timing inverval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure.
|
||||||
DeltaTime = Math.Max(40, (t[0].StartTime - t[1].StartTime) / timeRate);
|
DeltaTime = Math.Max(50, (BaseObject.StartTime - lastObject.StartTime) / timeRate);
|
||||||
TimeUntilHit = 450; // BaseObject.PreEmpt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void computeSliderCursorPosition(Slider slider)
|
private void computeSliderCursorPosition(Slider slider)
|
||||||
@ -107,7 +101,8 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var scoringTimes = slider.NestedHitObjects.Select(t => t.StartTime);
|
// Skip the head circle
|
||||||
|
var scoringTimes = slider.NestedHitObjects.Skip(1).Select(t => t.StartTime);
|
||||||
foreach (var time in scoringTimes)
|
foreach (var time in scoringTimes)
|
||||||
computeVertex(time);
|
computeVertex(time);
|
||||||
computeVertex(slider.EndTime);
|
computeVertex(slider.EndTime);
|
@ -2,9 +2,9 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;
|
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Skills
|
namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances.
|
/// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances.
|
@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||||
|
using osu.Game.Rulesets.Osu.Difficulty.Utils;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;
|
|
||||||
using osu.Game.Rulesets.Osu.OsuDifficulty.Utils;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Skills
|
namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to processes strain values of <see cref="OsuDifficultyHitObject"/>s, keep track of strain levels caused by the processed objects
|
/// Used to processes strain values of <see cref="OsuDifficultyHitObject"/>s, keep track of strain levels caused by the processed objects
|
@ -1,9 +1,9 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing;
|
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Skills
|
namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the skill required to press keys with regards to keeping up with the speed at which objects need to be hit.
|
/// Represents the skill required to press keys with regards to keeping up with the speed at which objects need to be hit.
|
@ -5,7 +5,7 @@ using System;
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Utils
|
namespace osu.Game.Rulesets.Osu.Difficulty.Utils
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An indexed stack with Push() only, which disposes items at the bottom after the capacity is full.
|
/// An indexed stack with Push() only, which disposes items at the bottom after the capacity is full.
|
@ -21,6 +21,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays
|
|||||||
Size = hitCircle.Size;
|
Size = hitCircle.Size;
|
||||||
Scale = hitCircle.Scale;
|
Scale = hitCircle.Scale;
|
||||||
|
|
||||||
|
CornerRadius = Size.X / 2;
|
||||||
|
|
||||||
AddInternal(new RingPiece());
|
AddInternal(new RingPiece());
|
||||||
|
|
||||||
hitCircle.HitObject.PositionChanged += _ => Position = hitCircle.Position;
|
hitCircle.HitObject.PositionChanged += _ => Position = hitCircle.Position;
|
||||||
|
@ -38,6 +38,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays
|
|||||||
Scale = slider.HeadCircle.Scale;
|
Scale = slider.HeadCircle.Scale;
|
||||||
|
|
||||||
AddInternal(new RingPiece());
|
AddInternal(new RingPiece());
|
||||||
|
|
||||||
|
Select();
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -52,5 +54,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays
|
|||||||
|
|
||||||
RelativeAnchorPosition = hitObject.RelativeAnchorPosition;
|
RelativeAnchorPosition = hitObject.RelativeAnchorPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Todo: This is temporary, since the slider circle masks don't do anything special yet. In the future they will handle input.
|
||||||
|
public override bool HandleMouseInput => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
@ -59,5 +60,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => body.ReceiveMouseInputAt(screenSpacePos);
|
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => body.ReceiveMouseInputAt(screenSpacePos);
|
||||||
|
|
||||||
|
public override Vector2 SelectionPoint => ToScreenSpace(OriginPosition);
|
||||||
|
public override Quad SelectionQuad => body.PathDrawQuad;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
public class OsuEditPlayfield : OsuPlayfield
|
public class OsuEditPlayfield : OsuPlayfield
|
||||||
{
|
{
|
||||||
protected override bool ProxyApproachCircles => false;
|
protected override bool DisplayJudgements => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
public class OsuEditRulesetContainer : OsuRulesetContainer
|
public class OsuEditRulesetContainer : OsuRulesetContainer
|
||||||
{
|
{
|
||||||
public OsuEditRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
public OsuEditRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||||
: base(ruleset, beatmap, isForCurrentRuleset)
|
: base(ruleset, beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new OsuEditRulesetContainer(ruleset, beatmap, true);
|
protected override RulesetContainer CreateRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) => new OsuEditRulesetContainer(ruleset, beatmap);
|
||||||
|
|
||||||
protected override IReadOnlyList<ICompositionTool> CompositionTools => new ICompositionTool[]
|
protected override IReadOnlyList<ICompositionTool> CompositionTools => new ICompositionTool[]
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
{
|
{
|
||||||
public class OsuModAutoplay : ModAutoplay<OsuHitObject>
|
public class OsuModAutoplay : ModAutoplay<OsuHitObject>
|
||||||
{
|
{
|
||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot), typeof(OsuModSpunOut) }).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).Append(typeof(OsuModSpunOut)).ToArray();
|
||||||
|
|
||||||
protected override Score CreateReplayScore(Beatmap<OsuHitObject> beatmap)
|
protected override Score CreateReplayScore(Beatmap<OsuHitObject> beatmap)
|
||||||
{
|
{
|
||||||
|
@ -5,20 +5,23 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.UI;
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Mods
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
{
|
{
|
||||||
public class OsuModHardRock : ModHardRock, IApplicableToHitObject<OsuHitObject>
|
public class OsuModHardRock : ModHardRock, IApplicableToHitObject
|
||||||
{
|
{
|
||||||
public override double ScoreMultiplier => 1.06;
|
public override double ScoreMultiplier => 1.06;
|
||||||
public override bool Ranked => true;
|
public override bool Ranked => true;
|
||||||
|
|
||||||
public void ApplyToHitObject(OsuHitObject hitObject)
|
public void ApplyToHitObject(HitObject hitObject)
|
||||||
{
|
{
|
||||||
hitObject.Position = new Vector2(hitObject.Position.X, OsuPlayfield.BASE_SIZE.Y - hitObject.Y);
|
var osuObject = (OsuHitObject)hitObject;
|
||||||
|
|
||||||
|
osuObject.Position = new Vector2(osuObject.Position.X, OsuPlayfield.BASE_SIZE.Y - osuObject.Y);
|
||||||
|
|
||||||
var slider = hitObject as Slider;
|
var slider = hitObject as Slider;
|
||||||
if (slider == null)
|
if (slider == null)
|
||||||
|
@ -9,6 +9,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
{
|
{
|
||||||
public class OsuModNoFail : ModNoFail
|
public class OsuModNoFail : ModNoFail
|
||||||
{
|
{
|
||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public class OsuModRelax : ModRelax
|
public class OsuModRelax : ModRelax
|
||||||
{
|
{
|
||||||
public override string Description => @"You don't need to click. Give your clicking/tapping fingers a break from the heat of things.";
|
public override string Description => @"You don't need to click. Give your clicking/tapping fingers a break from the heat of things.";
|
||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,6 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
{
|
{
|
||||||
public class OsuModSuddenDeath : ModSuddenDeath
|
public class OsuModSuddenDeath : ModSuddenDeath
|
||||||
{
|
{
|
||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ using System.Linq;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Framework.Graphics.Primitives;
|
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
@ -177,8 +176,5 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
public Drawable ProxiedLayer => HeadCircle.ApproachCircle;
|
public Drawable ProxiedLayer => HeadCircle.ApproachCircle;
|
||||||
|
|
||||||
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Body.ReceiveMouseInputAt(screenSpacePos);
|
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Body.ReceiveMouseInputAt(screenSpacePos);
|
||||||
|
|
||||||
public override Vector2 SelectionPoint => ToScreenSpace(OriginPosition);
|
|
||||||
public override Quad SelectionQuad => Body.PathDrawQuad;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Children = new Drawable[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
Background = new SpinnerBackground
|
Background = new SpinnerBackground
|
||||||
{
|
{
|
||||||
|
@ -7,10 +7,11 @@ using osu.Game.Rulesets.Objects;
|
|||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Edit.Types;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
public abstract class OsuHitObject : HitObject, IHasComboInformation, IHasPosition
|
public abstract class OsuHitObject : HitObject, IHasComboInformation, IHasEditablePosition
|
||||||
{
|
{
|
||||||
public const double OBJECT_RADIUS = 64;
|
public const double OBJECT_RADIUS = 64;
|
||||||
|
|
||||||
@ -70,5 +71,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
}
|
}
|
||||||
|
|
||||||
public virtual void OffsetPosition(Vector2 offset) => Position += offset;
|
public virtual void OffsetPosition(Vector2 offset) => Position += offset;
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => new OsuHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
osu.Game.Rulesets.Osu/Objects/OsuHitWindows.cs
Normal file
29
osu.Game.Rulesets.Osu/Objects/OsuHitWindows.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
|
{
|
||||||
|
public class OsuHitWindows : HitWindows
|
||||||
|
{
|
||||||
|
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
|
||||||
|
{
|
||||||
|
{ HitResult.Great, (160, 100, 40) },
|
||||||
|
{ HitResult.Good, (280, 200, 120) },
|
||||||
|
{ HitResult.Meh, (400, 300, 200) },
|
||||||
|
{ HitResult.Miss, (400, 400, 400) },
|
||||||
|
};
|
||||||
|
|
||||||
|
public override void SetDifficulty(double difficulty)
|
||||||
|
{
|
||||||
|
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
|
||||||
|
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);
|
||||||
|
Meh = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Meh]);
|
||||||
|
Miss = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Miss]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,94 +0,0 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An enumerable container wrapping <see cref="OsuHitObject"/> input as <see cref="OsuDifficultyHitObject"/>
|
|
||||||
/// which contains extra data required for difficulty calculation.
|
|
||||||
/// </summary>
|
|
||||||
public class OsuDifficultyBeatmap : IEnumerable<OsuDifficultyHitObject>
|
|
||||||
{
|
|
||||||
private readonly IEnumerator<OsuDifficultyHitObject> difficultyObjects;
|
|
||||||
private readonly Queue<OsuDifficultyHitObject> onScreen = new Queue<OsuDifficultyHitObject>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates an enumerator, which preprocesses a list of <see cref="OsuHitObject"/>s recieved as input, wrapping them as
|
|
||||||
/// <see cref="OsuDifficultyHitObject"/> which contains extra data required for difficulty calculation.
|
|
||||||
/// </summary>
|
|
||||||
public OsuDifficultyBeatmap(List<OsuHitObject> objects, double timeRate)
|
|
||||||
{
|
|
||||||
// Sort OsuHitObjects by StartTime - they are not correctly ordered in some cases.
|
|
||||||
// This should probably happen before the objects reach the difficulty calculator.
|
|
||||||
objects.Sort((a, b) => a.StartTime.CompareTo(b.StartTime));
|
|
||||||
difficultyObjects = createDifficultyObjectEnumerator(objects, timeRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns an enumerator that enumerates all <see cref="OsuDifficultyHitObject"/>s in the <see cref="OsuDifficultyBeatmap"/>.
|
|
||||||
/// The inner loop adds objects that appear on screen into a queue until we need to hit the next object.
|
|
||||||
/// The outer loop returns objects from this queue one at a time, only after they had to be hit, and should no longer be on screen.
|
|
||||||
/// This means that we can loop through every object that is on screen at the time when a new one appears,
|
|
||||||
/// allowing us to determine a reading strain for the object that just appeared.
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerator<OsuDifficultyHitObject> GetEnumerator()
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
// Add upcoming objects to the queue until we have at least one object that had been hit and can be dequeued.
|
|
||||||
// This means there is always at least one object in the queue unless we reached the end of the map.
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (!difficultyObjects.MoveNext())
|
|
||||||
break; // New objects can't be added anymore, but we still need to dequeue and return the ones already on screen.
|
|
||||||
|
|
||||||
OsuDifficultyHitObject latest = difficultyObjects.Current;
|
|
||||||
// Calculate flow values here
|
|
||||||
|
|
||||||
foreach (OsuDifficultyHitObject h in onScreen)
|
|
||||||
{
|
|
||||||
// ReSharper disable once PossibleNullReferenceException (resharper not smart enough to understand IEnumerator.MoveNext())
|
|
||||||
h.TimeUntilHit -= latest.DeltaTime;
|
|
||||||
// Calculate reading strain here
|
|
||||||
}
|
|
||||||
|
|
||||||
onScreen.Enqueue(latest);
|
|
||||||
}
|
|
||||||
while (onScreen.Peek().TimeUntilHit > 0); // Keep adding new objects on screen while there is still time before we have to hit the next one.
|
|
||||||
|
|
||||||
if (onScreen.Count == 0) break; // We have reached the end of the map and enumerated all the objects.
|
|
||||||
yield return onScreen.Dequeue(); // Remove and return objects one by one that had to be hit before the latest one appeared.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
|
|
||||||
private IEnumerator<OsuDifficultyHitObject> createDifficultyObjectEnumerator(List<OsuHitObject> objects, double timeRate)
|
|
||||||
{
|
|
||||||
// We will process OsuHitObjects in groups of three to form a triangle, so we can calculate an angle for each object.
|
|
||||||
OsuHitObject[] triangle = new OsuHitObject[3];
|
|
||||||
|
|
||||||
// OsuDifficultyHitObject construction requires three components, an extra copy of the first OsuHitObject is used at the beginning.
|
|
||||||
if (objects.Count > 1)
|
|
||||||
{
|
|
||||||
triangle[1] = objects[0]; // This copy will get shifted to the last spot in the triangle.
|
|
||||||
triangle[0] = objects[0]; // This component corresponds to the real first OsuHitOject.
|
|
||||||
}
|
|
||||||
|
|
||||||
// The final component of the first triangle will be the second OsuHitOject of the map, which forms the first jump.
|
|
||||||
// If the map has less than two OsuHitObjects, the enumerator will not return anything.
|
|
||||||
for (int i = 1; i < objects.Count; ++i)
|
|
||||||
{
|
|
||||||
triangle[2] = triangle[1];
|
|
||||||
triangle[1] = triangle[0];
|
|
||||||
triangle[0] = objects[i];
|
|
||||||
|
|
||||||
yield return new OsuDifficultyHitObject(triangle, timeRate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,28 +5,29 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.Osu.OsuDifficulty;
|
|
||||||
using osu.Game.Rulesets.Osu.UI;
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Osu.Scoring;
|
|
||||||
using osu.Game.Rulesets.Osu.Edit;
|
using osu.Game.Rulesets.Osu.Edit;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osu.Game.Rulesets.Osu.Replays;
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
using osu.Game.Rulesets.Replays.Types;
|
using osu.Game.Rulesets.Replays.Types;
|
||||||
|
using osu.Game.Beatmaps.Legacy;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Osu.Difficulty;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu
|
namespace osu.Game.Rulesets.Osu
|
||||||
{
|
{
|
||||||
public class OsuRuleset : Ruleset
|
public class OsuRuleset : Ruleset
|
||||||
{
|
{
|
||||||
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new OsuRulesetContainer(this, beatmap, isForCurrentRuleset);
|
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap) => new OsuRulesetContainer(this, beatmap);
|
||||||
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new OsuBeatmapConverter(beatmap);
|
||||||
|
public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new OsuBeatmapProcessor(beatmap);
|
||||||
|
|
||||||
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[]
|
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[]
|
||||||
{
|
{
|
||||||
@ -36,34 +37,51 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
new KeyBinding(InputKey.MouseRight, OsuAction.RightButton),
|
new KeyBinding(InputKey.MouseRight, OsuAction.RightButton),
|
||||||
};
|
};
|
||||||
|
|
||||||
public override IEnumerable<BeatmapStatistic> GetBeatmapStatistics(WorkingBeatmap beatmap)
|
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
||||||
{
|
{
|
||||||
IEnumerable<HitObject> hitObjects = beatmap.Beatmap.HitObjects;
|
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||||
IEnumerable<HitObject> circles = hitObjects.Where(c => !(c is IHasEndTime));
|
yield return new OsuModNightcore();
|
||||||
IEnumerable<HitObject> sliders = hitObjects.Where(s => s is IHasCurve);
|
else if (mods.HasFlag(LegacyMods.DoubleTime))
|
||||||
IEnumerable<HitObject> spinners = hitObjects.Where(s => s is IHasEndTime && !(s is IHasCurve));
|
yield return new OsuModDoubleTime();
|
||||||
|
|
||||||
return new[]
|
if (mods.HasFlag(LegacyMods.Autopilot))
|
||||||
{
|
yield return new OsuModAutopilot();
|
||||||
new BeatmapStatistic
|
|
||||||
{
|
if (mods.HasFlag(LegacyMods.Autoplay))
|
||||||
Name = @"Circle Count",
|
yield return new OsuModAutoplay();
|
||||||
Content = circles.Count().ToString(),
|
|
||||||
Icon = FontAwesome.fa_circle_o
|
if (mods.HasFlag(LegacyMods.Easy))
|
||||||
},
|
yield return new OsuModEasy();
|
||||||
new BeatmapStatistic
|
|
||||||
{
|
if (mods.HasFlag(LegacyMods.Flashlight))
|
||||||
Name = @"Slider Count",
|
yield return new OsuModFlashlight();
|
||||||
Content = sliders.Count().ToString(),
|
|
||||||
Icon = FontAwesome.fa_circle
|
if (mods.HasFlag(LegacyMods.HalfTime))
|
||||||
},
|
yield return new OsuModHalfTime();
|
||||||
new BeatmapStatistic
|
|
||||||
{
|
if (mods.HasFlag(LegacyMods.HardRock))
|
||||||
Name = @"Spinner Count",
|
yield return new OsuModHardRock();
|
||||||
Content = spinners.Count().ToString(),
|
|
||||||
Icon = FontAwesome.fa_circle
|
if (mods.HasFlag(LegacyMods.Hidden))
|
||||||
}
|
yield return new OsuModHidden();
|
||||||
};
|
|
||||||
|
if (mods.HasFlag(LegacyMods.NoFail))
|
||||||
|
yield return new OsuModNoFail();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Perfect))
|
||||||
|
yield return new OsuModPerfect();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Relax))
|
||||||
|
yield return new OsuModRelax();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.SpunOut))
|
||||||
|
yield return new OsuModSpunOut();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.SuddenDeath))
|
||||||
|
yield return new OsuModSuddenDeath();
|
||||||
|
|
||||||
|
if (mods.HasFlag(LegacyMods.Target))
|
||||||
|
yield return new OsuModTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<Mod> GetModsFor(ModType type)
|
public override IEnumerable<Mod> GetModsFor(ModType type)
|
||||||
@ -133,9 +151,9 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
|
|
||||||
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_osu_o };
|
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_osu_o };
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new OsuDifficultyCalculator(beatmap, mods);
|
public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new OsuDifficultyCalculator(beatmap, mods);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(Beatmap beatmap, Score score) => new OsuPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new OsuPerformanceCalculator(this, beatmap, score);
|
||||||
|
|
||||||
public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this);
|
public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this);
|
||||||
|
|
||||||
|
@ -2,11 +2,10 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using osu.Framework.Testing;
|
|
||||||
|
|
||||||
// We publish our internal attributes to other sub-projects of the framework.
|
// We publish our internal attributes to other sub-projects of the framework.
|
||||||
// Note, that we omit visual tests as they are meant to test the framework
|
// Note, that we omit visual tests as they are meant to test the framework
|
||||||
// behavior "in the wild".
|
// behavior "in the wild".
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Osu.Tests")]
|
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Osu.Tests")]
|
||||||
[assembly: InternalsVisibleTo(DynamicClassCompiler.DYNAMIC_ASSEMBLY_NAME)]
|
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Osu.Tests.Dynamic")]
|
||||||
|
@ -92,17 +92,17 @@ namespace osu.Game.Rulesets.Osu.Replays
|
|||||||
if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Miss) > endTime + h.HitWindows.HalfWindowFor(HitResult.Meh) + 50)
|
if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Miss) > endTime + h.HitWindows.HalfWindowFor(HitResult.Meh) + 50)
|
||||||
{
|
{
|
||||||
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y)));
|
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y)));
|
||||||
if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(h.StackedPosition.X, h.StackedPosition.Y)));
|
if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Miss), new Vector2(h.StackedPosition.X, h.StackedPosition.Y)));
|
||||||
}
|
}
|
||||||
else if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh) > endTime + h.HitWindows.HalfWindowFor(HitResult.Meh) + 50)
|
else if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh) > endTime + h.HitWindows.HalfWindowFor(HitResult.Meh) + 50)
|
||||||
{
|
{
|
||||||
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y)));
|
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y)));
|
||||||
if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(h.StackedPosition.X, h.StackedPosition.Y)));
|
if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(h.StackedPosition.X, h.StackedPosition.Y)));
|
||||||
}
|
}
|
||||||
else if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh) > endTime + h.HitWindows.HalfWindowFor(HitResult.Meh) + 50)
|
else if (h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Good) > endTime + h.HitWindows.HalfWindowFor(HitResult.Good) + 50)
|
||||||
{
|
{
|
||||||
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y)));
|
if (!(prev is Spinner) && h.StartTime - endTime < 1000) AddFrameToReplay(new OsuReplayFrame(endTime + h.HitWindows.HalfWindowFor(HitResult.Good), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y)));
|
||||||
if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Meh), new Vector2(h.StackedPosition.X, h.StackedPosition.Y)));
|
if (!(h is Spinner)) AddFrameToReplay(new OsuReplayFrame(h.StartTime - h.HitWindows.HalfWindowFor(HitResult.Good), new Vector2(h.StackedPosition.X, h.StackedPosition.Y)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user