mirror of
https://github.com/ppy/osu.git
synced 2026-05-13 21:53:29 +08:00
Compare commits
636 Commits
v2018.421.0
...
9
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="VisualTests (net461)" type="DotNetProject" factoryName=".NET Project" singleton="true">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/net461/osu.Game.Tests.exe" />
|
||||
<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/net471/osu.Game.Tests.exe" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
@@ -12,7 +12,7 @@
|
||||
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.6.1" />
|
||||
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="VisualTests (netcoreapp2.0)" type="DotNetProject" factoryName=".NET Project">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll" />
|
||||
<configuration default="false" name="VisualTests (netcoreapp2.1)" type="DotNetProject" factoryName=".NET Project">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/netcoreapp2.1/osu.Game.Tests.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
@@ -12,7 +12,7 @@
|
||||
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.0" />
|
||||
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="osu! (net461)" type="DotNetProject" factoryName=".NET Project" singleton="true">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net461/osu!.exe" />
|
||||
<configuration default="false" name="osu! (net471)" type="DotNetProject" factoryName=".NET Project" singleton="true">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net471/osu!.exe" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
@@ -12,7 +12,7 @@
|
||||
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.6.1" />
|
||||
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="osu! (netcoreapp2.0)" type="DotNetProject" factoryName=".NET Project">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp2.0/osu!.dll" />
|
||||
<configuration default="false" name="osu! (netcoreapp2.1)" type="DotNetProject" factoryName=".NET Project">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
@@ -12,7 +12,7 @@
|
||||
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.0" />
|
||||
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
Vendored
+20
-20
@@ -2,13 +2,13 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "VisualTests (Debug, net461)",
|
||||
"name": "VisualTests (Debug, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"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}",
|
||||
"preLaunchTask": "Build (Debug, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
@@ -16,13 +16,13 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, net461)",
|
||||
"name": "VisualTests (Release, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"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}",
|
||||
"preLaunchTask": "Build (Release, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
@@ -30,13 +30,13 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "osu! (Debug, net461)",
|
||||
"name": "osu! (Debug, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/net461/osu!.exe",
|
||||
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/net471/osu!.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
@@ -44,13 +44,13 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "osu! (Release, net461)",
|
||||
"name": "osu! (Release, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/osu.Desktop/bin/Release/net461/osu!.exe",
|
||||
"program": "${workspaceRoot}/osu.Desktop/bin/Release/net471/osu!.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
@@ -58,54 +58,54 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Debug, netcoreapp2.0)",
|
||||
"name": "VisualTests (Debug, netcoreapp2.1)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll"
|
||||
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.1/osu.Game.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, dotnet)",
|
||||
"preLaunchTask": "Build tests (Debug, dotnet)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, netcoreapp2.0)",
|
||||
"name": "VisualTests (Release, netcoreapp2.1)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll"
|
||||
"${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.1/osu.Game.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, dotnet)",
|
||||
"preLaunchTask": "Build tests (Release, dotnet)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "osu! (Debug, netcoreapp2.0)",
|
||||
"name": "osu! (Debug, netcoreapp2.1)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.0/osu!.dll",
|
||||
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll",
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, dotnet)",
|
||||
"preLaunchTask": "Build osu! (Debug, dotnet)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "osu! (Release, netcoreapp2.0)",
|
||||
"name": "osu! (Release, netcoreapp2.1)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.0/osu!.dll",
|
||||
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1/osu!.dll",
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, dotnet)",
|
||||
"preLaunchTask": "Build osu! (Release, dotnet)",
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
}
|
||||
|
||||
Vendored
+41
-8
@@ -8,7 +8,7 @@
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"/p:TargetFramework=net461",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -22,7 +22,7 @@
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"/p:Configuration=Release",
|
||||
"/p:TargetFramework=net461",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -31,14 +31,14 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Debug, dotnet)",
|
||||
"label": "Build osu! (Debug, dotnet)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Desktop",
|
||||
"/p:TargetFramework=netcoreapp2.0",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -47,14 +47,14 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Release, dotnet)",
|
||||
"label": "Build osu! (Release, dotnet)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Desktop",
|
||||
"/p:TargetFramework=netcoreapp2.0",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
@@ -64,7 +64,40 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (net461)",
|
||||
"label": "Build tests (Debug, dotnet)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Tests",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/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.1",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (net471)",
|
||||
"type": "shell",
|
||||
"command": "nuget",
|
||||
"args": [
|
||||
@@ -73,7 +106,7 @@
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Restore (netcoreapp2.0)",
|
||||
"label": "Restore (netcoreapp2.1)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
|
||||
@@ -8,7 +8,7 @@ This is still heavily under development and is not intended for end-user use. Th
|
||||
|
||||
# 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
|
||||
- Clone the repository including submodules (`git clone --recurse-submodules https://github.com/ppy/osu`)
|
||||
|
||||
+25
-25
@@ -1,26 +1,26 @@
|
||||
clone_depth: 1
|
||||
version: '{branch}-{build}'
|
||||
image: Visual Studio 2017
|
||||
configuration: Debug
|
||||
cache:
|
||||
- C:\ProgramData\chocolatey\bin -> appveyor.yml
|
||||
- C:\ProgramData\chocolatey\lib -> appveyor.yml
|
||||
- inspectcode -> appveyor.yml
|
||||
- packages -> **\packages.config
|
||||
install:
|
||||
- cmd: git submodule update --init --recursive --depth=5
|
||||
- cmd: choco install resharper-clt -y
|
||||
- cmd: choco install nvika -y
|
||||
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.4/CodeFileSanity.exe
|
||||
before_build:
|
||||
- cmd: CodeFileSanity.exe
|
||||
- cmd: nuget restore -verbosity quiet
|
||||
environment:
|
||||
TargetFramework: net461
|
||||
build:
|
||||
project: osu.sln
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
after_build:
|
||||
- cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL
|
||||
clone_depth: 1
|
||||
version: '{branch}-{build}'
|
||||
image: Visual Studio 2017 preview
|
||||
configuration: Debug
|
||||
cache:
|
||||
- C:\ProgramData\chocolatey\bin -> appveyor.yml
|
||||
- C:\ProgramData\chocolatey\lib -> appveyor.yml
|
||||
- inspectcode -> appveyor.yml
|
||||
- packages -> **\packages.config
|
||||
install:
|
||||
- cmd: git submodule update --init --recursive --depth=5
|
||||
- cmd: choco install resharper-clt -y
|
||||
- cmd: choco install nvika -y
|
||||
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.5/CodeFileSanity.exe
|
||||
before_build:
|
||||
- cmd: CodeFileSanity.exe
|
||||
- cmd: nuget restore -verbosity quiet
|
||||
environment:
|
||||
TargetFramework: net471
|
||||
build:
|
||||
project: osu.sln
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
after_build:
|
||||
- cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL
|
||||
- cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
|
||||
+18
-18
@@ -1,34 +1,34 @@
|
||||
branches:
|
||||
only:
|
||||
- release
|
||||
skip_tags: true
|
||||
skip_branch_with_pr: true
|
||||
clone_depth: 1
|
||||
version: '{branch}-{build}'
|
||||
version: '{build}'
|
||||
# skip_non_tags: true
|
||||
image: Visual Studio 2017
|
||||
configuration: Debug
|
||||
cache:
|
||||
- packages -> **\packages.config
|
||||
- '%USERPROFILE%\.nuget\packages -> **\*.csproj'
|
||||
install:
|
||||
- cmd: git submodule update --init --recursive --depth=5
|
||||
- git clone https://github.com/ppy/osu-deploy
|
||||
before_build:
|
||||
- ps: if($env:appveyor_repo_tag -eq 'True') { Update-AppveyorBuild -Version $env:appveyor_repo_tag_name }
|
||||
- cmd: git submodule update --init --recursive --depth=5
|
||||
- cmd: nuget restore -verbosity quiet
|
||||
build:
|
||||
project: osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
|
||||
verbosity: minimal
|
||||
after_build:
|
||||
build_script:
|
||||
- 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\net461\osu.Desktop.Deploy.exe.config
|
||||
- cd osu.Desktop.Deploy\bin\Debug\net461\
|
||||
- osu.Desktop.Deploy.exe %code_signing_password%
|
||||
- cd osu-deploy
|
||||
- nuget restore -verbosity quiet
|
||||
- msbuild osu.Desktop.Deploy.csproj
|
||||
- cmd: ..\appveyor-tools\secure-file -decrypt ..\fdc6f19b04.enc -secret %decode_secret% -out bin\Debug\net471\osu-deploy.exe.config
|
||||
- cd bin\Debug\net471\
|
||||
- osu.Desktop.Deploy.exe %code_signing_password% %APPVEYOR_REPO_TAG_NAME%
|
||||
environment:
|
||||
TargetFramework: net461
|
||||
TargetFramework: net471
|
||||
decode_secret:
|
||||
secure: i67IC2xj6DjjxmA6Oj2jing3+MwzLkq6CbGsjfZ7rdY=
|
||||
code_signing_password:
|
||||
secure: 34tLNqvjmmZEi97MLKfrnQ==
|
||||
artifacts:
|
||||
- path: 'Releases\*'
|
||||
- path: 'Releases\*'
|
||||
deploy:
|
||||
- provider: Environment
|
||||
name: github
|
||||
+1
-1
Submodule osu-framework updated: f1751c27ff...b963ce8250
+2
-2
@@ -7,7 +7,7 @@
|
||||
"name": "Deploy (Debug)",
|
||||
"request": "launch",
|
||||
"type": "mono",
|
||||
"program": "${workspaceRoot}/bin/Debug/net461/osu.Desktop.Deploy.exe",
|
||||
"program": "${workspaceRoot}/bin/Debug/net471/osu.Desktop.Deploy.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
"runtimeExecutable": null,
|
||||
@@ -18,7 +18,7 @@
|
||||
"name": "Deploy (Release)",
|
||||
"request": "launch",
|
||||
"type": "clr",
|
||||
"program": "${workspaceRoot}/bin/Release/net461/osu.Desktop.Deploy.exe",
|
||||
"program": "${workspaceRoot}/bin/Release/net471/osu.Desktop.Deploy.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
"runtimeExecutable": null,
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
-->
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="StagingFolder" value="Staging" />
|
||||
<add key="ReleasesFolder" value="Releases" />
|
||||
<add key="GitHubAccessToken" value="" />
|
||||
<add key="GitHubUsername" value="ppy" />
|
||||
<add key="GitHubRepoName" value="osu" />
|
||||
<add key="ProjectName" value="osu.Desktop" />
|
||||
<add key="NuSpecName" value="osu.Desktop\osu.nuspec" />
|
||||
<add key="SolutionName" value="osu" />
|
||||
<add key="TargetName" value="osu.Desktop" />
|
||||
<add key="PackageName" value="osulazer" />
|
||||
<add key="IconName" value="lazer.ico" />
|
||||
<add key="CodeSigningCertificate" value="" />
|
||||
</appSettings>
|
||||
</configuration>
|
||||
@@ -1,16 +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 Newtonsoft.Json;
|
||||
|
||||
namespace osu.Desktop.Deploy
|
||||
{
|
||||
public class GitHubObject
|
||||
{
|
||||
[JsonProperty(@"id")]
|
||||
public int Id;
|
||||
|
||||
[JsonProperty(@"name")]
|
||||
public string Name;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +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 Newtonsoft.Json;
|
||||
|
||||
namespace osu.Desktop.Deploy
|
||||
{
|
||||
public class GitHubRelease
|
||||
{
|
||||
[JsonProperty(@"id")]
|
||||
public int Id;
|
||||
|
||||
[JsonProperty(@"tag_name")]
|
||||
public string TagName => $"v{Name}";
|
||||
|
||||
[JsonProperty(@"name")]
|
||||
public string Name;
|
||||
|
||||
[JsonProperty(@"draft")]
|
||||
public bool Draft;
|
||||
|
||||
[JsonProperty(@"prerelease")]
|
||||
public bool PreRelease;
|
||||
|
||||
[JsonProperty(@"upload_url")]
|
||||
public string UploadUrl;
|
||||
}
|
||||
}
|
||||
@@ -1,471 +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;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.IO.Network;
|
||||
using FileWebRequest = osu.Framework.IO.Network.FileWebRequest;
|
||||
using WebRequest = osu.Framework.IO.Network.WebRequest;
|
||||
|
||||
namespace osu.Desktop.Deploy
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
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 squirrelPath => Path.Combine(packages, @"squirrel.windows\1.7.8\tools\Squirrel.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 ReleasesFolder = ConfigurationManager.AppSettings["ReleasesFolder"];
|
||||
public static string GitHubAccessToken = ConfigurationManager.AppSettings["GitHubAccessToken"];
|
||||
public static string GitHubUsername = ConfigurationManager.AppSettings["GitHubUsername"];
|
||||
public static string GitHubRepoName = ConfigurationManager.AppSettings["GitHubRepoName"];
|
||||
public static string SolutionName = ConfigurationManager.AppSettings["SolutionName"];
|
||||
public static string ProjectName = ConfigurationManager.AppSettings["ProjectName"];
|
||||
public static string NuSpecName = ConfigurationManager.AppSettings["NuSpecName"];
|
||||
public static string TargetNames = ConfigurationManager.AppSettings["TargetName"];
|
||||
public static string PackageName = ConfigurationManager.AppSettings["PackageName"];
|
||||
public static string IconName = ConfigurationManager.AppSettings["IconName"];
|
||||
public static string CodeSigningCertificate = ConfigurationManager.AppSettings["CodeSigningCertificate"];
|
||||
|
||||
public static string GitHubApiEndpoint => $"https://api.github.com/repos/{GitHubUsername}/{GitHubRepoName}/releases";
|
||||
public static string GitHubReleasePage => $"https://github.com/{GitHubUsername}/{GitHubRepoName}/releases";
|
||||
|
||||
/// <summary>
|
||||
/// How many previous build deltas we want to keep when publishing.
|
||||
/// </summary>
|
||||
private const int keep_delta_count = 4;
|
||||
|
||||
private static string codeSigningCmd => string.IsNullOrEmpty(codeSigningPassword) ? "" : $"-n \"/a /f {codeSigningCertPath} /p {codeSigningPassword} /t http://timestamp.comodoca.com/authenticode\"";
|
||||
|
||||
private static string homeDir => Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||
private static string codeSigningCertPath => Path.Combine(homeDir, CodeSigningCertificate);
|
||||
private static string solutionPath => Environment.CurrentDirectory;
|
||||
private static string stagingPath => Path.Combine(solutionPath, StagingFolder);
|
||||
private static string iconPath => Path.Combine(solutionPath, ProjectName, IconName);
|
||||
|
||||
private static string nupkgFilename(string ver) => $"{PackageName}.{ver}.nupkg";
|
||||
private static string nupkgDistroFilename(string ver) => $"{PackageName}-{ver}-full.nupkg";
|
||||
|
||||
private static readonly Stopwatch sw = new Stopwatch();
|
||||
|
||||
private static string codeSigningPassword;
|
||||
|
||||
private static bool interactive;
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
interactive = args.Length == 0;
|
||||
|
||||
displayHeader();
|
||||
|
||||
findSolutionPath();
|
||||
|
||||
if (!Directory.Exists(ReleasesFolder))
|
||||
{
|
||||
write("WARNING: No release directory found. Make sure you want this!", ConsoleColor.Yellow);
|
||||
Directory.CreateDirectory(ReleasesFolder);
|
||||
}
|
||||
|
||||
checkGitHubReleases();
|
||||
|
||||
refreshDirectory(StagingFolder);
|
||||
|
||||
//increment build number until we have a unique one.
|
||||
string verBase = DateTime.Now.ToString("yyyy.Mdd.");
|
||||
int increment = 0;
|
||||
while (Directory.GetFiles(ReleasesFolder, $"*{verBase}{increment}*").Any())
|
||||
increment++;
|
||||
|
||||
string version = $"{verBase}{increment}";
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.Write($"Ready to deploy {version}!");
|
||||
pauseIfInteractive();
|
||||
|
||||
sw.Start();
|
||||
|
||||
if (!string.IsNullOrEmpty(CodeSigningCertificate))
|
||||
{
|
||||
Console.Write("Enter code signing password: ");
|
||||
codeSigningPassword = args.Length > 0 ? args[0] : readLineMasked();
|
||||
}
|
||||
|
||||
write("Updating AssemblyInfo...");
|
||||
updateCsprojVersion(version);
|
||||
updateAppveyorVersion(version);
|
||||
|
||||
write("Running build process...");
|
||||
foreach (string targetName in TargetNames.Split(','))
|
||||
runCommand(msbuild_path, $"/v:quiet /m /t:{targetName.Replace('.', '_')} /p:OutputPath={stagingPath};Targets=\"Clean;Build\";Configuration=Release {SolutionName}.sln");
|
||||
|
||||
write("Creating NuGet deployment package...");
|
||||
runCommand(nugetPath, $"pack {NuSpecName} -Version {version} -Properties Configuration=Deploy -OutputDirectory {stagingPath} -BasePath {stagingPath}");
|
||||
|
||||
//prune once before checking for files so we can avoid erroring on files which aren't even needed for this build.
|
||||
pruneReleases();
|
||||
|
||||
checkReleaseFiles();
|
||||
|
||||
write("Running squirrel build...");
|
||||
runCommand(squirrelPath, $"--releasify {stagingPath}\\{nupkgFilename(version)} --setupIcon {iconPath} --icon {iconPath} {codeSigningCmd} --no-msi");
|
||||
|
||||
//prune again to clean up before upload.
|
||||
pruneReleases();
|
||||
|
||||
//rename setup to install.
|
||||
File.Copy(Path.Combine(ReleasesFolder, "Setup.exe"), Path.Combine(ReleasesFolder, "install.exe"), true);
|
||||
File.Delete(Path.Combine(ReleasesFolder, "Setup.exe"));
|
||||
|
||||
uploadBuild(version);
|
||||
|
||||
//reset assemblyinfo.
|
||||
updateCsprojVersion("0.0.0");
|
||||
|
||||
write("Done!", ConsoleColor.White);
|
||||
pauseIfInteractive();
|
||||
}
|
||||
|
||||
private static void displayHeader()
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" Please note that OSU! and PPY are registered trademarks and as such covered by trademark law.");
|
||||
Console.WriteLine(" Do not distribute builds of this project publicly that make use of these.");
|
||||
Console.ResetColor();
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure we have all the files in the release directory which are expected to be there.
|
||||
/// This should have been accounted for in earlier steps, and just serves as a verification step.
|
||||
/// </summary>
|
||||
private static void checkReleaseFiles()
|
||||
{
|
||||
if (!canGitHub) return;
|
||||
|
||||
var releaseLines = getReleaseLines();
|
||||
|
||||
//ensure we have all files necessary
|
||||
foreach (var l in releaseLines)
|
||||
if (!File.Exists(Path.Combine(ReleasesFolder, l.Filename)))
|
||||
error($"Local file missing {l.Filename}");
|
||||
}
|
||||
|
||||
private static IEnumerable<ReleaseLine> getReleaseLines() => File.ReadAllLines(Path.Combine(ReleasesFolder, "RELEASES")).Select(l => new ReleaseLine(l));
|
||||
|
||||
private static void pruneReleases()
|
||||
{
|
||||
if (!canGitHub) return;
|
||||
|
||||
write("Pruning RELEASES...");
|
||||
|
||||
var releaseLines = getReleaseLines().ToList();
|
||||
|
||||
var fulls = releaseLines.Where(l => l.Filename.Contains("-full")).Reverse().Skip(1);
|
||||
|
||||
//remove any FULL releases (except most recent)
|
||||
foreach (var l in fulls)
|
||||
{
|
||||
write($"- Removing old release {l.Filename}", ConsoleColor.Yellow);
|
||||
File.Delete(Path.Combine(ReleasesFolder, l.Filename));
|
||||
releaseLines.Remove(l);
|
||||
}
|
||||
|
||||
//remove excess deltas
|
||||
var deltas = releaseLines.Where(l => l.Filename.Contains("-delta")).ToArray();
|
||||
if (deltas.Length > keep_delta_count)
|
||||
{
|
||||
foreach (var l in deltas.Take(deltas.Length - keep_delta_count))
|
||||
{
|
||||
write($"- Removing old delta {l.Filename}", ConsoleColor.Yellow);
|
||||
File.Delete(Path.Combine(ReleasesFolder, l.Filename));
|
||||
releaseLines.Remove(l);
|
||||
}
|
||||
}
|
||||
|
||||
var lines = new List<string>();
|
||||
releaseLines.ForEach(l => lines.Add(l.ToString()));
|
||||
File.WriteAllLines(Path.Combine(ReleasesFolder, "RELEASES"), lines);
|
||||
}
|
||||
|
||||
private static void uploadBuild(string version)
|
||||
{
|
||||
if (!canGitHub || string.IsNullOrEmpty(CodeSigningCertificate))
|
||||
return;
|
||||
|
||||
write("Publishing to GitHub...");
|
||||
|
||||
write($"- Creating release {version}...", ConsoleColor.Yellow);
|
||||
var req = new JsonWebRequest<GitHubRelease>($"{GitHubApiEndpoint}")
|
||||
{
|
||||
Method = HttpMethod.POST,
|
||||
};
|
||||
req.AddRaw(JsonConvert.SerializeObject(new GitHubRelease
|
||||
{
|
||||
Name = version,
|
||||
Draft = true,
|
||||
PreRelease = true
|
||||
}));
|
||||
req.AuthenticatedBlockingPerform();
|
||||
|
||||
var assetUploadUrl = req.ResponseObject.UploadUrl.Replace("{?name,label}", "?name={0}");
|
||||
foreach (var a in Directory.GetFiles(ReleasesFolder).Reverse()) //reverse to upload RELEASES first.
|
||||
{
|
||||
write($"- Adding asset {a}...", ConsoleColor.Yellow);
|
||||
var upload = new WebRequest(assetUploadUrl, Path.GetFileName(a))
|
||||
{
|
||||
Method = HttpMethod.POST,
|
||||
Timeout = 240000,
|
||||
ContentType = "application/octet-stream",
|
||||
};
|
||||
|
||||
upload.AddRaw(File.ReadAllBytes(a));
|
||||
upload.AuthenticatedBlockingPerform();
|
||||
}
|
||||
|
||||
openGitHubReleasePage();
|
||||
}
|
||||
|
||||
private static void openGitHubReleasePage() => Process.Start(GitHubReleasePage);
|
||||
|
||||
private static bool canGitHub => !string.IsNullOrEmpty(GitHubAccessToken);
|
||||
|
||||
private static void checkGitHubReleases()
|
||||
{
|
||||
if (!canGitHub) return;
|
||||
|
||||
write("Checking GitHub releases...");
|
||||
var req = new JsonWebRequest<List<GitHubRelease>>($"{GitHubApiEndpoint}");
|
||||
req.AuthenticatedBlockingPerform();
|
||||
|
||||
var lastRelease = req.ResponseObject.FirstOrDefault();
|
||||
|
||||
if (lastRelease == null)
|
||||
return;
|
||||
|
||||
if (lastRelease.Draft)
|
||||
{
|
||||
openGitHubReleasePage();
|
||||
error("There's a pending draft release! You probably don't want to push a build with this present.");
|
||||
}
|
||||
|
||||
//there's a previous release for this project.
|
||||
var assetReq = new JsonWebRequest<List<GitHubObject>>($"{GitHubApiEndpoint}/{lastRelease.Id}/assets");
|
||||
assetReq.AuthenticatedBlockingPerform();
|
||||
var assets = assetReq.ResponseObject;
|
||||
|
||||
//make sure our RELEASES file is the same as the last build on the server.
|
||||
var releaseAsset = assets.FirstOrDefault(a => a.Name == "RELEASES");
|
||||
|
||||
//if we don't have a RELEASES asset then the previous release likely wasn't a Squirrel one.
|
||||
if (releaseAsset == null) return;
|
||||
|
||||
write($"Last GitHub release was {lastRelease.Name}.");
|
||||
|
||||
bool requireDownload = false;
|
||||
|
||||
if (!File.Exists(Path.Combine(ReleasesFolder, nupkgDistroFilename(lastRelease.Name))))
|
||||
{
|
||||
write("Last version's package not found locally.", ConsoleColor.Red);
|
||||
requireDownload = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var lastReleases = new RawFileWebRequest($"{GitHubApiEndpoint}/assets/{releaseAsset.Id}");
|
||||
lastReleases.AuthenticatedBlockingPerform();
|
||||
if (File.ReadAllText(Path.Combine(ReleasesFolder, "RELEASES")) != lastReleases.ResponseString)
|
||||
{
|
||||
write("Server's RELEASES differed from ours.", ConsoleColor.Red);
|
||||
requireDownload = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!requireDownload) return;
|
||||
|
||||
write("Refreshing local releases directory...");
|
||||
refreshDirectory(ReleasesFolder);
|
||||
|
||||
foreach (var a in assets)
|
||||
{
|
||||
if (a.Name.EndsWith(".exe")) continue;
|
||||
|
||||
write($"- Downloading {a.Name}...", ConsoleColor.Yellow);
|
||||
new FileWebRequest(Path.Combine(ReleasesFolder, a.Name), $"{GitHubApiEndpoint}/assets/{a.Id}").AuthenticatedBlockingPerform();
|
||||
}
|
||||
}
|
||||
|
||||
private static void refreshDirectory(string directory)
|
||||
{
|
||||
if (Directory.Exists(directory))
|
||||
Directory.Delete(directory, true);
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
private static void updateCsprojVersion(string version)
|
||||
{
|
||||
var toUpdate = new[] { "<Version>", "<FileVersion>" };
|
||||
string file = Path.Combine(ProjectName, $"{ProjectName}.csproj");
|
||||
|
||||
var l1 = File.ReadAllLines(file);
|
||||
List<string> l2 = new List<string>();
|
||||
foreach (var l in l1)
|
||||
{
|
||||
string line = l;
|
||||
|
||||
foreach (var tag in toUpdate)
|
||||
{
|
||||
int startIndex = l.IndexOf(tag, StringComparison.InvariantCulture);
|
||||
if (startIndex == -1)
|
||||
continue;
|
||||
startIndex += tag.Length;
|
||||
|
||||
int endIndex = l.IndexOf("<", startIndex, StringComparison.InvariantCulture);
|
||||
line = $"{l.Substring(0, startIndex)}{version}{l.Substring(endIndex)}";
|
||||
}
|
||||
|
||||
l2.Add(line);
|
||||
}
|
||||
|
||||
File.WriteAllLines(file, l2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the base path of the active solution (git checkout location)
|
||||
/// </summary>
|
||||
private static void findSolutionPath()
|
||||
{
|
||||
string path = Path.GetDirectoryName(Environment.CommandLine.Replace("\"", "").Trim());
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
path = Environment.CurrentDirectory;
|
||||
|
||||
while (!File.Exists(Path.Combine(path, $"{SolutionName}.sln")))
|
||||
path = path.Remove(path.LastIndexOf(Path.DirectorySeparatorChar));
|
||||
path += Path.DirectorySeparatorChar;
|
||||
|
||||
Environment.CurrentDirectory = path;
|
||||
}
|
||||
|
||||
private static bool runCommand(string command, string args)
|
||||
{
|
||||
var psi = new ProcessStartInfo(command, args)
|
||||
{
|
||||
WorkingDirectory = solutionPath,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
};
|
||||
|
||||
Process p = Process.Start(psi);
|
||||
if (p == null) return false;
|
||||
|
||||
string output = p.StandardOutput.ReadToEnd();
|
||||
output += p.StandardError.ReadToEnd();
|
||||
|
||||
if (p.ExitCode == 0) return true;
|
||||
|
||||
write(output);
|
||||
error($"Command {command} {args} failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string readLineMasked()
|
||||
{
|
||||
var fg = Console.ForegroundColor;
|
||||
Console.ForegroundColor = Console.BackgroundColor;
|
||||
var ret = Console.ReadLine();
|
||||
Console.ForegroundColor = fg;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void error(string message)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine($"FATAL ERROR: {message}");
|
||||
|
||||
pauseIfInteractive();
|
||||
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)
|
||||
{
|
||||
if (sw.ElapsedMilliseconds > 0)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
Console.Write(sw.ElapsedMilliseconds.ToString().PadRight(8));
|
||||
}
|
||||
Console.ForegroundColor = col;
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
public static void AuthenticatedBlockingPerform(this WebRequest r)
|
||||
{
|
||||
r.AddHeader("Authorization", $"token {GitHubAccessToken}");
|
||||
r.Perform();
|
||||
}
|
||||
}
|
||||
|
||||
internal class RawFileWebRequest : WebRequest
|
||||
{
|
||||
public RawFileWebRequest(string url) : base(url)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string Accept => "application/octet-stream";
|
||||
}
|
||||
|
||||
internal class ReleaseLine
|
||||
{
|
||||
public string Hash;
|
||||
public string Filename;
|
||||
public int Filesize;
|
||||
|
||||
public ReleaseLine(string line)
|
||||
{
|
||||
var split = line.Split(' ');
|
||||
Hash = split[0];
|
||||
Filename = split[1];
|
||||
Filesize = int.Parse(split[2]);
|
||||
}
|
||||
|
||||
public override string ToString() => $"{Hash} {Filename} {Filesize}";
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.Game.props" />
|
||||
<PropertyGroup Label="Project">
|
||||
<TargetFrameworks>net461</TargetFrameworks>
|
||||
<OutputType>Exe</OutputType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="NuGet.CommandLine" Version="4.5.1" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="squirrel.windows" Version="1.7.8" Condition="'$(TargetFramework)' == 'net461'" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.4.0" />
|
||||
<PackageReference Include="System.Management.Automation.dll" Version="10.0.10586" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -12,6 +12,7 @@ using osu.Framework.Platform;
|
||||
using osu.Game;
|
||||
using OpenTK.Input;
|
||||
using Microsoft.Win32;
|
||||
using osu.Framework.Platform.Windows;
|
||||
|
||||
namespace osu.Desktop
|
||||
{
|
||||
@@ -40,7 +41,7 @@ namespace osu.Desktop
|
||||
/// <summary>
|
||||
/// A method of accessing an osu-stable install in a controlled fashion.
|
||||
/// </summary>
|
||||
private class StableStorage : DesktopStorage
|
||||
private class StableStorage : WindowsStorage
|
||||
{
|
||||
protected override string LocateBasePath()
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\osu.Game.props" />
|
||||
<PropertyGroup Label="Project">
|
||||
<TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
|
||||
<TargetFrameworks>net471;netcoreapp2.1</TargetFrameworks>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
@@ -10,11 +10,11 @@
|
||||
<Title>osu!lazer</Title>
|
||||
<Product>osu!lazer</Product>
|
||||
<ApplicationIcon>lazer.ico</ApplicationIcon>
|
||||
<Version>0.0.0.0</Version>
|
||||
<FileVersion>0.0.0.0</FileVersion>
|
||||
<Version>0.0.0</Version>
|
||||
<FileVersion>0.0.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Defines">
|
||||
<DefineConstants Condition="'$(TargetFramework)' == 'net461'">$(DefineConstants);NET_FRAMEWORK</DefineConstants>
|
||||
<DefineConstants Condition="'$(TargetFramework)' == 'net471'">$(DefineConstants);NET_FRAMEWORK</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject>osu.Desktop.Program</StartupObject>
|
||||
@@ -30,8 +30,8 @@
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
|
||||
<PackageReference Include="squirrel.windows" Version="1.7.8" Condition="'$(TargetFramework)' == 'net461'" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.3" />
|
||||
<PackageReference Include="squirrel.windows" Version="1.8.0" Condition="'$(TargetFramework)' == 'net471'" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Resources">
|
||||
<EmbeddedResource Include="lazer.ico" />
|
||||
|
||||
+8
-8
@@ -2,13 +2,13 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "VisualTests (Debug, net461)",
|
||||
"name": "VisualTests (Debug, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"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}",
|
||||
"preLaunchTask": "Build (Debug, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
@@ -16,13 +16,13 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, net461)",
|
||||
"name": "VisualTests (Release, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Catch.Tests.exe",
|
||||
"program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Catch.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
@@ -30,12 +30,12 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Debug, netcoreapp2.0)",
|
||||
"name": "VisualTests (Debug, netcoreapp2.1)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Catch.Tests.dll"
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Catch.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, dotnet)",
|
||||
@@ -43,12 +43,12 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, netcoreapp2.0)",
|
||||
"name": "VisualTests (Release, netcoreapp2.1)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Catch.Tests.dll"
|
||||
"${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Catch.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, dotnet)",
|
||||
|
||||
+6
-6
@@ -9,7 +9,7 @@
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||
"/p:TargetFramework=net461",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -24,7 +24,7 @@
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||
"/p:Configuration=Release",
|
||||
"/p:TargetFramework=net461",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -40,7 +40,7 @@
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.0",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -56,7 +56,7 @@
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.0",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
@@ -66,7 +66,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (net461)",
|
||||
"label": "Restore (net471)",
|
||||
"type": "shell",
|
||||
"command": "nuget",
|
||||
"args": [
|
||||
@@ -75,7 +75,7 @@
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Restore (netcoreapp2.0)",
|
||||
"label": "Restore (netcoreapp2.1)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
|
||||
@@ -5,8 +5,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
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.UI;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@@ -14,7 +12,7 @@ using osu.Game.Tests.Beatmaps;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
internal class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
{
|
||||
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>
|
||||
/// A sane value to account for osu!stable using ints everwhere.
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
}
|
||||
|
||||
protected override Beatmap CreateBeatmap(Ruleset ruleset)
|
||||
protected override IBeatmap CreateBeatmap(Ruleset ruleset)
|
||||
{
|
||||
var beatmap = new Beatmap
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
Child = catcherArea = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size })
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.BottomLeft
|
||||
Origin = Anchor.TopLeft
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
typeof(DrawableCatchHitObject),
|
||||
typeof(DrawableFruit),
|
||||
typeof(DrawableDroplet),
|
||||
typeof(BananaShower),
|
||||
typeof(Pulp),
|
||||
};
|
||||
|
||||
@@ -53,12 +54,19 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
|
||||
private DrawableFruit createDrawable(int index)
|
||||
{
|
||||
var fruit = new Fruit
|
||||
{
|
||||
StartTime = 1000000000000,
|
||||
IndexInBeatmap = index,
|
||||
Scale = 1.5f,
|
||||
};
|
||||
Fruit fruit = index == 5
|
||||
? new BananaShower.Banana
|
||||
{
|
||||
StartTime = 1000000000000,
|
||||
IndexInBeatmap = index,
|
||||
Scale = 1.5f,
|
||||
}
|
||||
: new Fruit
|
||||
{
|
||||
StartTime = 1000000000000,
|
||||
IndexInBeatmap = index,
|
||||
Scale = 1.5f,
|
||||
};
|
||||
|
||||
return new DrawableFruit(fruit)
|
||||
{
|
||||
|
||||
@@ -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 } };
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
||||
<TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
|
||||
|
||||
@@ -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 CatchBeatmapConverter(IBeatmap beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
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 positionData = obj as IHasXPosition;
|
||||
@@ -23,7 +28,20 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
var endTime = obj as IHasEndTime;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (curveData != null)
|
||||
{
|
||||
@@ -43,19 +61,6 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
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
|
||||
{
|
||||
StartTime = obj.StartTime,
|
||||
@@ -64,5 +69,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
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
|
||||
{
|
||||
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;
|
||||
foreach (var obj in beatmap.HitObjects)
|
||||
foreach (var obj in Beatmap.HitObjects.OfType<CatchHitObject>())
|
||||
obj.IndexInBeatmap = index++;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,12 +13,17 @@ using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.Catch.Replays;
|
||||
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
|
||||
{
|
||||
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[]
|
||||
{
|
||||
@@ -138,7 +143,7 @@ namespace osu.Game.Rulesets.Catch
|
||||
|
||||
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;
|
||||
|
||||
|
||||
+5
-8
@@ -1,21 +1,18 @@
|
||||
// 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.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
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;
|
||||
|
||||
protected override BeatmapConverter<CatchHitObject> CreateBeatmapConverter(Beatmap beatmap) => new CatchBeatmapConverter();
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,11 @@ using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.UI;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using System;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public class CatchModHardRock : ModHardRock, IApplicableToHitObject<CatchHitObject>
|
||||
public class CatchModHardRock : ModHardRock, IApplicableToHitObject
|
||||
{
|
||||
public override double ScoreMultiplier => 1.12;
|
||||
public override bool Ranked => true;
|
||||
@@ -17,9 +18,11 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
private float lastStartX;
|
||||
private int lastStartTime;
|
||||
|
||||
public void ApplyToHitObject(CatchHitObject hitObject)
|
||||
public void ApplyToHitObject(HitObject hitObject)
|
||||
{
|
||||
float position = hitObject.X;
|
||||
var catchObject = (CatchHitObject)hitObject;
|
||||
|
||||
float position = catchObject.X;
|
||||
int startTime = (int)hitObject.StartTime;
|
||||
|
||||
if (lastStartX == 0)
|
||||
@@ -60,7 +63,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
position += rand;
|
||||
}
|
||||
|
||||
hitObject.X = position;
|
||||
catchObject.X = position;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -79,7 +82,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
}
|
||||
}
|
||||
|
||||
hitObject.X = position;
|
||||
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;
|
||||
}
|
||||
|
||||
protected override HitWindows CreateHitWindows() => null;
|
||||
}
|
||||
|
||||
public enum FruitVisualRepresentation
|
||||
|
||||
@@ -18,12 +18,19 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
private Circle border;
|
||||
|
||||
private const float drawable_radius = (float)CatchHitObject.OBJECT_RADIUS * radius_adjust;
|
||||
|
||||
/// <summary>
|
||||
/// Because we're adding a border around the fruit, we need to scale down some.
|
||||
/// </summary>
|
||||
private const float radius_adjust = 1.1f;
|
||||
|
||||
public DrawableFruit(Fruit h)
|
||||
: base(h)
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS);
|
||||
Size = new Vector2(drawable_radius);
|
||||
Masking = false;
|
||||
|
||||
Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
|
||||
@@ -44,14 +51,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
Hollow = !HitObject.HyperDash,
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 4,
|
||||
Radius = 4 * radius_adjust,
|
||||
Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Darken(1).Opacity(0.6f)
|
||||
},
|
||||
Size = new Vector2(Height * 1.5f),
|
||||
Size = new Vector2(Height),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
BorderColour = Color4.White,
|
||||
BorderThickness = 4f,
|
||||
BorderThickness = 3f * radius_adjust,
|
||||
Children = new Framework.Graphics.Drawable[]
|
||||
{
|
||||
new Box
|
||||
@@ -82,8 +89,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
|
||||
private Framework.Graphics.Drawable createPulp(FruitVisualRepresentation representation)
|
||||
{
|
||||
const float large_pulp_3 = 13f;
|
||||
const float distance_from_centre_3 = 0.23f;
|
||||
const float large_pulp_3 = 8f * radius_adjust;
|
||||
const float distance_from_centre_3 = 0.15f;
|
||||
|
||||
const float large_pulp_4 = large_pulp_3 * 0.925f;
|
||||
const float distance_from_centre_4 = distance_from_centre_3 / 0.925f;
|
||||
@@ -106,11 +113,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(small_pulp),
|
||||
Y = 0.05f,
|
||||
Y = -0.34f,
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
@@ -146,11 +151,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(small_pulp),
|
||||
Y = 0.1f,
|
||||
Y = -0.3f,
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
@@ -186,11 +189,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(small_pulp),
|
||||
Y = -0.1f,
|
||||
Y = -0.33f,
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
@@ -220,10 +221,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(small_pulp),
|
||||
Y = -0.25f,
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
@@ -253,16 +253,15 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(small_pulp),
|
||||
Y = -0.15f
|
||||
Y = -0.3f
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Size = new Vector2(large_pulp_4 * 1.2f, large_pulp_4 * 3),
|
||||
Size = new Vector2(large_pulp_4 * 0.8f, large_pulp_4 * 2.5f),
|
||||
Y = 0.05f,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -29,14 +29,24 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 8,
|
||||
Colour = accentColour.Darken(0.2f).Opacity(0.75f)
|
||||
};
|
||||
if (IsLoaded) updateAccentColour();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAccentColour()
|
||||
{
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = Size.X / 2,
|
||||
Colour = accentColour.Darken(0.2f).Opacity(0.75f)
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
updateAccentColour();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.Replays
|
||||
Dashing = dashing;
|
||||
}
|
||||
|
||||
public void ConvertFrom(LegacyReplayFrame legacyFrame, Beatmap beatmap)
|
||||
public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap)
|
||||
{
|
||||
Position = legacyFrame.Position.X / CatchPlayfield.BASE_WIDTH;
|
||||
Dashing = legacyFrame.ButtonState == ReplayButtonState.Left1;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Input.Handlers;
|
||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||
using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||
using osu.Game.Rulesets.Catch.Replays;
|
||||
@@ -20,8 +19,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public class CatchRulesetContainer : ScrollingRulesetContainer<CatchPlayfield, CatchHitObject>
|
||||
{
|
||||
public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
||||
: base(ruleset, beatmap, isForCurrentRuleset)
|
||||
public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -29,14 +28,12 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
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);
|
||||
|
||||
public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
|
||||
|
||||
protected override Vector2 PlayfieldArea => new Vector2(0.86f); // matches stable's vertical offset for catcher plate
|
||||
|
||||
protected override DrawableHitObject<CatchHitObject> GetVisualRepresentation(CatchHitObject h)
|
||||
{
|
||||
switch (h)
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
{
|
||||
public class CatcherArea : Container
|
||||
{
|
||||
public const float CATCHER_SIZE = 172;
|
||||
public const float CATCHER_SIZE = 84;
|
||||
|
||||
protected readonly Catcher MovableCatcher;
|
||||
|
||||
@@ -99,8 +99,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
|
||||
public class Catcher : Container, IKeyBindingHandler<CatchAction>
|
||||
{
|
||||
private Texture texture;
|
||||
|
||||
private Container<DrawableHitObject> caughtFruit;
|
||||
|
||||
public Container ExplodingFruitTarget;
|
||||
@@ -121,10 +119,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
private void load()
|
||||
{
|
||||
texture = textures.Get(@"Play/Catch/fruit-catcher-idle");
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
caughtFruit = new Container<DrawableHitObject>
|
||||
@@ -196,13 +192,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50);
|
||||
}
|
||||
|
||||
private Sprite createCatcherSprite() => new Sprite
|
||||
{
|
||||
Size = new Vector2(CATCHER_SIZE),
|
||||
FillMode = FillMode.Fill,
|
||||
Texture = texture,
|
||||
OriginPosition = new Vector2(-3, 10) // temporary until the sprite is aligned correctly.
|
||||
};
|
||||
private Sprite createCatcherSprite() => new CatcherSprite();
|
||||
|
||||
/// <summary>
|
||||
/// Add a caught fruit to the catcher's stack.
|
||||
@@ -411,6 +401,23 @@ namespace osu.Game.Rulesets.Catch.UI
|
||||
f.Expire();
|
||||
}
|
||||
}
|
||||
|
||||
private class CatcherSprite : Sprite
|
||||
{
|
||||
public CatcherSprite()
|
||||
{
|
||||
Size = new Vector2(CATCHER_SIZE);
|
||||
|
||||
// Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling.
|
||||
OriginPosition = new Vector2(-0.02f, 0.06f) * CATCHER_SIZE;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
{
|
||||
Texture = textures.Get(@"Play/Catch/fruit-catcher-idle");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -2,13 +2,13 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "VisualTests (Debug, net461)",
|
||||
"name": "VisualTests (Debug, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"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}",
|
||||
"preLaunchTask": "Build (Debug, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
@@ -16,13 +16,13 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, net461)",
|
||||
"name": "VisualTests (Release, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Mania.Tests.exe",
|
||||
"program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Mania.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
@@ -30,12 +30,12 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Debug, netcoreapp2.0)",
|
||||
"name": "VisualTests (Debug, netcoreapp2.1)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Mania.Tests.dll"
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Mania.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, dotnet)",
|
||||
@@ -43,12 +43,12 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, netcoreapp2.0)",
|
||||
"name": "VisualTests (Release, netcoreapp2.1)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Mania.Tests.dll"
|
||||
"${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Mania.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, dotnet)",
|
||||
|
||||
+6
-6
@@ -9,7 +9,7 @@
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||
"/p:TargetFramework=net461",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -24,7 +24,7 @@
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||
"/p:Configuration=Release",
|
||||
"/p:TargetFramework=net461",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -40,7 +40,7 @@
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.0",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -56,7 +56,7 @@
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.0",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
@@ -66,7 +66,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (net461)",
|
||||
"label": "Restore (net471)",
|
||||
"type": "shell",
|
||||
"command": "nuget",
|
||||
"args": [
|
||||
@@ -75,7 +75,7 @@
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Restore (netcoreapp2.0)",
|
||||
"label": "Restore (netcoreapp2.1)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
|
||||
@@ -5,8 +5,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
@@ -14,17 +12,14 @@ using osu.Game.Tests.Beatmaps;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
internal class ManiaBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
||||
|
||||
private bool isForCurrentRuleset;
|
||||
|
||||
[NonParallelizable]
|
||||
[TestCase("basic", false)]
|
||||
public void Test(string name, bool isForCurrentRuleset)
|
||||
[TestCase("basic")]
|
||||
public new void Test(string name)
|
||||
{
|
||||
this.isForCurrentRuleset = isForCurrentRuleset;
|
||||
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>
|
||||
/// A sane value to account for osu!stable using ints everwhere.
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
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.Drawables;
|
||||
using osu.Game.Tests.Visual;
|
||||
@@ -17,6 +19,14 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
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
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
@@ -43,14 +53,14 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
RelativeChildSize = new Vector2(1, 10000),
|
||||
Children = new[]
|
||||
{
|
||||
new DrawableNote(new Note(), ManiaAction.Key1)
|
||||
new DrawableNote(note1, ManiaAction.Key1)
|
||||
{
|
||||
Y = 5000,
|
||||
LifetimeStart = double.MinValue,
|
||||
LifetimeEnd = double.MaxValue,
|
||||
AccentColour = Color4.Red
|
||||
},
|
||||
new DrawableNote(new Note(), ManiaAction.Key1)
|
||||
new DrawableNote(note2, ManiaAction.Key1)
|
||||
{
|
||||
Y = 6000,
|
||||
LifetimeStart = double.MinValue,
|
||||
@@ -77,13 +87,13 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
RelativeChildSize = new Vector2(1, 10000),
|
||||
Children = new[]
|
||||
{
|
||||
new DrawableHoldNote(new HoldNote { Duration = 1000 } , ManiaAction.Key1)
|
||||
new DrawableHoldNote(holdNote, ManiaAction.Key1)
|
||||
{
|
||||
Y = 5000,
|
||||
Height = 1000,
|
||||
LifetimeStart = double.MinValue,
|
||||
LifetimeEnd = double.MaxValue,
|
||||
AccentColour = Color4.Red
|
||||
AccentColour = Color4.Red,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
@@ -83,13 +85,16 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
playfield.OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
|
||||
playfield.Columns[col].OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
|
||||
playfield.OnJudgement(drawableNote, 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)
|
||||
{
|
||||
playfield.Add(new DrawableNote(new Note
|
||||
{
|
||||
StartTime = t,
|
||||
Column = 0
|
||||
}, ManiaAction.Key1));
|
||||
var note1 = new Note { StartTime = t, Column = 0 };
|
||||
var note2 = new Note { StartTime = t, Column = 3 };
|
||||
|
||||
playfield.Add(new DrawableNote(new Note
|
||||
{
|
||||
StartTime = t,
|
||||
Column = 3
|
||||
}, ManiaAction.Key4));
|
||||
note1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
note2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
playfield.Add(new DrawableNote(note1, ManiaAction.Key1));
|
||||
playfield.Add(new DrawableNote(note2, ManiaAction.Key4));
|
||||
}
|
||||
|
||||
playfield.Add(new DrawableHoldNote(new HoldNote
|
||||
{
|
||||
StartTime = start_time,
|
||||
Duration = duration,
|
||||
Column = 1
|
||||
}, ManiaAction.Key2));
|
||||
var holdNote1 = new HoldNote { StartTime = start_time, Duration = duration, Column = 1 };
|
||||
var holdNote2 = new HoldNote { StartTime = start_time, Duration = duration, Column = 2 };
|
||||
|
||||
playfield.Add(new DrawableHoldNote(new HoldNote
|
||||
{
|
||||
StartTime = start_time,
|
||||
Duration = duration,
|
||||
Column = 2
|
||||
}, ManiaAction.Key3));
|
||||
holdNote1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
holdNote2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
playfield.Add(new DrawableHoldNote(holdNote1, ManiaAction.Key2));
|
||||
playfield.Add(new DrawableHoldNote(holdNote2, ManiaAction.Key3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
||||
<TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
|
||||
@@ -29,5 +30,27 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
{
|
||||
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;
|
||||
|
||||
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 roundedOverallDifficulty = Math.Round(original.BeatmapInfo.BaseDifficulty.OverallDifficulty);
|
||||
var roundedCircleSize = Math.Round(beatmap.BeatmapInfo.BaseDifficulty.CircleSize);
|
||||
var roundedOverallDifficulty = Math.Round(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
|
||||
|
||||
if (isForCurrentRuleset)
|
||||
if (IsForCurrentRuleset)
|
||||
TargetColumns = (int)Math.Max(1, roundedCircleSize);
|
||||
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)
|
||||
TargetColumns = 7;
|
||||
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;
|
||||
|
||||
@@ -68,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
|
||||
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;
|
||||
if (maniaOriginal != null)
|
||||
@@ -112,7 +113,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
/// <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>
|
||||
/// <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);
|
||||
|
||||
@@ -128,7 +129,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
/// <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>
|
||||
/// <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 distanceData = original as IHasDistance;
|
||||
@@ -165,7 +166,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
/// </summary>
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
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)
|
||||
{
|
||||
convertType = PatternType.None;
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
{
|
||||
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)
|
||||
{
|
||||
var endtimeData = HitObject as IHasEndTime;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
|
||||
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)
|
||||
{
|
||||
if (previousTime > hitObject.StartTime) throw new ArgumentOutOfRangeException(nameof(previousTime));
|
||||
|
||||
@@ -28,9 +28,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
/// <summary>
|
||||
/// The beatmap which <see cref="HitObject"/> is being converted from.
|
||||
/// </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)
|
||||
{
|
||||
if (random == null) throw new ArgumentNullException(nameof(random));
|
||||
@@ -113,7 +113,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||
drainTime /= 1000;
|
||||
|
||||
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);
|
||||
|
||||
return conversionDifficulty.Value;
|
||||
|
||||
+12
-13
@@ -1,16 +1,18 @@
|
||||
// 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.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
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;
|
||||
|
||||
@@ -31,12 +33,12 @@ namespace osu.Game.Rulesets.Mania
|
||||
/// </summary>
|
||||
private readonly List<ManiaHitObjectDifficulty> difficultyHitObjects = new List<ManiaHitObjectDifficulty>();
|
||||
|
||||
public ManiaDifficultyCalculator(Beatmap beatmap)
|
||||
public ManiaDifficultyCalculator(IBeatmap beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
public ManiaDifficultyCalculator(Beatmap beatmap, Mod[] mods)
|
||||
public ManiaDifficultyCalculator(IBeatmap beatmap, Mod[] mods)
|
||||
: base(beatmap, mods)
|
||||
{
|
||||
}
|
||||
@@ -48,18 +50,17 @@ namespace osu.Game.Rulesets.Mania
|
||||
|
||||
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.
|
||||
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())
|
||||
return 0;
|
||||
|
||||
double starRating = calculateDifficulty() * star_scaling_factor;
|
||||
|
||||
categoryDifficulty?.Add("Strain", starRating);
|
||||
if (categoryDifficulty != null)
|
||||
categoryDifficulty["Strain"] = starRating;
|
||||
|
||||
return starRating;
|
||||
}
|
||||
@@ -140,7 +141,5 @@ namespace osu.Game.Rulesets.Mania
|
||||
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter(Beatmap beatmap) => new ManiaBeatmapConverter(true, beatmap);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -15,12 +15,18 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Replays;
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -182,7 +188,7 @@ namespace osu.Game.Rulesets.Mania
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -3,19 +3,18 @@
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.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 abstract int KeyCount { get; }
|
||||
public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier
|
||||
public override bool Ranked => true;
|
||||
|
||||
public void ApplyToBeatmapConverter(BeatmapConverter<ManiaHitObject> beatmapConverter)
|
||||
public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter)
|
||||
{
|
||||
var mbc = (ManiaBeatmapConverter)beatmapConverter;
|
||||
|
||||
|
||||
@@ -11,19 +11,23 @@ using osu.Game.Rulesets.UI;
|
||||
|
||||
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 ShortenedName => "DS";
|
||||
public override string Description => @"Double the stages, double the fun!";
|
||||
public override double ScoreMultiplier => 0;
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public void ApplyToBeatmapConverter(BeatmapConverter<ManiaHitObject> beatmapConverter)
|
||||
private bool isForCurrentRuleset;
|
||||
|
||||
public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter)
|
||||
{
|
||||
var mbc = (ManiaBeatmapConverter)beatmapConverter;
|
||||
|
||||
isForCurrentRuleset = mbc.IsForCurrentRuleset;
|
||||
|
||||
// Although this can work, for now let's not allow keymods for mania-specific beatmaps
|
||||
if (mbc.IsForCurrentRuleset)
|
||||
if (isForCurrentRuleset)
|
||||
return;
|
||||
|
||||
mbc.TargetColumns *= 2;
|
||||
@@ -34,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
var mrc = (ManiaRulesetContainer)rulesetContainer;
|
||||
|
||||
// Although this can work, for now let's not allow keymods for mania-specific beatmaps
|
||||
if (mrc.IsForCurrentRuleset)
|
||||
if (isForCurrentRuleset)
|
||||
return;
|
||||
|
||||
var newDefinitions = new List<StageDefinition>();
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public override string ShortenedName => "RD";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_dice;
|
||||
public override string Description => @"Shuffle around the keys!";
|
||||
public override double ScoreMultiplier => 0;
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
/// </summary>
|
||||
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>, IKeyBindingHandler<ManiaAction>
|
||||
{
|
||||
public override bool DisplayJudgement => false;
|
||||
|
||||
private readonly DrawableNote head;
|
||||
private readonly DrawableNote tail;
|
||||
|
||||
@@ -99,6 +101,19 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
|
||||
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()
|
||||
@@ -191,6 +206,13 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
// Factor in the release lenience
|
||||
timeOffset /= release_window_lenience;
|
||||
|
||||
if (!userTriggered)
|
||||
{
|
||||
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
/// <summary>
|
||||
/// The tail note of the hold.
|
||||
/// </summary>
|
||||
public readonly Note Tail = new TailNote();
|
||||
public readonly Note Tail = new Note();
|
||||
|
||||
/// <summary>
|
||||
/// 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>.
|
||||
// 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.Objects;
|
||||
|
||||
@@ -12,12 +10,6 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
{
|
||||
public virtual int Column { get; set; }
|
||||
|
||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||
{
|
||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||
|
||||
HitWindows.AllowsPerfect = true;
|
||||
HitWindows.AllowsOk = true;
|
||||
}
|
||||
protected override HitWindows CreateHitWindows() => new ManiaHitWindows();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,10 +24,10 @@ namespace osu.Game.Rulesets.Mania.Replays
|
||||
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
|
||||
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
|
||||
// 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)
|
||||
{
|
||||
if (!judgement.IsHit)
|
||||
if (!judgement.IsHit || !judgedObject.DisplayJudgement)
|
||||
return;
|
||||
|
||||
explosionContainer.Add(new HitExplosion(judgedObject));
|
||||
|
||||
@@ -36,8 +36,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
public IEnumerable<BarLine> BarLines;
|
||||
|
||||
public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
||||
: base(ruleset, beatmap, isForCurrentRuleset)
|
||||
public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
{
|
||||
// Generate the bar lines
|
||||
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);
|
||||
|
||||
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter(IsForCurrentRuleset, WorkingBeatmap.Beatmap);
|
||||
|
||||
protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (!judgedObject.DisplayJudgement)
|
||||
return;
|
||||
|
||||
judgements.Clear();
|
||||
judgements.Add(new DrawableManiaJudgement(judgement, judgedObject)
|
||||
{
|
||||
|
||||
+8
-8
@@ -2,13 +2,13 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "VisualTests (Debug, net461)",
|
||||
"name": "VisualTests (Debug, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"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}",
|
||||
"preLaunchTask": "Build (Debug, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
@@ -16,13 +16,13 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, net461)",
|
||||
"name": "VisualTests (Release, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Osu.Tests.exe",
|
||||
"program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Osu.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
@@ -30,12 +30,12 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Debug, netcoreapp2.0)",
|
||||
"name": "VisualTests (Debug, netcoreapp2.1)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Osu.Tests.dll"
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Osu.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, dotnet)",
|
||||
@@ -43,12 +43,12 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, netcoreapp2.0)",
|
||||
"name": "VisualTests (Release, netcoreapp2.1)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Osu.Tests.dll"
|
||||
"${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Osu.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, dotnet)",
|
||||
|
||||
+6
-6
@@ -9,7 +9,7 @@
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||
"/p:TargetFramework=net461",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -24,7 +24,7 @@
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||
"/p:Configuration=Release",
|
||||
"/p:TargetFramework=net461",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -40,7 +40,7 @@
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.0",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -56,7 +56,7 @@
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.0",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
@@ -66,7 +66,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (net461)",
|
||||
"label": "Restore (net471)",
|
||||
"type": "shell",
|
||||
"command": "nuget",
|
||||
"args": [
|
||||
@@ -75,7 +75,7 @@
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Restore (netcoreapp2.0)",
|
||||
"label": "Restore (netcoreapp2.1)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
|
||||
@@ -5,17 +5,15 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
internal class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
{
|
||||
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>
|
||||
/// 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 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 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 testSimpleSmall(int repeats = 0) => createSlider(7, repeats: repeats);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
||||
<TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
|
||||
|
||||
@@ -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>
|
||||
{
|
||||
public OsuBeatmapConverter(IBeatmap beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
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 endTimeData = original as IHasEndTime;
|
||||
@@ -45,8 +50,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
StartTime = original.StartTime,
|
||||
Samples = original.Samples,
|
||||
EndTime = endTimeData.EndTime,
|
||||
|
||||
Position = positionData?.Position ?? OsuPlayfield.BASE_SIZE / 2,
|
||||
Position = positionData?.Position ?? OsuPlayfield.BASE_SIZE / 2
|
||||
};
|
||||
}
|
||||
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
|
||||
{
|
||||
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)
|
||||
|
||||
+16
-19
@@ -4,55 +4,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
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.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 double difficulty_multiplier = 0.0675;
|
||||
|
||||
public OsuDifficultyCalculator(Beatmap beatmap)
|
||||
public OsuDifficultyCalculator(IBeatmap beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
public OsuDifficultyCalculator(Beatmap beatmap, Mod[] mods)
|
||||
public OsuDifficultyCalculator(IBeatmap beatmap, Mod[] mods)
|
||||
: base(beatmap, mods)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void PreprocessHitObjects()
|
||||
{
|
||||
new OsuBeatmapProcessor().PostProcess(Beatmap);
|
||||
}
|
||||
|
||||
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 =
|
||||
{
|
||||
new Aim(),
|
||||
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)
|
||||
{
|
||||
while (h.BaseObject.StartTime > sectionEnd)
|
||||
while (h.BaseObject.StartTime > currentSectionEnd)
|
||||
{
|
||||
foreach (Skill s in skills)
|
||||
{
|
||||
s.SaveCurrentPeak();
|
||||
s.StartNewSectionFrom(sectionEnd);
|
||||
s.StartNewSectionFrom(currentSectionEnd);
|
||||
}
|
||||
|
||||
sectionEnd += section_length;
|
||||
currentSectionEnd += sectionLength;
|
||||
}
|
||||
|
||||
foreach (Skill s in skills)
|
||||
@@ -72,7 +71,5 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty
|
||||
|
||||
return starRating;
|
||||
}
|
||||
|
||||
protected override BeatmapConverter<OsuHitObject> CreateBeatmapConverter(Beatmap beatmap) => new OsuBeatmapConverter();
|
||||
}
|
||||
}
|
||||
+42
-30
@@ -5,35 +5,46 @@ 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.Osu.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
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 beatmapMaxCombo;
|
||||
|
||||
private Mod[] mods;
|
||||
|
||||
/// <summary>
|
||||
/// Approach rate adjusted by mods.
|
||||
/// </summary>
|
||||
private double realApproachRate;
|
||||
|
||||
/// <summary>
|
||||
/// Overall difficulty adjusted by mods.
|
||||
/// </summary>
|
||||
private double realOverallDifficulty;
|
||||
|
||||
private double accuracy;
|
||||
private int scoreMaxCombo;
|
||||
private int count300;
|
||||
private int count100;
|
||||
private int count50;
|
||||
private int countGreat;
|
||||
private int countGood;
|
||||
private int countMeh;
|
||||
private int countMiss;
|
||||
|
||||
public OsuPerformanceCalculator(Ruleset ruleset, Beatmap beatmap, Score score)
|
||||
public OsuPerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score)
|
||||
: base(ruleset, beatmap, score)
|
||||
{
|
||||
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);
|
||||
|
||||
beatmapMaxCombo = Beatmap.HitObjects.Count;
|
||||
beatmapMaxCombo += Beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count) + 1;
|
||||
beatmapMaxCombo = Beatmap.HitObjects.Count();
|
||||
// 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)
|
||||
@@ -41,25 +52,21 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
mods = Score.Mods;
|
||||
accuracy = Score.Accuracy;
|
||||
scoreMaxCombo = Score.MaxCombo;
|
||||
count300 = Convert.ToInt32(Score.Statistics[HitResult.Great]);
|
||||
count100 = Convert.ToInt32(Score.Statistics[HitResult.Good]);
|
||||
count50 = Convert.ToInt32(Score.Statistics[HitResult.Meh]);
|
||||
countGreat = Convert.ToInt32(Score.Statistics[HitResult.Great]);
|
||||
countGood = Convert.ToInt32(Score.Statistics[HitResult.Good]);
|
||||
countMeh = Convert.ToInt32(Score.Statistics[HitResult.Meh]);
|
||||
countMiss = Convert.ToInt32(Score.Statistics[HitResult.Miss]);
|
||||
|
||||
// Don't count scores made with supposedly unranked mods
|
||||
if (mods.Any(m => !m.Ranked))
|
||||
return 0;
|
||||
|
||||
// Todo: In the future we should apply changes to PreEmpt/AR at an OsuHitObject/BaseDifficulty level, but this is done
|
||||
// locally for now as doing so would modify animations and other things unexpectedly
|
||||
// DO NOT MODIFY THIS
|
||||
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);
|
||||
// Todo: These int casts are 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;
|
||||
double preEmpt = (int)BeatmapDifficulty.DifficultyRange(Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / TimeRate;
|
||||
|
||||
realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5;
|
||||
realOverallDifficulty = (80 - hitWindowGreat) / 6;
|
||||
|
||||
// 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
|
||||
@@ -85,6 +92,9 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
categoryRatings.Add("Aim", aimValue);
|
||||
categoryRatings.Add("Speed", speedValue);
|
||||
categoryRatings.Add("Accuracy", accuracyValue);
|
||||
categoryRatings.Add("OD", realOverallDifficulty);
|
||||
categoryRatings.Add("AR", realApproachRate);
|
||||
categoryRatings.Add("Max Combo", beatmapMaxCombo);
|
||||
}
|
||||
|
||||
return totalValue;
|
||||
@@ -121,8 +131,9 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
|
||||
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))
|
||||
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))
|
||||
{
|
||||
@@ -133,7 +144,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
// Scale the aim value with accuracy _slightly_
|
||||
aimValue *= 0.5f + accuracy / 2.0f;
|
||||
// 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;
|
||||
}
|
||||
@@ -153,10 +164,13 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
if (beatmapMaxCombo > 0)
|
||||
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_
|
||||
speedValue *= 0.5f + accuracy / 2.0f;
|
||||
// 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;
|
||||
}
|
||||
@@ -168,7 +182,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
int amountHitObjectsWithAccuracy = countHitCircles;
|
||||
|
||||
if (amountHitObjectsWithAccuracy > 0)
|
||||
betterAccuracyPercentage = ((count300 - (totalHits - amountHitObjectsWithAccuracy)) * 6 + count100 * 2 + count50) / (amountHitObjectsWithAccuracy * 6);
|
||||
betterAccuracyPercentage = ((countGreat - (totalHits - amountHitObjectsWithAccuracy)) * 6 + countGood * 2 + countMeh) / (amountHitObjectsWithAccuracy * 6);
|
||||
else
|
||||
betterAccuracyPercentage = 0;
|
||||
|
||||
@@ -178,7 +192,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
|
||||
// Lots of arbitrary values from testing.
|
||||
// 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
|
||||
accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f));
|
||||
@@ -191,9 +205,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
return accuracyValue;
|
||||
}
|
||||
|
||||
private double totalHits => count300 + count100 + count50 + countMiss;
|
||||
private double totalSuccessfulHits => count300 + count100 + count50;
|
||||
|
||||
protected override BeatmapConverter<OsuHitObject> CreateBeatmapConverter() => new OsuBeatmapConverter();
|
||||
private double totalHits => countGreat + countGood + countMeh + countMiss;
|
||||
private double totalSuccessfulHits => countGreat + countGood + countMeh;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-19
@@ -3,16 +3,18 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
||||
namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
{
|
||||
/// <summary>
|
||||
/// A wrapper around <see cref="OsuHitObject"/> extending it with additional data required for difficulty calculation.
|
||||
/// </summary>
|
||||
public class OsuDifficultyHitObject
|
||||
{
|
||||
private const int normalized_radius = 52;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="OsuHitObject"/> this <see cref="OsuDifficultyHitObject"/> refers to.
|
||||
/// </summary>
|
||||
@@ -28,26 +30,19 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
||||
/// </summary>
|
||||
public double DeltaTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 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 OsuHitObject lastObject;
|
||||
private readonly double timeRate;
|
||||
|
||||
private readonly OsuHitObject[] t;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the object calculating extra data required for difficulty calculation.
|
||||
/// </summary>
|
||||
public OsuDifficultyHitObject(OsuHitObject[] triangle, double timeRate)
|
||||
public OsuDifficultyHitObject(OsuHitObject currentObject, OsuHitObject lastObject, double timeRate)
|
||||
{
|
||||
this.lastObject = lastObject;
|
||||
this.timeRate = timeRate;
|
||||
|
||||
t = triangle;
|
||||
BaseObject = t[0];
|
||||
BaseObject = currentObject;
|
||||
|
||||
setDistances();
|
||||
setTimingValues();
|
||||
// Calculate angle here
|
||||
@@ -63,10 +58,10 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
||||
scalingFactor *= 1 + smallCircleBonus;
|
||||
}
|
||||
|
||||
Vector2 lastCursorPosition = t[1].StackedPosition;
|
||||
Vector2 lastCursorPosition = lastObject.StackedPosition;
|
||||
float lastTravelDistance = 0;
|
||||
|
||||
var lastSlider = t[1] as Slider;
|
||||
var lastSlider = lastObject as Slider;
|
||||
if (lastSlider != null)
|
||||
{
|
||||
computeSliderCursorPosition(lastSlider);
|
||||
@@ -80,8 +75,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
||||
private void setTimingValues()
|
||||
{
|
||||
// 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);
|
||||
TimeUntilHit = 450; // BaseObject.PreEmpt;
|
||||
DeltaTime = Math.Max(50, (BaseObject.StartTime - lastObject.StartTime) / timeRate);
|
||||
}
|
||||
|
||||
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)
|
||||
computeVertex(time);
|
||||
computeVertex(slider.EndTime);
|
||||
+2
-2
@@ -2,9 +2,9 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
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>
|
||||
/// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances.
|
||||
+3
-3
@@ -3,11 +3,11 @@
|
||||
|
||||
using System;
|
||||
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.OsuDifficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Osu.OsuDifficulty.Utils;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Skills
|
||||
namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to processes strain values of <see cref="OsuDifficultyHitObject"/>s, keep track of strain levels caused by the processed objects
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
// 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.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>
|
||||
/// Represents the skill required to press keys with regards to keeping up with the speed at which objects need to be hit.
|
||||
+1
-1
@@ -5,7 +5,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Utils
|
||||
namespace osu.Game.Rulesets.Osu.Difficulty.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// An indexed stack with Push() only, which disposes items at the bottom after the capacity is full.
|
||||
@@ -11,8 +11,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
{
|
||||
public class OsuEditRulesetContainer : OsuRulesetContainer
|
||||
{
|
||||
public OsuEditRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
||||
: base(ruleset, beatmap, isForCurrentRuleset)
|
||||
public OsuEditRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||
: 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[]
|
||||
{
|
||||
|
||||
@@ -13,8 +13,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override string ShortenedName => "AP";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot;
|
||||
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
|
||||
public override double ScoreMultiplier => 0;
|
||||
public override bool Ranked => false;
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail), typeof(ModAutoplay) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,20 +5,23 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using OpenTK;
|
||||
|
||||
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 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;
|
||||
if (slider == null)
|
||||
|
||||
@@ -71,5 +71,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
}
|
||||
|
||||
public virtual void OffsetPosition(Vector2 offset) => Position += offset;
|
||||
|
||||
protected override HitWindows CreateHitWindows() => new OsuHitWindows();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,29 +5,29 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Osu.OsuDifficulty;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Osu.Scoring;
|
||||
using osu.Game.Rulesets.Osu.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.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
|
||||
{
|
||||
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[]
|
||||
{
|
||||
@@ -37,36 +37,6 @@ namespace osu.Game.Rulesets.Osu
|
||||
new KeyBinding(InputKey.MouseRight, OsuAction.RightButton),
|
||||
};
|
||||
|
||||
public override IEnumerable<BeatmapStatistic> GetBeatmapStatistics(WorkingBeatmap beatmap)
|
||||
{
|
||||
IEnumerable<HitObject> hitObjects = beatmap.Beatmap.HitObjects;
|
||||
IEnumerable<HitObject> circles = hitObjects.Where(c => !(c is IHasEndTime));
|
||||
IEnumerable<HitObject> sliders = hitObjects.Where(s => s is IHasCurve);
|
||||
IEnumerable<HitObject> spinners = hitObjects.Where(s => s is IHasEndTime && !(s is IHasCurve));
|
||||
|
||||
return new[]
|
||||
{
|
||||
new BeatmapStatistic
|
||||
{
|
||||
Name = @"Circle Count",
|
||||
Content = circles.Count().ToString(),
|
||||
Icon = FontAwesome.fa_circle_o
|
||||
},
|
||||
new BeatmapStatistic
|
||||
{
|
||||
Name = @"Slider Count",
|
||||
Content = sliders.Count().ToString(),
|
||||
Icon = FontAwesome.fa_circle
|
||||
},
|
||||
new BeatmapStatistic
|
||||
{
|
||||
Name = @"Spinner Count",
|
||||
Content = spinners.Count().ToString(),
|
||||
Icon = FontAwesome.fa_circle
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
||||
{
|
||||
if (mods.HasFlag(LegacyMods.Nightcore))
|
||||
@@ -181,9 +151,9 @@ namespace osu.Game.Rulesets.Osu
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Replays
|
||||
Actions.AddRange(actions);
|
||||
}
|
||||
|
||||
public void ConvertFrom(LegacyReplayFrame legacyFrame, Beatmap beatmap)
|
||||
public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap)
|
||||
{
|
||||
Position = legacyFrame.Position;
|
||||
if (legacyFrame.MouseLeft) Actions.Add(OsuAction.LeftButton);
|
||||
|
||||
@@ -7,7 +7,6 @@ using OpenTK;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Input.Handlers;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Replays;
|
||||
@@ -21,17 +20,13 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
{
|
||||
public class OsuRulesetContainer : RulesetContainer<OsuHitObject>
|
||||
{
|
||||
public OsuRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
||||
: base(ruleset, beatmap, isForCurrentRuleset)
|
||||
public OsuRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor() => new OsuScoreProcessor(this);
|
||||
|
||||
protected override BeatmapConverter<OsuHitObject> CreateBeatmapConverter() => new OsuBeatmapConverter();
|
||||
|
||||
protected override BeatmapProcessor<OsuHitObject> CreateBeatmapProcessor() => new OsuBeatmapProcessor();
|
||||
|
||||
protected override Playfield CreatePlayfield() => new OsuPlayfield();
|
||||
|
||||
public override PassThroughInputManager CreateInputManager() => new OsuInputManager(Ruleset.RulesetInfo);
|
||||
|
||||
+8
-8
@@ -2,13 +2,13 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "VisualTests (Debug, net461)",
|
||||
"name": "VisualTests (Debug, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Taiko.Tests.exe",
|
||||
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Taiko.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
@@ -16,13 +16,13 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, net461)",
|
||||
"name": "VisualTests (Release, net471)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Debug/net461/osu.Game.Rulesets.Taiko.Tests.exe",
|
||||
"program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Taiko.Tests.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, msbuild)",
|
||||
"runtimeExecutable": null,
|
||||
@@ -30,12 +30,12 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Debug, netcoreapp2.0)",
|
||||
"name": "VisualTests (Debug, netcoreapp2.1)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Taiko.Tests.dll"
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Taiko.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug, dotnet)",
|
||||
@@ -43,12 +43,12 @@
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "VisualTests (Release, netcoreapp2.0)",
|
||||
"name": "VisualTests (Release, netcoreapp2.1)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/bin/Debug/netcoreapp2.0/osu.Game.Rulesets.Taiko.Tests.dll"
|
||||
"${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Taiko.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release, dotnet)",
|
||||
|
||||
+6
-6
@@ -9,7 +9,7 @@
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Taiko.Tests.csproj",
|
||||
"/p:TargetFramework=net461",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -24,7 +24,7 @@
|
||||
"args": [
|
||||
"osu.Game.Rulesets.Taiko.Tests.csproj",
|
||||
"/p:Configuration=Release",
|
||||
"/p:TargetFramework=net461",
|
||||
"/p:TargetFramework=net471",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -40,7 +40,7 @@
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Taiko.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.0",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
@@ -56,7 +56,7 @@
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Rulesets.Taiko.Tests.csproj",
|
||||
"/p:TargetFramework=netcoreapp2.0",
|
||||
"/p:TargetFramework=netcoreapp2.1",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
@@ -66,7 +66,7 @@
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (net461)",
|
||||
"label": "Restore (net471)",
|
||||
"type": "shell",
|
||||
"command": "nuget",
|
||||
"args": [
|
||||
@@ -75,7 +75,7 @@
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Restore (netcoreapp2.0)",
|
||||
"label": "Restore (netcoreapp2.1)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
|
||||
@@ -5,27 +5,22 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Tests
|
||||
{
|
||||
public class TaikoBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
internal class TaikoBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
||||
|
||||
private bool isForCurrentRuleset;
|
||||
|
||||
[NonParallelizable]
|
||||
[TestCase("basic", false), Ignore("See: https://github.com/ppy/osu/issues/2152")]
|
||||
[TestCase("slider-generating-drumroll", false)]
|
||||
public void Test(string name, bool isForCurrentRuleset)
|
||||
[TestCase("basic")]
|
||||
[TestCase("slider-generating-drumroll")]
|
||||
public new void Test(string name)
|
||||
{
|
||||
this.isForCurrentRuleset = isForCurrentRuleset;
|
||||
base.Test(name);
|
||||
}
|
||||
|
||||
@@ -43,10 +38,10 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
};
|
||||
}
|
||||
|
||||
protected override IBeatmapConverter CreateConverter(Beatmap beatmap) => new TaikoBeatmapConverter(isForCurrentRuleset);
|
||||
protected override Ruleset CreateRuleset() => new TaikoRuleset();
|
||||
}
|
||||
|
||||
public struct ConvertValue : IEquatable<ConvertValue>
|
||||
internal struct ConvertValue : IEquatable<ConvertValue>
|
||||
{
|
||||
/// <summary>
|
||||
/// A sane value to account for osu!stable using ints everwhere.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user