1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 06:47:24 +08:00

Merge branch 'master' of https://github.com/ppy/osu into Private_Messages

# Conflicts:
#	osu.Game.Tests/Visual/TestCaseChatLink.cs
This commit is contained in:
miterosan 2018-06-17 14:15:14 +02:00
commit cd0fe6a09e
249 changed files with 4244 additions and 3901 deletions

3
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "osu-framework"]
path = osu-framework
url = https://github.com/ppy/osu-framework
[submodule "osu-resources"] [submodule "osu-resources"]
path = osu-resources path = osu-resources
url = https://github.com/ppy/osu-resources url = https://github.com/ppy/osu-resources

View File

@ -1,21 +1,17 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (catch)" type="DotNetProject" factoryName=".NET Project"> <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="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Catch.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" /> <option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests" /> <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests" />
<option name="PASS_PARENT_ENVS" value="1" /> <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="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj" /> <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_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" /> <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" /> <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" /> <option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" /> <option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" /> <browser url="http://localhost:5000" />
<method /> <method />
</configuration> </configuration>

View File

@ -1,21 +1,17 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (mania)" type="DotNetProject" factoryName=".NET Project"> <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="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Mania.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" /> <option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests" /> <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests" />
<option name="PASS_PARENT_ENVS" value="1" /> <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="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj" /> <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_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" /> <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" /> <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" /> <option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" /> <option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" /> <browser url="http://localhost:5000" />
<method /> <method />
</configuration> </configuration>

View File

@ -1,21 +1,17 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (osu!)" type="DotNetProject" factoryName=".NET Project"> <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="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Osu.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" /> <option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests" /> <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests" />
<option name="PASS_PARENT_ENVS" value="1" /> <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="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj" /> <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_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" /> <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" /> <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" /> <option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" /> <option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" /> <browser url="http://localhost:5000" />
<method /> <method />
</configuration> </configuration>

View File

@ -1,21 +1,17 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (taiko)" type="DotNetProject" factoryName=".NET Project"> <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="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Taiko.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" /> <option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests" /> <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests" />
<option name="PASS_PARENT_ENVS" value="1" /> <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="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj" /> <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_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" /> <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" /> <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" /> <option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.1" /> <option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" /> <browser url="http://localhost:5000" />
<method /> <method />
</configuration> </configuration>

View File

@ -1,18 +0,0 @@
<component name="ProjectRunConfigurationManager">
<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" />
<envs />
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Tests/osu.Game.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" />
<method />
</configuration>
</component>

View File

@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="VisualTests (netcoreapp2.0)" type="DotNetProject" factoryName=".NET Project"> <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.0/osu.Game.Tests.dll" /> <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="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests" /> <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests" />
<option name="PASS_PARENT_ENVS" value="1" /> <option name="PASS_PARENT_ENVS" value="1" />
@ -12,7 +12,7 @@
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" /> <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" /> <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" /> <option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.0" /> <option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<method /> <method />
</configuration> </configuration>
</component> </component>

View File

@ -1,18 +0,0 @@
<component name="ProjectRunConfigurationManager">
<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" />
<envs />
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Desktop/osu.Desktop.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" />
<method />
</configuration>
</component>

View File

@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="osu! (netcoreapp2.0)" type="DotNetProject" factoryName=".NET Project"> <configuration default="false" name="osu! (netcoreapp2.1)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp2.0/osu!.dll" /> <option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll" />
<option name="PROGRAM_PARAMETERS" value="" /> <option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop" /> <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop" />
<option name="PASS_PARENT_ENVS" value="1" /> <option name="PASS_PARENT_ENVS" value="1" />
@ -12,7 +12,7 @@
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" /> <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" /> <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" /> <option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.0" /> <option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<method /> <method />
</configuration> </configuration>
</component> </component>

80
.vscode/launch.json vendored
View File

@ -2,110 +2,54 @@
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "VisualTests (Debug, net471)", "name": "VisualTests (Debug)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Game.Tests/bin/Debug/net471/osu.Game.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, msbuild)",
"runtimeExecutable": null,
"env": {},
"console": "internalConsole"
},
{
"name": "VisualTests (Release, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Game.Tests/bin/Release/net471/osu.Game.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null,
"env": {},
"console": "internalConsole"
},
{
"name": "osu! (Debug, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/net471/osu!.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, msbuild)",
"runtimeExecutable": null,
"env": {},
"console": "internalConsole"
},
{
"name": "osu! (Release, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/osu.Desktop/bin/Release/net471/osu!.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null,
"env": {},
"console": "internalConsole"
},
{
"name": "VisualTests (Debug, netcoreapp2.0)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
"args": [ "args": [
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll" "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.1/osu.Game.Tests.dll"
], ],
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build tests (Debug, dotnet)", "preLaunchTask": "Build tests (Debug)",
"env": {}, "env": {},
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "VisualTests (Release, netcoreapp2.0)", "name": "VisualTests (Release)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
"args": [ "args": [
"${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.0/osu.Game.Tests.dll" "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.1/osu.Game.Tests.dll"
], ],
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build tests (Release, dotnet)", "preLaunchTask": "Build tests (Release)",
"env": {}, "env": {},
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "osu! (Debug, netcoreapp2.0)", "name": "osu! (Debug)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
"args": [ "args": [
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.0/osu!.dll", "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll",
], ],
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Debug, dotnet)", "preLaunchTask": "Build osu! (Debug)",
"env": {}, "env": {},
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "osu! (Release, netcoreapp2.0)", "name": "osu! (Release)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
"args": [ "args": [
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.0/osu!.dll", "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1/osu!.dll",
], ],
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Release, dotnet)", "preLaunchTask": "Build osu! (Release)",
"env": {}, "env": {},
"console": "internalConsole" "console": "internalConsole"
} }

54
.vscode/tasks.json vendored
View File

@ -4,41 +4,14 @@
"version": "2.0.0", "version": "2.0.0",
"tasks": [ "tasks": [
{ {
"label": "Build (Debug, msbuild)", "label": "Build osu! (Debug)",
"type": "shell",
"command": "msbuild",
"args": [
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Build (Release, msbuild)",
"type": "shell",
"command": "msbuild",
"args": [
"/p:Configuration=Release",
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Build osu! (Debug, dotnet)",
"type": "shell", "type": "shell",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [
"build", "build",
"--no-restore", "--no-restore",
"osu.Desktop", "osu.Desktop",
"/p:TargetFramework=netcoreapp2.0", "/p:TargetFramework=netcoreapp2.1",
"/p:GenerateFullPaths=true", "/p:GenerateFullPaths=true",
"/m", "/m",
"/verbosity:m" "/verbosity:m"
@ -47,14 +20,14 @@
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "Build osu! (Release, dotnet)", "label": "Build osu! (Release)",
"type": "shell", "type": "shell",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [
"build", "build",
"--no-restore", "--no-restore",
"osu.Desktop", "osu.Desktop",
"/p:TargetFramework=netcoreapp2.0", "/p:TargetFramework=netcoreapp2.1",
"/p:Configuration=Release", "/p:Configuration=Release",
"/p:GenerateFullPaths=true", "/p:GenerateFullPaths=true",
"/m", "/m",
@ -64,14 +37,14 @@
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "Build tests (Debug, dotnet)", "label": "Build tests (Debug)",
"type": "shell", "type": "shell",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [
"build", "build",
"--no-restore", "--no-restore",
"osu.Game.Tests", "osu.Game.Tests",
"/p:TargetFramework=netcoreapp2.0", "/p:TargetFramework=netcoreapp2.1",
"/p:GenerateFullPaths=true", "/p:GenerateFullPaths=true",
"/m", "/m",
"/verbosity:m" "/verbosity:m"
@ -80,14 +53,14 @@
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "Build tests (Release, dotnet)", "label": "Build tests (Release)",
"type": "shell", "type": "shell",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [
"build", "build",
"--no-restore", "--no-restore",
"osu.Game.Tests", "osu.Game.Tests",
"/p:TargetFramework=netcoreapp2.0", "/p:TargetFramework=netcoreapp2.1",
"/p:Configuration=Release", "/p:Configuration=Release",
"/p:GenerateFullPaths=true", "/p:GenerateFullPaths=true",
"/m", "/m",
@ -97,16 +70,7 @@
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "Restore (net471)", "label": "Restore (netcoreapp2.1)",
"type": "shell",
"command": "nuget",
"args": [
"restore"
],
"problemMatcher": []
},
{
"label": "Restore (netcoreapp2.0)",
"type": "shell", "type": "shell",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [

View File

@ -1,36 +0,0 @@
# Linux
### 1. Requirements:
Mono >= 5.4.0 (>= 5.8.0 recommended)
Please check [here](http://www.mono-project.com/download/) for stable or [here](http://www.mono-project.com/download/alpha/) for an alpha release.
NuGet >= 4.4.0
msbuild
git
### 2. Cloning project
Clone the entire repository with submodules using
```
git clone https://github.com/ppy/osu --recursive
```
Then restore NuGet packages from the repository
```
nuget restore
```
### 3. Compiling
Simply run `msbuild` where `osu.sln` is located, this will create all binaries in `osu/osu.Desktop/bin/Debug`.
### 4. Optimizing
If you want additional performance you can change build type to Release with
```
msbuild -p:Configuration=Release
```
Additionally, mono provides an AOT utility which attempts to precompile binaries. You can utilize that by running
```
mono --aot ./osu\!.exe
```
### 5. Troubleshooting
You may run into trouble with NuGet versioning, as the one in packaging system is almost always out of date. Simply run
```
nuget
sudo nuget update -self
```
**Warning** NuGet creates few config files when it's run for the first time.
Do not run NuGet as root on the first run or you might run into very peculiar issues.

View File

@ -2,11 +2,6 @@ clone_depth: 1
version: '{branch}-{build}' version: '{branch}-{build}'
image: Visual Studio 2017 image: Visual Studio 2017
configuration: Debug configuration: Debug
cache:
- C:\ProgramData\chocolatey\bin -> appveyor.yml
- C:\ProgramData\chocolatey\lib -> appveyor.yml
- inspectcode -> appveyor.yml
- packages -> **\packages.config
install: install:
- cmd: git submodule update --init --recursive --depth=5 - cmd: git submodule update --init --recursive --depth=5
- cmd: choco install resharper-clt -y - cmd: choco install resharper-clt -y

View File

@ -1,29 +1,24 @@
branches:
only:
- release
skip_tags: true
skip_branch_with_pr: true
clone_depth: 1 clone_depth: 1
version: '{branch}-{build}' version: '{build}'
skip_non_tags: true
image: Visual Studio 2017 image: Visual Studio 2017
configuration: Debug
cache:
- packages -> **\packages.config
install: install:
- cmd: git submodule update --init --recursive --depth=5 - git clone https://github.com/ppy/osu-deploy
before_build: 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 - cmd: nuget restore -verbosity quiet
build: build_script:
project: osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
verbosity: minimal
after_build:
- ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1')) - 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 - 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 - 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 - appveyor DownloadFile https://puu.sh/A6g75/fdc6f19b04.enc # deploy configuration
- cmd: appveyor-tools\secure-file -decrypt fdc6f19b04.enc -secret %decode_secret% -out osu.Desktop.Deploy\bin\Debug\net471\osu.Desktop.Deploy.exe.config - cd osu-deploy
- cd osu.Desktop.Deploy\bin\Debug\net471\ - nuget restore -verbosity quiet
- osu.Desktop.Deploy.exe %code_signing_password% - msbuild osu.Desktop.Deploy.csproj
- cmd: ..\appveyor-tools\secure-file -decrypt ..\fdc6f19b04.enc -secret %decode_secret% -out bin\Debug\net471\osu.Desktop.Deploy.exe.config
- cd bin\Debug\net471\
- osu.Desktop.Deploy.exe %code_signing_password% %APPVEYOR_REPO_TAG_NAME%
environment: environment:
TargetFramework: net471 TargetFramework: net471
decode_secret: decode_secret:
@ -32,3 +27,6 @@ environment:
secure: 34tLNqvjmmZEi97MLKfrnQ== secure: 34tLNqvjmmZEi97MLKfrnQ==
artifacts: artifacts:
- path: 'Releases\*' - path: 'Releases\*'
deploy:
- provider: Environment
name: github

@ -1 +0,0 @@
Subproject commit aebfa5bc5c634c1fd0c103e0c17518e5111a67c7

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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.8.0\tools\Squirrel.exe");
private const string msbuild_path = @"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe";
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)} --framework-version=net471 --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}";
}
}

View File

@ -1,19 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\osu.Game.props" />
<PropertyGroup Label="Project">
<TargetFrameworks>net471</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.8.0" Condition="'$(TargetFramework)' == 'net471'" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.4.0" />
<PackageReference Include="System.Management.Automation.dll" Version="10.0.10586" />
</ItemGroup>
</Project>

View File

@ -3,7 +3,6 @@
using System.Diagnostics; using System.Diagnostics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Development;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
@ -14,6 +13,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Notifications;
using osu.Game.Utils;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
@ -118,7 +118,7 @@ namespace osu.Desktop.Overlays
Icon = FontAwesome.fa_check_square; Icon = FontAwesome.fa_check_square;
Activated = delegate Activated = delegate
{ {
Process.Start($"https://github.com/ppy/osu/releases/tag/v{version}"); Process.Start($"https://osu.ppy.sh/home/changelog/{version}");
return true; return true;
}; };
} }

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\osu.Game.props" /> <Import Project="..\osu.Game.props" />
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">
<TargetFrameworks>net471;netcoreapp2.0</TargetFrameworks> <TargetFrameworks>net471;netcoreapp2.1</TargetFrameworks>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@ -20,26 +20,19 @@
<StartupObject>osu.Desktop.Program</StartupObject> <StartupObject>osu.Desktop.Program</StartupObject>
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Project References"> <ItemGroup Label="Project References">
<!-- This can be removed after .NET Core SDK version 2.1.300; see https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet -->
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.3" />
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj" />
<ProjectReference Include="..\osu.Game\osu.Game.csproj" /> <ProjectReference Include="..\osu.Game\osu.Game.csproj" />
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" /> <ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" /> <ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" /> <ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" /> <ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" /> <ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" /> <PackageReference Include="Microsoft.Win32.Registry" Version="4.5.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0" />
<PackageReference Include="squirrel.windows" Version="1.8.0" Condition="'$(TargetFramework)' == 'net471'" /> <PackageReference Include="squirrel.windows" Version="1.8.0" Condition="'$(TargetFramework)' == 'net471'" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Resources"> <ItemGroup Label="Resources">
<EmbeddedResource Include="lazer.ico" /> <EmbeddedResource Include="lazer.ico" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<!-- This can be removed after .NET Core SDK version 2.1.300; see https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet -->
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
</ItemGroup>
</Project> </Project>

View File

@ -22,7 +22,7 @@
}, },
"type": "mono", "type": "mono",
"request": "launch", "request": "launch",
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Catch.Tests.exe", "program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Catch.Tests.exe",
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)", "preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null, "runtimeExecutable": null,
@ -30,12 +30,12 @@
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "VisualTests (Debug, netcoreapp2.0)", "name": "VisualTests (Debug, netcoreapp2.1)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
"args": [ "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}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, dotnet)", "preLaunchTask": "Build (Debug, dotnet)",
@ -43,12 +43,12 @@
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "VisualTests (Release, netcoreapp2.0)", "name": "VisualTests (Release, netcoreapp2.1)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
"args": [ "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}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, dotnet)", "preLaunchTask": "Build (Release, dotnet)",

View File

@ -40,7 +40,7 @@
"build", "build",
"--no-restore", "--no-restore",
"osu.Game.Rulesets.Catch.Tests.csproj", "osu.Game.Rulesets.Catch.Tests.csproj",
"/p:TargetFramework=netcoreapp2.0", "/p:TargetFramework=netcoreapp2.1",
"/p:GenerateFullPaths=true", "/p:GenerateFullPaths=true",
"/m", "/m",
"/verbosity:m" "/verbosity:m"
@ -56,7 +56,7 @@
"build", "build",
"--no-restore", "--no-restore",
"osu.Game.Rulesets.Catch.Tests.csproj", "osu.Game.Rulesets.Catch.Tests.csproj",
"/p:TargetFramework=netcoreapp2.0", "/p:TargetFramework=netcoreapp2.1",
"/p:Configuration=Release", "/p:Configuration=Release",
"/p:GenerateFullPaths=true", "/p:GenerateFullPaths=true",
"/m", "/m",
@ -75,7 +75,7 @@
"problemMatcher": [] "problemMatcher": []
}, },
{ {
"label": "Restore (netcoreapp2.0)", "label": "Restore (netcoreapp2.1)",
"type": "shell", "type": "shell",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [

View File

@ -53,10 +53,10 @@ namespace osu.Game.Rulesets.Catch.Tests
return beatmap; return beatmap;
} }
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) protected override Player CreatePlayer(Ruleset ruleset)
{ {
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }); Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
return base.CreatePlayer(beatmap, ruleset); return base.CreatePlayer(ruleset);
} }
} }
} }

View File

@ -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 NUnit.Framework;
namespace osu.Game.Rulesets.Catch.Tests
{
[TestFixture]
public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints
{
public TestCasePerformancePoints()
: base(new CatchRuleset())
{
}
}
}

View File

@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" /> <Import Project="..\osu.TestProject.props" />
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFrameworks>netcoreapp2.0;net471</TargetFrameworks> <TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Project References"> <ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" /> <ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />

View File

@ -82,56 +82,25 @@ namespace osu.Game.Rulesets.Catch
{ {
new CatchModEasy(), new CatchModEasy(),
new CatchModNoFail(), new CatchModNoFail(),
new MultiMod new MultiMod(new CatchModHalfTime(), new CatchModDaycore())
{
Mods = new Mod[]
{
new CatchModHalfTime(),
new CatchModDaycore(),
},
},
}; };
case ModType.DifficultyIncrease: case ModType.DifficultyIncrease:
return new Mod[] return new Mod[]
{ {
new CatchModHardRock(), new CatchModHardRock(),
new MultiMod new MultiMod(new CatchModSuddenDeath(), new CatchModPerfect()),
{ new MultiMod(new CatchModDoubleTime(), new CatchModNightcore()),
Mods = new Mod[]
{
new CatchModSuddenDeath(),
new CatchModPerfect(),
},
},
new MultiMod
{
Mods = new Mod[]
{
new CatchModDoubleTime(),
new CatchModNightcore(),
},
},
new CatchModHidden(), new CatchModHidden(),
new CatchModFlashlight(), new CatchModFlashlight(),
}; };
case ModType.Special: case ModType.Special:
return new Mod[] return new Mod[]
{ {
new CatchModRelax(), new CatchModRelax(),
null, null,
null, null,
new MultiMod new MultiMod(new CatchModAutoplay(), new ModCinema()),
{
Mods = new Mod[]
{
new CatchModAutoplay(),
new ModCinema(),
},
},
}; };
default: default:
return new Mod[] { }; return new Mod[] { };
} }
@ -143,7 +112,7 @@ namespace osu.Game.Rulesets.Catch
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o }; public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o };
public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap); public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(this, beatmap);
public override int? LegacyID => 2; public override int? LegacyID => 2;

View File

@ -1,18 +1,19 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Difficulty namespace osu.Game.Rulesets.Catch.Difficulty
{ {
public class CatchDifficultyCalculator : DifficultyCalculator public class CatchDifficultyCalculator : DifficultyCalculator
{ {
public CatchDifficultyCalculator(IBeatmap beatmap) : base(beatmap) public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
: base(ruleset, beatmap)
{ {
} }
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) => 0; protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) => new DifficultyAttributes(mods, 0);
} }
} }

View File

@ -42,6 +42,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{ {
public virtual bool CanBePlated => false; public virtual bool CanBePlated => false;
public virtual bool StaysOnPlate => CanBePlated;
protected DrawableCatchHitObject(CatchHitObject hitObject) protected DrawableCatchHitObject(CatchHitObject hitObject)
: base(hitObject) : base(hitObject)
{ {

View File

@ -13,6 +13,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{ {
private Pulp pulp; private Pulp pulp;
public override bool StaysOnPlate => false;
public DrawableDroplet(Droplet h) public DrawableDroplet(Droplet h)
: base(h) : base(h)
{ {

View File

@ -124,6 +124,9 @@ namespace osu.Game.Rulesets.Catch.Objects
X = X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH X = X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH
}); });
} }
if (NestedHitObjects.LastOrDefault() is IHasComboInformation lastNested)
lastNested.LastInCombo = LastInCombo;
} }
public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity; public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity;

View File

@ -48,6 +48,16 @@ namespace osu.Game.Rulesets.Catch.UI
public void OnJudgement(DrawableCatchHitObject fruit, Judgement judgement) public void OnJudgement(DrawableCatchHitObject fruit, Judgement judgement)
{ {
void runAfterLoaded(Action action)
{
// this is required to make this run after the last caught fruit runs UpdateState at least once.
// TODO: find a better alternative
if (lastPlateableFruit.IsLoaded)
action();
else
lastPlateableFruit.OnLoadComplete = _ => action();
}
if (judgement.IsHit && fruit.CanBePlated) if (judgement.IsHit && fruit.CanBePlated)
{ {
var caughtFruit = (DrawableCatchHitObject)GetVisualRepresentation?.Invoke(fruit.HitObject); var caughtFruit = (DrawableCatchHitObject)GetVisualRepresentation?.Invoke(fruit.HitObject);
@ -63,21 +73,17 @@ namespace osu.Game.Rulesets.Catch.UI
caughtFruit.LifetimeEnd = double.MaxValue; caughtFruit.LifetimeEnd = double.MaxValue;
MovableCatcher.Add(caughtFruit); MovableCatcher.Add(caughtFruit);
lastPlateableFruit = caughtFruit; lastPlateableFruit = caughtFruit;
if (!fruit.StaysOnPlate)
runAfterLoaded(() => MovableCatcher.Explode(caughtFruit));
} }
if (fruit.HitObject.LastInCombo) if (fruit.HitObject.LastInCombo)
{ {
if (judgement.IsHit) if (judgement.IsHit)
{ runAfterLoaded(() => MovableCatcher.Explode());
// this is required to make this run after the last caught fruit runs UpdateState at least once.
// TODO: find a better alternative
if (lastPlateableFruit.IsLoaded)
MovableCatcher.Explode();
else
lastPlateableFruit.OnLoadComplete = _ => { MovableCatcher.Explode(); };
}
else else
MovableCatcher.Drop(); MovableCatcher.Drop();
} }
@ -378,28 +384,31 @@ namespace osu.Game.Rulesets.Catch.UI
var fruit = caughtFruit.ToArray(); var fruit = caughtFruit.ToArray();
foreach (var f in fruit) foreach (var f in fruit)
Explode(f);
}
public void Explode(DrawableHitObject fruit)
{
var originalX = fruit.X * Scale.X;
if (ExplodingFruitTarget != null)
{ {
var originalX = f.X * Scale.X; fruit.Anchor = Anchor.TopLeft;
fruit.Position = caughtFruit.ToSpaceOfOtherDrawable(fruit.DrawPosition, ExplodingFruitTarget);
if (ExplodingFruitTarget != null) caughtFruit.Remove(fruit);
{
f.Anchor = Anchor.TopLeft;
f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget);
caughtFruit.Remove(f); ExplodingFruitTarget.Add(fruit);
ExplodingFruitTarget.Add(f);
}
f.MoveToY(f.Y - 50, 250, Easing.OutSine)
.Then()
.MoveToY(f.Y + 50, 500, Easing.InSine);
f.MoveToX(f.X + originalX * 6, 1000);
f.FadeOut(750);
f.Expire();
} }
fruit.MoveToY(fruit.Y - 50, 250, Easing.OutSine)
.Then()
.MoveToY(fruit.Y + 50, 500, Easing.InSine);
fruit.MoveToX(fruit.X + originalX * 6, 1000);
fruit.FadeOut(750);
fruit.Expire();
} }
private class CatcherSprite : Sprite private class CatcherSprite : Sprite

View File

@ -22,7 +22,7 @@
}, },
"type": "mono", "type": "mono",
"request": "launch", "request": "launch",
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Mania.Tests.exe", "program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Mania.Tests.exe",
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)", "preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null, "runtimeExecutable": null,
@ -30,12 +30,12 @@
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "VisualTests (Debug, netcoreapp2.0)", "name": "VisualTests (Debug, netcoreapp2.1)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
"args": [ "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}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, dotnet)", "preLaunchTask": "Build (Debug, dotnet)",
@ -43,12 +43,12 @@
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "VisualTests (Release, netcoreapp2.0)", "name": "VisualTests (Release, netcoreapp2.1)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
"args": [ "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}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, dotnet)", "preLaunchTask": "Build (Release, dotnet)",

View File

@ -40,7 +40,7 @@
"build", "build",
"--no-restore", "--no-restore",
"osu.Game.Rulesets.Mania.Tests.csproj", "osu.Game.Rulesets.Mania.Tests.csproj",
"/p:TargetFramework=netcoreapp2.0", "/p:TargetFramework=netcoreapp2.1",
"/p:GenerateFullPaths=true", "/p:GenerateFullPaths=true",
"/m", "/m",
"/verbosity:m" "/verbosity:m"
@ -56,7 +56,7 @@
"build", "build",
"--no-restore", "--no-restore",
"osu.Game.Rulesets.Mania.Tests.csproj", "osu.Game.Rulesets.Mania.Tests.csproj",
"/p:TargetFramework=netcoreapp2.0", "/p:TargetFramework=netcoreapp2.1",
"/p:Configuration=Release", "/p:Configuration=Release",
"/p:GenerateFullPaths=true", "/p:GenerateFullPaths=true",
"/m", "/m",
@ -75,7 +75,7 @@
"problemMatcher": [] "problemMatcher": []
}, },
{ {
"label": "Restore (netcoreapp2.0)", "label": "Restore (netcoreapp2.1)",
"type": "shell", "type": "shell",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [

View File

@ -98,17 +98,12 @@ namespace osu.Game.Rulesets.Mania.Tests
}); });
} }
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(RulesetStore rulesets, SettingsStore settings) private void load(RulesetStore rulesets, SettingsStore settings)
{ {
maniaRuleset = rulesets.GetRuleset(3); maniaRuleset = rulesets.GetRuleset(3);
dependencies.Cache(new ManiaConfigManager(settings, maniaRuleset, 4)); Dependencies.Cache(new ManiaConfigManager(settings, maniaRuleset, 4));
} }
private ManiaPlayfield createPlayfield(int cols, bool inverted = false) private ManiaPlayfield createPlayfield(int cols, bool inverted = false)

View File

@ -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 NUnit.Framework;
namespace osu.Game.Rulesets.Mania.Tests
{
[TestFixture]
public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints
{
public TestCasePerformancePoints()
: base(new ManiaRuleset())
{
}
}
}

View File

@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" /> <Import Project="..\osu.TestProject.props" />
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFrameworks>netcoreapp2.0;net471</TargetFrameworks> <TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Project References"> <ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" /> <ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />

View File

@ -58,6 +58,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
public override Pattern Generate() public override Pattern Generate()
{ {
if (TotalColumns == 1)
{
var pattern = new Pattern();
addToPattern(pattern, 0, HitObject.StartTime, endTime);
return pattern;
}
if (spanCount > 1) if (spanCount > 1)
{ {
if (segmentDuration <= 90) if (segmentDuration <= 90)

View File

@ -77,10 +77,25 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
} }
else else
convertType |= PatternType.LowProbability; convertType |= PatternType.LowProbability;
if ((convertType & PatternType.KeepSingle) == 0)
{
if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && TotalColumns != 8)
convertType |= PatternType.Mirror;
else
convertType |= PatternType.Gathered;
}
} }
public override Pattern Generate() public override Pattern Generate()
{ {
if (TotalColumns == 1)
{
var pattern = new Pattern();
addToPattern(pattern, 0);
return pattern;
}
int lastColumn = PreviousPattern.HitObjects.FirstOrDefault()?.Column ?? 0; int lastColumn = PreviousPattern.HitObjects.FirstOrDefault()?.Column ?? 0;
if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Any()) if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Any())
@ -346,7 +361,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
addToCentre = false; addToCentre = false;
if ((convertType & PatternType.ForceNotStack) > 0) if ((convertType & PatternType.ForceNotStack) > 0)
return getRandomNoteCount(p2 / 2, p2, (p2 + p3) / 2, p3); return getRandomNoteCount(1 / 2f + p2 / 2, p2, (p2 + p3) / 2, p3);
switch (TotalColumns) switch (TotalColumns)
{ {

View File

@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Mania.Configuration
{ {
public class ManiaConfigManager : RulesetConfigManager<ManiaSetting> public class ManiaConfigManager : RulesetConfigManager<ManiaSetting>
{ {
public ManiaConfigManager(SettingsStore settings, RulesetInfo ruleset, int variant) public ManiaConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null)
: base(settings, ruleset, variant) : base(settings, ruleset, variant)
{ {
} }

View File

@ -7,6 +7,7 @@ using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
@ -28,47 +29,33 @@ namespace osu.Game.Rulesets.Mania.Difficulty
/// </summary> /// </summary>
private const double decay_weight = 0.9; private const double decay_weight = 0.9;
/// <summary> public ManiaDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
/// HitObjects are stored as a member variable. : base(ruleset, beatmap)
/// </summary>
private readonly List<ManiaHitObjectDifficulty> difficultyHitObjects = new List<ManiaHitObjectDifficulty>();
public ManiaDifficultyCalculator(IBeatmap beatmap)
: base(beatmap)
{ {
} }
public ManiaDifficultyCalculator(IBeatmap beatmap, Mod[] mods) protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate)
: base(beatmap, mods)
{ {
} var difficultyHitObjects = new List<ManiaHitObjectDifficulty>();
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) int columnCount = ((ManiaBeatmap)beatmap).TotalColumns;
{
// Fill our custom DifficultyHitObject class, that carries additional information
difficultyHitObjects.Clear();
int columnCount = (Beatmap as ManiaBeatmap)?.TotalColumns ?? 7;
// Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure. // Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure.
// Note: Stable sort is done so that the ordering of hitobjects with equal start times doesn't change // 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)); difficultyHitObjects.AddRange(beatmap.HitObjects.Select(h => new ManiaHitObjectDifficulty((ManiaHitObject)h, columnCount)).OrderBy(h => h.BaseHitObject.StartTime));
if (!calculateStrainValues()) if (!calculateStrainValues(difficultyHitObjects, timeRate))
return 0; return new DifficultyAttributes(mods, 0);
double starRating = calculateDifficulty() * star_scaling_factor; double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor;
if (categoryDifficulty != null) return new DifficultyAttributes(mods, starRating);
categoryDifficulty["Strain"] = starRating;
return starRating;
} }
private bool calculateStrainValues() private bool calculateStrainValues(List<ManiaHitObjectDifficulty> objects, double timeRate)
{ {
// Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment.
using (List<ManiaHitObjectDifficulty>.Enumerator hitObjectsEnumerator = difficultyHitObjects.GetEnumerator()) using (var hitObjectsEnumerator = objects.GetEnumerator())
{ {
if (!hitObjectsEnumerator.MoveNext()) if (!hitObjectsEnumerator.MoveNext())
return false; return false;
@ -79,7 +66,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
while (hitObjectsEnumerator.MoveNext()) while (hitObjectsEnumerator.MoveNext())
{ {
var next = hitObjectsEnumerator.Current; var next = hitObjectsEnumerator.Current;
next?.CalculateStrains(current, TimeRate); next?.CalculateStrains(current, timeRate);
current = next; current = next;
} }
@ -87,9 +74,9 @@ namespace osu.Game.Rulesets.Mania.Difficulty
} }
} }
private double calculateDifficulty() private double calculateDifficulty(List<ManiaHitObjectDifficulty> objects, double timeRate)
{ {
double actualStrainStep = strain_step * TimeRate; double actualStrainStep = strain_step * timeRate;
// Find the highest strain value within each strain step // Find the highest strain value within each strain step
List<double> highestStrains = new List<double>(); List<double> highestStrains = new List<double>();
@ -97,7 +84,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval
ManiaHitObjectDifficulty previousHitObject = null; ManiaHitObjectDifficulty previousHitObject = null;
foreach (var hitObject in difficultyHitObjects) foreach (var hitObject in objects)
{ {
// While we are beyond the current interval push the currently available maximum to our strain list // While we are beyond the current interval push the currently available maximum to our strain list
while (hitObject.BaseHitObject.StartTime > intervalEndTime) while (hitObject.BaseHitObject.StartTime > intervalEndTime)
@ -141,5 +128,23 @@ namespace osu.Game.Rulesets.Mania.Difficulty
return difficulty; return difficulty;
} }
protected override Mod[] DifficultyAdjustmentMods => new Mod[]
{
new ManiaModDoubleTime(),
new ManiaModHalfTime(),
new ManiaModEasy(),
new ManiaModHardRock(),
new ManiaModKey1(),
new ManiaModKey2(),
new ManiaModKey3(),
new ManiaModKey4(),
new ManiaModKey5(),
new ManiaModKey6(),
new ManiaModKey7(),
new ManiaModKey8(),
new ManiaModKey9(),
};
} }
} }

View File

@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
private int countMeh; private int countMeh;
private int countMiss; private int countMiss;
public ManiaPerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score) public ManiaPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score)
: base(ruleset, beatmap, score) : base(ruleset, beatmap, score)
{ {
} }
@ -82,7 +82,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
private double computeStrainValue() private double computeStrainValue()
{ {
// Obtain strain difficulty // Obtain strain difficulty
double strainValue = Math.Pow(5 * Math.Max(1, Attributes["Strain"] / 0.2) - 4.0, 2.2) / 135.0; double strainValue = Math.Pow(5 * Math.Max(1, Attributes.StarRating / 0.2) - 4.0, 2.2) / 135.0;
// Longer maps are worth more // Longer maps are worth more
strainValue *= 1.0 + 0.1 * Math.Min(1.0, totalHits / 1500.0); strainValue *= 1.0 + 0.1 * Math.Min(1.0, totalHits / 1500.0);

View File

@ -15,8 +15,11 @@ using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Replays.Types; using osu.Game.Rulesets.Replays.Types;
using osu.Game.Beatmaps.Legacy; using osu.Game.Beatmaps.Legacy;
using osu.Game.Configuration;
using osu.Game.Rulesets.Configuration;
using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.Difficulty; using osu.Game.Rulesets.Mania.Difficulty;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -26,7 +29,7 @@ namespace osu.Game.Rulesets.Mania
{ {
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap) => new ManiaRulesetContainer(this, beatmap); public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap) => new ManiaRulesetContainer(this, beatmap);
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(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 PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new ManiaPerformanceCalculator(this, beatmap, score);
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods) public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
{ {
@ -105,78 +108,34 @@ namespace osu.Game.Rulesets.Mania
{ {
new ManiaModEasy(), new ManiaModEasy(),
new ManiaModNoFail(), new ManiaModNoFail(),
new MultiMod new MultiMod(new ManiaModHalfTime(), new ManiaModDaycore()),
{
Mods = new Mod[]
{
new ManiaModHalfTime(),
new ManiaModDaycore(),
},
},
}; };
case ModType.DifficultyIncrease: case ModType.DifficultyIncrease:
return new Mod[] return new Mod[]
{ {
new ManiaModHardRock(), new ManiaModHardRock(),
new MultiMod new MultiMod(new ManiaModSuddenDeath(), new ManiaModPerfect()),
{ new MultiMod(new ManiaModDoubleTime(), new ManiaModNightcore()),
Mods = new Mod[] new MultiMod(new ManiaModFadeIn(), new ManiaModHidden()),
{
new ManiaModSuddenDeath(),
new ManiaModPerfect(),
},
},
new MultiMod
{
Mods = new Mod[]
{
new ManiaModDoubleTime(),
new ManiaModNightcore(),
},
},
new MultiMod
{
Mods = new Mod[]
{
new ManiaModFadeIn(),
new ManiaModHidden(),
}
},
new ManiaModFlashlight(), new ManiaModFlashlight(),
}; };
case ModType.Special: case ModType.Special:
return new Mod[] return new Mod[]
{ {
new MultiMod new MultiMod(new ManiaModKey4(),
{ new ManiaModKey5(),
Mods = new Mod[] new ManiaModKey6(),
{ new ManiaModKey7(),
new ManiaModKey4(), new ManiaModKey8(),
new ManiaModKey5(), new ManiaModKey9(),
new ManiaModKey6(), new ManiaModKey1(),
new ManiaModKey7(), new ManiaModKey2(),
new ManiaModKey8(), new ManiaModKey3()),
new ManiaModKey9(),
new ManiaModKey1(),
new ManiaModKey2(),
new ManiaModKey3(),
},
},
new ManiaModRandom(), new ManiaModRandom(),
new ManiaModDualStages(), new ManiaModDualStages(),
new ManiaModMirror(), new ManiaModMirror(),
new MultiMod new MultiMod(new ManiaModAutoplay(), new ModCinema()),
{
Mods = new Mod[]
{
new ManiaModAutoplay(),
new ModCinema(),
},
},
}; };
default: default:
return new Mod[] { }; return new Mod[] { };
} }
@ -188,12 +147,14 @@ namespace osu.Game.Rulesets.Mania
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o }; public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o };
public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap, mods); public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new ManiaDifficultyCalculator(this, beatmap);
public override int? LegacyID => 3; public override int? LegacyID => 3;
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame(); public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame();
public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new ManiaConfigManager(settings, RulesetInfo);
public ManiaRuleset(RulesetInfo rulesetInfo = null) public ManiaRuleset(RulesetInfo rulesetInfo = null)
: base(rulesetInfo) : base(rulesetInfo)
{ {

View File

@ -1,6 +1,8 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
@ -24,5 +26,18 @@ namespace osu.Game.Rulesets.Mania.Mods
mbc.TargetColumns = KeyCount; mbc.TargetColumns = KeyCount;
} }
public override Type[] IncompatibleMods => new[]
{
typeof(ManiaModKey1),
typeof(ManiaModKey2),
typeof(ManiaModKey3),
typeof(ManiaModKey4),
typeof(ManiaModKey5),
typeof(ManiaModKey6),
typeof(ManiaModKey7),
typeof(ManiaModKey8),
typeof(ManiaModKey9),
}.Except(new[] { GetType() }).ToArray();
} }
} }

View File

@ -5,6 +5,7 @@ using OpenTK;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Mania.Objects.Drawables namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
@ -28,7 +29,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
: base(barLine) : base(barLine)
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Height = 1; Height = 2f;
AddInternal(new Box AddInternal(new Box
{ {
@ -36,6 +37,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
Anchor = Anchor.BottomCentre, Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre, Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = new Color4(255, 204, 33, 255),
}); });
bool isMajor = barLine.BeatIndex % (int)barLine.ControlPoint.TimeSignature == 0; bool isMajor = barLine.BeatIndex % (int)barLine.ControlPoint.TimeSignature == 0;

View File

@ -2,7 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq; using System.Linq;
using osu.Game.Rulesets.Objects.Drawables; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using OpenTK.Graphics; using OpenTK.Graphics;
@ -23,9 +23,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
private readonly DrawableNote head; private readonly DrawableNote head;
private readonly DrawableNote tail; private readonly DrawableNote tail;
private readonly GlowPiece glowPiece;
private readonly BodyPiece bodyPiece; private readonly BodyPiece bodyPiece;
private readonly Container fullHeightContainer;
/// <summary> /// <summary>
/// Time at which the user started holding this hold note. Null if the user is not holding this hold note. /// Time at which the user started holding this hold note. Null if the user is not holding this hold note.
@ -37,25 +35,17 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary> /// </summary>
private bool hasBroken; private bool hasBroken;
private readonly Container<DrawableHoldNoteTick> tickContainer;
public DrawableHoldNote(HoldNote hitObject, ManiaAction action) public DrawableHoldNote(HoldNote hitObject, ManiaAction action)
: base(hitObject, action) : base(hitObject, action)
{ {
Container<DrawableHoldNoteTick> tickContainer;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
// The hit object itself cannot be used for various elements because the tail overshoots it
// So a specialized container that is updated to contain the tail height is used
fullHeightContainer = new Container
{
RelativeSizeAxes = Axes.X,
Child = glowPiece = new GlowPiece()
},
bodyPiece = new BodyPiece bodyPiece = new BodyPiece
{ {
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
}, },
tickContainer = new Container<DrawableHoldNoteTick> tickContainer = new Container<DrawableHoldNoteTick>
@ -92,21 +82,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
base.AccentColour = value; base.AccentColour = value;
glowPiece.AccentColour = value;
bodyPiece.AccentColour = value; bodyPiece.AccentColour = value;
head.AccentColour = value; head.AccentColour = value;
tail.AccentColour = value; tail.AccentColour = value;
} tickContainer.ForEach(t => t.AccentColour = value);
}
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;
} }
} }
@ -121,12 +100,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
base.Update(); base.Update();
// Make the body piece not lie under the head note // Make the body piece not lie under the head note
bodyPiece.Y = head.Height; bodyPiece.Y = head.Height / 2;
bodyPiece.Height = DrawHeight - head.Height; bodyPiece.Height = DrawHeight - head.Height / 2 + tail.Height / 2;
// Make the fullHeightContainer "contain" the height of the tail note, keeping in mind
// that the tail note overshoots the height of this hit object
fullHeightContainer.Height = DrawHeight + tail.Height;
} }
public bool OnPressed(ManiaAction action) public bool OnPressed(ManiaAction action)
@ -175,8 +150,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
: base(holdNote.HitObject.Head, action) : base(holdNote.HitObject.Head, action)
{ {
this.holdNote = holdNote; this.holdNote = holdNote;
GlowPiece.Alpha = 0;
} }
public override bool OnPressed(ManiaAction action) public override bool OnPressed(ManiaAction action)
@ -194,11 +167,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
return true; return true;
} }
protected override void UpdateState(ArmedState state)
{
// The holdnote keeps scrolling through for now, so having the head disappear looks weird
}
} }
/// <summary> /// <summary>
@ -219,8 +187,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
: base(holdNote.HitObject.Tail, action) : base(holdNote.HitObject.Tail, action)
{ {
this.holdNote = holdNote; this.holdNote = holdNote;
GlowPiece.Alpha = 0;
} }
protected override void CheckForJudgements(bool userTriggered, double timeOffset) protected override void CheckForJudgements(bool userTriggered, double timeOffset)
@ -253,11 +219,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
}); });
} }
protected override void UpdateState(ArmedState state)
{
// The holdnote keeps scrolling through, so having the tail disappear looks weird
}
public override bool OnPressed(ManiaAction action) => false; // Tail doesn't handle key down public override bool OnPressed(ManiaAction action) => false; // Tail doesn't handle key down
public override bool OnReleased(ManiaAction action) public override bool OnReleased(ManiaAction action)

View File

@ -8,7 +8,6 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -87,16 +86,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect }); AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect });
} }
protected override void UpdateState(ArmedState state)
{
switch (State.Value)
{
case ArmedState.Hit:
AccentColour = Color4.Green;
break;
}
}
protected override void Update() protected override void Update()
{ {
if (AllJudged) if (AllJudged)

View File

@ -27,5 +27,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (action != null) if (action != null)
Action = action.Value; Action = action.Value;
} }
protected override void UpdateState(ArmedState state)
{
switch (state)
{
case ArmedState.Miss:
this.FadeOut(150, Easing.In).Expire();
break;
case ArmedState.Hit:
this.FadeOut(150, Easing.OutQuint).Expire();
break;
}
}
} }
} }

View File

@ -1,12 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Extensions.Color4Extensions;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Objects.Drawables namespace osu.Game.Rulesets.Mania.Objects.Drawables
@ -16,9 +17,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary> /// </summary>
public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<ManiaAction> public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<ManiaAction>
{ {
protected readonly GlowPiece GlowPiece;
private readonly LaneGlowPiece laneGlowPiece;
private readonly NotePiece headPiece; private readonly NotePiece headPiece;
public DrawableNote(Note hitObject, ManiaAction action) public DrawableNote(Note hitObject, ManiaAction action)
@ -27,14 +25,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y; AutoSizeAxes = Axes.Y;
CornerRadius = 5;
Masking = true;
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
laneGlowPiece = new LaneGlowPiece
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
},
GlowPiece = new GlowPiece(),
headPiece = new NotePiece headPiece = new NotePiece
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
@ -49,9 +44,14 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
set set
{ {
base.AccentColour = value; base.AccentColour = value;
laneGlowPiece.AccentColour = AccentColour;
GlowPiece.AccentColour = AccentColour;
headPiece.AccentColour = AccentColour; headPiece.AccentColour = AccentColour;
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Colour = AccentColour.Lighten(1f).Opacity(0.6f),
Radius = 10,
};
} }
} }
@ -71,17 +71,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
AddJudgement(new ManiaJudgement { Result = result }); AddJudgement(new ManiaJudgement { Result = result });
} }
protected override void UpdateState(ArmedState state)
{
switch (state)
{
case ArmedState.Hit:
case ArmedState.Miss:
this.FadeOut(100).Expire();
break;
}
}
public virtual bool OnPressed(ManiaAction action) public virtual bool OnPressed(ManiaAction action)
{ {
if (action != Action) if (action != Action)

View File

@ -123,8 +123,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
if (!IsLoaded) if (!IsLoaded)
return; return;
foreground.Colour = AccentColour.Opacity(0.4f); foreground.Colour = AccentColour.Opacity(0.9f);
background.Colour = AccentColour.Opacity(0.2f); background.Colour = AccentColour.Opacity(0.6f);
subtractionCache.Invalidate(); subtractionCache.Invalidate();
} }

View File

@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
/// </summary> /// </summary>
internal class NotePiece : Container, IHasAccentColour internal class NotePiece : Container, IHasAccentColour
{ {
private const float head_height = 10; public const float NOTE_HEIGHT = 10;
private const float head_colour_height = 6; private const float head_colour_height = 6;
private readonly Box colouredBox; private readonly Box colouredBox;
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
public NotePiece() public NotePiece()
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Height = head_height; Height = NOTE_HEIGHT;
Children = new[] Children = new[]
{ {

View File

@ -33,6 +33,7 @@ namespace osu.Game.Rulesets.Mania.UI
public ManiaAction Action; public ManiaAction Action;
private readonly Box background; private readonly Box background;
private readonly Box backgroundOverlay;
private readonly Container hitTargetBar; private readonly Container hitTargetBar;
private readonly Container keyIcon; private readonly Container keyIcon;
@ -42,22 +43,32 @@ namespace osu.Game.Rulesets.Mania.UI
protected override Container<Drawable> Content => content; protected override Container<Drawable> Content => content;
private readonly Container<Drawable> content; private readonly Container<Drawable> content;
private const float opacity_released = 0.1f;
private const float opacity_pressed = 0.25f;
public Column() public Column()
: base(ScrollingDirection.Up) : base(ScrollingDirection.Up)
{ {
RelativeSizeAxes = Axes.Y; RelativeSizeAxes = Axes.Y;
Width = column_width; Width = column_width;
Masking = true;
CornerRadius = 5;
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
background = new Box background = new Box
{ {
Name = "Background", Name = "Background",
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = opacity_released Alpha = 0.3f
},
backgroundOverlay = new Box
{
Name = "Background Gradient Overlay",
RelativeSizeAxes = Axes.Both,
Height = 0.5f,
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
Blending = BlendingMode.Additive,
Alpha = 0
}, },
new Container new Container
{ {
@ -182,6 +193,7 @@ namespace osu.Game.Rulesets.Mania.UI
accentColour = value; accentColour = value;
background.Colour = accentColour; background.Colour = accentColour;
backgroundOverlay.Colour = ColourInfo.GradientVertical(accentColour.Opacity(0.6f), accentColour.Opacity(0));
hitTargetBar.EdgeEffect = new EdgeEffectParameters hitTargetBar.EdgeEffect = new EdgeEffectParameters
{ {
@ -223,8 +235,8 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
if (action == Action) if (action == Action)
{ {
background.FadeTo(opacity_pressed, 50, Easing.OutQuint); backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint); keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint);
} }
return false; return false;
@ -234,8 +246,8 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
if (action == Action) if (action == Action)
{ {
background.FadeTo(opacity_released, 800, Easing.OutQuart); backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
keyIcon.ScaleTo(1f, 400, Easing.OutQuart); keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
} }
return false; return false;
@ -265,8 +277,13 @@ namespace osu.Game.Rulesets.Mania.UI
if (action != Action) if (action != Action)
return false; return false;
var hitObject = HitObjects.Objects.LastOrDefault(h => h.HitObject.StartTime > Time.Current) ?? HitObjects.Objects.FirstOrDefault(); var nextObject =
hitObject?.PlaySamples(); HitObjects.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ??
// fallback to non-alive objects to find next off-screen object
HitObjects.Objects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ??
HitObjects.Objects.LastOrDefault();
nextObject?.PlaySamples();
return true; return true;
} }

View File

@ -1,19 +1,23 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using OpenTK;
namespace osu.Game.Rulesets.Mania.UI namespace osu.Game.Rulesets.Mania.UI
{ {
internal class HitExplosion : CompositeDrawable internal class HitExplosion : CompositeDrawable
{ {
private readonly Box inner; public override bool RemoveWhenNotAlive => true;
private readonly CircularContainer circle;
public HitExplosion(DrawableHitObject judgedObject) public HitExplosion(DrawableHitObject judgedObject)
{ {
@ -22,33 +26,32 @@ namespace osu.Game.Rulesets.Mania.UI
Anchor = Anchor.TopCentre; Anchor = Anchor.TopCentre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.X;
Size = new Vector2(isTick ? 0.5f : 1); Y = NotePiece.NOTE_HEIGHT / 2;
FillMode = FillMode.Fit; Height = NotePiece.NOTE_HEIGHT;
Blending = BlendingMode.Additive; // scale roughly in-line with visual appearance of notes
Scale = new Vector2(isTick ? 0.4f : 0.8f);
Color4 accent = isTick ? Color4.White : judgedObject.AccentColour; InternalChild = circle = new CircularContainer
InternalChild = new CircularContainer
{ {
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Masking = true, Masking = true,
BorderThickness = 1, // we want our size to be very small so the glow dominates it.
BorderColour = accent, Size = new Vector2(0.1f),
EdgeEffect = new EdgeEffectParameters EdgeEffect = new EdgeEffectParameters
{ {
Type = EdgeEffectType.Glow, Type = EdgeEffectType.Glow,
Colour = accent, Colour = Interpolation.ValueAt(0.1f, judgedObject.AccentColour, Color4.White, 0, 1),
Radius = 10, Radius = 100,
Hollow = true
}, },
Child = inner = new Box Child = new Box
{ {
Alpha = 0,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = accent, AlwaysPresent = true
Alpha = 1,
AlwaysPresent = true,
} }
}; };
} }
@ -57,8 +60,8 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
base.LoadComplete(); base.LoadComplete();
this.ScaleTo(2f, 600, Easing.OutQuint).FadeOut(500); circle.ResizeTo(circle.Size * new Vector2(4, 20), 1000, Easing.OutQuint);
inner.FadeOut(250); this.FadeIn(16).Then().FadeOut(500, Easing.OutQuint);
Expire(true); Expire(true);
} }

View File

@ -10,12 +10,9 @@ using osu.Framework.Input;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Configuration;
using osu.Game.Input.Handlers; using osu.Game.Input.Handlers;
using osu.Game.Rulesets.Configuration;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Mania.Replays;
@ -103,7 +100,5 @@ namespace osu.Game.Rulesets.Mania.UI
protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f); protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f);
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay); protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
protected override IRulesetConfigManager CreateConfig(Ruleset ruleset, SettingsStore settings) => new ManiaConfigManager(settings, Ruleset.RulesetInfo, Variant);
} }
} }

View File

@ -9,7 +9,6 @@ using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
@ -78,6 +77,7 @@ namespace osu.Game.Rulesets.Mania.UI
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X, AutoSizeAxes = Axes.X,
Masking = true, Masking = true,
CornerRadius = 5,
Children = new Drawable[] Children = new Drawable[]
{ {
new Box new Box
@ -183,15 +183,15 @@ namespace osu.Game.Rulesets.Mania.UI
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load()
{ {
normalColumnColours = new List<Color4> normalColumnColours = new List<Color4>
{ {
colours.RedDark, new Color4(94, 0, 57, 255),
colours.GreenDark new Color4(6, 84, 0, 255)
}; };
specialColumnColour = colours.BlueDark; specialColumnColour = new Color4(0, 48, 63, 255);
// Set the special column + colour + key // Set the special column + colour + key
foreach (var column in Columns) foreach (var column in Columns)

View File

@ -22,7 +22,7 @@
}, },
"type": "mono", "type": "mono",
"request": "launch", "request": "launch",
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Osu.Tests.exe", "program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Osu.Tests.exe",
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)", "preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null, "runtimeExecutable": null,
@ -30,12 +30,12 @@
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "VisualTests (Debug, netcoreapp2.0)", "name": "VisualTests (Debug, netcoreapp2.1)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
"args": [ "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}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, dotnet)", "preLaunchTask": "Build (Debug, dotnet)",
@ -43,12 +43,12 @@
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "VisualTests (Release, netcoreapp2.0)", "name": "VisualTests (Release, netcoreapp2.1)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
"args": [ "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}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, dotnet)", "preLaunchTask": "Build (Release, dotnet)",

View File

@ -40,7 +40,7 @@
"build", "build",
"--no-restore", "--no-restore",
"osu.Game.Rulesets.Osu.Tests.csproj", "osu.Game.Rulesets.Osu.Tests.csproj",
"/p:TargetFramework=netcoreapp2.0", "/p:TargetFramework=netcoreapp2.1",
"/p:GenerateFullPaths=true", "/p:GenerateFullPaths=true",
"/m", "/m",
"/verbosity:m" "/verbosity:m"
@ -56,7 +56,7 @@
"build", "build",
"--no-restore", "--no-restore",
"osu.Game.Rulesets.Osu.Tests.csproj", "osu.Game.Rulesets.Osu.Tests.csproj",
"/p:TargetFramework=netcoreapp2.0", "/p:TargetFramework=netcoreapp2.1",
"/p:Configuration=Release", "/p:Configuration=Release",
"/p:GenerateFullPaths=true", "/p:GenerateFullPaths=true",
"/m", "/m",
@ -75,7 +75,7 @@
"problemMatcher": [] "problemMatcher": []
}, },
{ {
"label": "Restore (netcoreapp2.0)", "label": "Restore (netcoreapp2.1)",
"type": "shell", "type": "shell",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [

View File

@ -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 NUnit.Framework;
namespace osu.Game.Rulesets.Osu.Tests
{
[TestFixture]
public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints
{
public TestCasePerformancePoints()
: base(new OsuRuleset())
{
}
}
}

View File

@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" /> <Import Project="..\osu.TestProject.props" />
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFrameworks>netcoreapp2.0;net471</TargetFrameworks> <TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Project References"> <ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" /> <ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />

View File

@ -0,0 +1,19 @@
// 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.Difficulty;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Osu.Difficulty
{
public class OsuDifficultyAttributes : DifficultyAttributes
{
public double AimStrain;
public double SpeedStrain;
public OsuDifficultyAttributes(Mod[] mods, double starRating)
: base(mods, starRating)
{
}
}
}

View File

@ -2,12 +2,13 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Collections.Generic; using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Difficulty.Skills; using osu.Game.Rulesets.Osu.Difficulty.Skills;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Difficulty namespace osu.Game.Rulesets.Osu.Difficulty
@ -17,31 +18,26 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private const int section_length = 400; private const int section_length = 400;
private const double difficulty_multiplier = 0.0675; private const double difficulty_multiplier = 0.0675;
public OsuDifficultyCalculator(IBeatmap beatmap) public OsuDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
: base(beatmap) : base(ruleset, beatmap)
{ {
} }
public OsuDifficultyCalculator(IBeatmap beatmap, Mod[] mods) protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate)
: base(beatmap, mods)
{ {
} OsuDifficultyBeatmap difficultyBeatmap = new OsuDifficultyBeatmap(beatmap.HitObjects.Cast<OsuHitObject>().ToList(), timeRate);
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
{
OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap((List<OsuHitObject>)Beatmap.HitObjects, TimeRate);
Skill[] skills = Skill[] skills =
{ {
new Aim(), new Aim(),
new Speed() new Speed()
}; };
double sectionLength = section_length * TimeRate; double sectionLength = section_length * timeRate;
// The first object doesn't generate a strain, so we begin with an incremented section end // The first object doesn't generate a strain, so we begin with an incremented section end
double currentSectionEnd = 2 * sectionLength; double currentSectionEnd = 2 * sectionLength;
foreach (OsuDifficultyHitObject h in beatmap) foreach (OsuDifficultyHitObject h in difficultyBeatmap)
{ {
while (h.BaseObject.StartTime > currentSectionEnd) while (h.BaseObject.StartTime > currentSectionEnd)
{ {
@ -60,16 +56,21 @@ namespace osu.Game.Rulesets.Osu.Difficulty
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2;
if (categoryDifficulty != null) return new OsuDifficultyAttributes(mods, starRating)
{ {
categoryDifficulty.Add("Aim", aimRating); AimStrain = aimRating,
categoryDifficulty.Add("Speed", speedRating); SpeedStrain = speedRating
} };
return starRating;
} }
protected override Mod[] DifficultyAdjustmentMods => new Mod[]
{
new OsuModDoubleTime(),
new OsuModHalfTime(),
new OsuModEasy(),
new OsuModHardRock(),
};
} }
} }

View File

@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
{ {
public class OsuPerformanceCalculator : PerformanceCalculator public class OsuPerformanceCalculator : PerformanceCalculator
{ {
public new OsuDifficultyAttributes Attributes => (OsuDifficultyAttributes)base.Attributes;
private readonly int countHitCircles; private readonly int countHitCircles;
private readonly int beatmapMaxCombo; private readonly int beatmapMaxCombo;
@ -37,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private int countMeh; private int countMeh;
private int countMiss; private int countMiss;
public OsuPerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score) public OsuPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score)
: base(ruleset, beatmap, score) : base(ruleset, beatmap, score)
{ {
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle); countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);
@ -102,7 +104,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private double computeAimValue() private double computeAimValue()
{ {
double aimValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes["Aim"] / 0.0675f) - 4.0f, 3.0f) / 100000.0f; double aimValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes.AimStrain / 0.0675f) - 4.0f, 3.0f) / 100000.0f;
// Longer maps are worth more // Longer maps are worth more
double lengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + double lengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) +
@ -151,7 +153,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private double computeSpeedValue() private double computeSpeedValue()
{ {
double speedValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes["Speed"] / 0.0675f) - 4.0f, 3.0f) / 100000.0f; double speedValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes.SpeedStrain / 0.0675f) - 4.0f, 3.0f) / 100000.0f;
// Longer maps are worth more // Longer maps are worth more
speedValue *= 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + speedValue *= 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) +

View File

@ -7,33 +7,34 @@ using System.Linq;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Mods namespace osu.Game.Rulesets.Osu.Mods
{ {
public class OsuModHidden : ModHidden, IApplicableToDrawableHitObjects public class OsuModHidden : ModHidden
{ {
public override string Description => @"Play with no approach circles and fading circles/sliders."; public override string Description => @"Play with no approach circles and fading circles/sliders.";
public override double ScoreMultiplier => 1.06; public override double ScoreMultiplier => 1.06;
private const double fade_in_duration_multiplier = 0.4; private const double fade_in_duration_multiplier = 0.4;
private const double fade_out_duration_multiplier = 0.3; private const double fade_out_duration_multiplier = 0.3;
public void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables) public override void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
{ {
void adjustFadeIn(OsuHitObject h) => h.TimeFadein = h.TimePreempt * fade_in_duration_multiplier;
foreach (var d in drawables.OfType<DrawableOsuHitObject>()) foreach (var d in drawables.OfType<DrawableOsuHitObject>())
{ {
d.ApplyCustomUpdateState += ApplyHiddenState; adjustFadeIn(d.HitObject);
d.HitObject.TimeFadein = d.HitObject.TimePreempt * fade_in_duration_multiplier;
foreach (var h in d.HitObject.NestedHitObjects.OfType<OsuHitObject>()) foreach (var h in d.HitObject.NestedHitObjects.OfType<OsuHitObject>())
h.TimeFadein = h.TimePreempt * fade_in_duration_multiplier; adjustFadeIn(h);
} }
base.ApplyToDrawableHitObjects(drawables);
} }
protected void ApplyHiddenState(DrawableHitObject drawable, ArmedState state) protected override void ApplyHiddenState(DrawableHitObject drawable, ArmedState state)
{ {
if (!(drawable is DrawableOsuHitObject d)) if (!(drawable is DrawableOsuHitObject d))
return; return;

View File

@ -93,57 +93,26 @@ namespace osu.Game.Rulesets.Osu
{ {
new OsuModEasy(), new OsuModEasy(),
new OsuModNoFail(), new OsuModNoFail(),
new MultiMod new MultiMod(new OsuModHalfTime(), new OsuModDaycore()),
{
Mods = new Mod[]
{
new OsuModHalfTime(),
new OsuModDaycore(),
},
},
}; };
case ModType.DifficultyIncrease: case ModType.DifficultyIncrease:
return new Mod[] return new Mod[]
{ {
new OsuModHardRock(), new OsuModHardRock(),
new MultiMod new MultiMod(new OsuModSuddenDeath(), new OsuModPerfect()),
{ new MultiMod(new OsuModDoubleTime(), new OsuModNightcore()),
Mods = new Mod[]
{
new OsuModSuddenDeath(),
new OsuModPerfect(),
},
},
new MultiMod
{
Mods = new Mod[]
{
new OsuModDoubleTime(),
new OsuModNightcore(),
},
},
new OsuModHidden(), new OsuModHidden(),
new OsuModFlashlight(), new OsuModFlashlight(),
}; };
case ModType.Special: case ModType.Special:
return new Mod[] return new Mod[]
{ {
new OsuModRelax(), new OsuModRelax(),
new OsuModAutopilot(), new OsuModAutopilot(),
new OsuModSpunOut(), new OsuModSpunOut(),
new MultiMod new MultiMod(new OsuModAutoplay(), new ModCinema()),
{
Mods = new Mod[]
{
new OsuModAutoplay(),
new ModCinema(),
},
},
new OsuModTarget(), new OsuModTarget(),
}; };
default: default:
return new Mod[] { }; return new Mod[] { };
} }
@ -151,9 +120,9 @@ namespace osu.Game.Rulesets.Osu
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_osu_o }; public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_osu_o };
public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new OsuDifficultyCalculator(beatmap, mods); public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(this, beatmap);
public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new OsuPerformanceCalculator(this, beatmap, score); public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new OsuPerformanceCalculator(this, beatmap, score);
public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this); public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this);
@ -161,7 +130,7 @@ namespace osu.Game.Rulesets.Osu
public override string ShortName => "osu"; public override string ShortName => "osu";
public override SettingsSubsection CreateSettings() => new OsuSettings(); public override RulesetSettingsSubsection CreateSettings() => new OsuSettings(this);
public override int? LegacyID => 0; public override int? LegacyID => 0;

View File

@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private Bindable<double> cursorScale; private Bindable<double> cursorScale;
private Bindable<bool> autoCursorScale; private Bindable<bool> autoCursorScale;
private Bindable<WorkingBeatmap> beatmap; private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
public OsuCursor() public OsuCursor()
{ {
@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuConfigManager config, OsuGameBase game) private void load(OsuConfigManager config, IBindableBeatmap beatmap)
{ {
Child = cursorContainer = new SkinnableDrawable("cursor", _ => new CircularContainer Child = cursorContainer = new SkinnableDrawable("cursor", _ => new CircularContainer
{ {
@ -160,8 +160,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}; };
beatmap = game.Beatmap.GetBoundCopy(); this.beatmap.BindTo(beatmap);
beatmap.ValueChanged += v => calculateScale(); this.beatmap.ValueChanged += v => calculateScale();
cursorScale = config.GetBindable<double>(OsuSetting.GameplayCursorSize); cursorScale = config.GetBindable<double>(OsuSetting.GameplayCursorSize);
cursorScale.ValueChanged += v => calculateScale(); cursorScale.ValueChanged += v => calculateScale();

View File

@ -64,9 +64,7 @@ namespace osu.Game.Rulesets.Osu.UI
public override void PostProcess() public override void PostProcess()
{ {
connectionLayer.HitObjects = HitObjects.Objects connectionLayer.HitObjects = HitObjects.Objects.Select(d => d.HitObject).OfType<OsuHitObject>();
.Select(d => d.HitObject)
.OrderBy(h => h.StartTime).OfType<OsuHitObject>();
} }
private void onJudgement(DrawableHitObject judgedObject, Judgement judgement) private void onJudgement(DrawableHitObject judgedObject, Judgement judgement)

View File

@ -8,10 +8,15 @@ using osu.Game.Overlays.Settings;
namespace osu.Game.Rulesets.Osu.UI namespace osu.Game.Rulesets.Osu.UI
{ {
public class OsuSettings : SettingsSubsection public class OsuSettings : RulesetSettingsSubsection
{ {
protected override string Header => "osu!"; protected override string Header => "osu!";
public OsuSettings(Ruleset ruleset)
: base(ruleset)
{
}
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuConfigManager config) private void load(OsuConfigManager config)
{ {

View File

@ -22,7 +22,7 @@
}, },
"type": "mono", "type": "mono",
"request": "launch", "request": "launch",
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Taiko.Tests.exe", "program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Taiko.Tests.exe",
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)", "preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null, "runtimeExecutable": null,
@ -30,12 +30,12 @@
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "VisualTests (Debug, netcoreapp2.0)", "name": "VisualTests (Debug, netcoreapp2.1)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
"args": [ "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}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, dotnet)", "preLaunchTask": "Build (Debug, dotnet)",
@ -43,12 +43,12 @@
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "VisualTests (Release, netcoreapp2.0)", "name": "VisualTests (Release, netcoreapp2.1)",
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"program": "dotnet", "program": "dotnet",
"args": [ "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}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, dotnet)", "preLaunchTask": "Build (Release, dotnet)",

View File

@ -40,7 +40,7 @@
"build", "build",
"--no-restore", "--no-restore",
"osu.Game.Rulesets.Taiko.Tests.csproj", "osu.Game.Rulesets.Taiko.Tests.csproj",
"/p:TargetFramework=netcoreapp2.0", "/p:TargetFramework=netcoreapp2.1",
"/p:GenerateFullPaths=true", "/p:GenerateFullPaths=true",
"/m", "/m",
"/verbosity:m" "/verbosity:m"
@ -56,7 +56,7 @@
"build", "build",
"--no-restore", "--no-restore",
"osu.Game.Rulesets.Taiko.Tests.csproj", "osu.Game.Rulesets.Taiko.Tests.csproj",
"/p:TargetFramework=netcoreapp2.0", "/p:TargetFramework=netcoreapp2.1",
"/p:Configuration=Release", "/p:Configuration=Release",
"/p:GenerateFullPaths=true", "/p:GenerateFullPaths=true",
"/m", "/m",
@ -75,7 +75,7 @@
"problemMatcher": [] "problemMatcher": []
}, },
{ {
"label": "Restore (netcoreapp2.0)", "label": "Restore (netcoreapp2.1)",
"type": "shell", "type": "shell",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [

View File

@ -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 NUnit.Framework;
namespace osu.Game.Rulesets.Taiko.Tests
{
[TestFixture]
public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints
{
public TestCasePerformancePoints()
: base(new TaikoRuleset())
{
}
}
}

View File

@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" /> <Import Project="..\osu.TestProject.props" />
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFrameworks>netcoreapp2.0;net471</TargetFrameworks> <TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Project References"> <ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" /> <ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Mods;
using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Objects;
namespace osu.Game.Rulesets.Taiko.Difficulty namespace osu.Game.Rulesets.Taiko.Difficulty
@ -26,46 +27,33 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
/// </summary> /// </summary>
private const double decay_weight = 0.9; private const double decay_weight = 0.9;
/// <summary> public TaikoDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
/// HitObjects are stored as a member variable. : base(ruleset, beatmap)
/// </summary>
private readonly List<TaikoHitObjectDifficulty> difficultyHitObjects = new List<TaikoHitObjectDifficulty>();
public TaikoDifficultyCalculator(IBeatmap beatmap)
: base(beatmap)
{ {
} }
public TaikoDifficultyCalculator(IBeatmap beatmap, Mod[] mods) protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate)
: base(beatmap, mods)
{ {
} var difficultyHitObjects = new List<TaikoHitObjectDifficulty>();
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) foreach (var hitObject in beatmap.HitObjects)
{
// Fill our custom DifficultyHitObject class, that carries additional information
difficultyHitObjects.Clear();
foreach (var hitObject in Beatmap.HitObjects)
difficultyHitObjects.Add(new TaikoHitObjectDifficulty((TaikoHitObject)hitObject)); difficultyHitObjects.Add(new TaikoHitObjectDifficulty((TaikoHitObject)hitObject));
// Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure. // Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure.
difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime)); difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime));
if (!calculateStrainValues()) return 0; if (!calculateStrainValues(difficultyHitObjects, timeRate))
return new DifficultyAttributes(mods, 0);
double starRating = calculateDifficulty() * star_scaling_factor; double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor;
if (categoryDifficulty != null) return new DifficultyAttributes(mods, starRating);
categoryDifficulty["Strain"] = starRating;
return starRating;
} }
private bool calculateStrainValues() private bool calculateStrainValues(List<TaikoHitObjectDifficulty> objects, double timeRate)
{ {
// Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment.
using (List<TaikoHitObjectDifficulty>.Enumerator hitObjectsEnumerator = difficultyHitObjects.GetEnumerator()) using (var hitObjectsEnumerator = objects.GetEnumerator())
{ {
if (!hitObjectsEnumerator.MoveNext()) return false; if (!hitObjectsEnumerator.MoveNext()) return false;
@ -75,7 +63,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
while (hitObjectsEnumerator.MoveNext()) while (hitObjectsEnumerator.MoveNext())
{ {
var next = hitObjectsEnumerator.Current; var next = hitObjectsEnumerator.Current;
next?.CalculateStrains(current, TimeRate); next?.CalculateStrains(current, timeRate);
current = next; current = next;
} }
@ -83,9 +71,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
} }
} }
private double calculateDifficulty() private double calculateDifficulty(List<TaikoHitObjectDifficulty> objects, double timeRate)
{ {
double actualStrainStep = strain_step * TimeRate; double actualStrainStep = strain_step * timeRate;
// Find the highest strain value within each strain step // Find the highest strain value within each strain step
List<double> highestStrains = new List<double>(); List<double> highestStrains = new List<double>();
@ -93,7 +81,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval
TaikoHitObjectDifficulty previousHitObject = null; TaikoHitObjectDifficulty previousHitObject = null;
foreach (var hitObject in difficultyHitObjects) foreach (var hitObject in objects)
{ {
// While we are beyond the current interval push the currently available maximum to our strain list // While we are beyond the current interval push the currently available maximum to our strain list
while (hitObject.BaseHitObject.StartTime > intervalEndTime) while (hitObject.BaseHitObject.StartTime > intervalEndTime)
@ -135,5 +123,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
return difficulty; return difficulty;
} }
protected override Mod[] DifficultyAdjustmentMods => new Mod[]
{
new TaikoModDoubleTime(),
new TaikoModHalfTime(),
new TaikoModEasy(),
new TaikoModHardRock(),
};
} }
} }

View File

@ -22,10 +22,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
private int countMeh; private int countMeh;
private int countMiss; private int countMiss;
public TaikoPerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score) public TaikoPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score)
: base(ruleset, beatmap, score) : base(ruleset, beatmap, score)
{ {
beatmapMaxCombo = beatmap.HitObjects.Count(h => h is Hit); beatmapMaxCombo = Beatmap.HitObjects.Count(h => h is Hit);
} }
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
private double computeStrainValue() private double computeStrainValue()
{ {
double strainValue = Math.Pow(5.0 * Math.Max(1.0, Attributes["Strain"] / 0.0075) - 4.0, 2.0) / 100000.0; double strainValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.StarRating / 0.0075) - 4.0, 2.0) / 100000.0;
// Longer maps are worth more // Longer maps are worth more
double lengthBonus = 1 + 0.1f * Math.Min(1.0, totalHits / 1500.0); double lengthBonus = 1 + 0.1f * Math.Min(1.0, totalHits / 1500.0);

View File

@ -84,56 +84,25 @@ namespace osu.Game.Rulesets.Taiko
{ {
new TaikoModEasy(), new TaikoModEasy(),
new TaikoModNoFail(), new TaikoModNoFail(),
new MultiMod new MultiMod(new TaikoModHalfTime(), new TaikoModDaycore()),
{
Mods = new Mod[]
{
new TaikoModHalfTime(),
new TaikoModDaycore(),
},
},
}; };
case ModType.DifficultyIncrease: case ModType.DifficultyIncrease:
return new Mod[] return new Mod[]
{ {
new TaikoModHardRock(), new TaikoModHardRock(),
new MultiMod new MultiMod(new TaikoModSuddenDeath(), new TaikoModPerfect()),
{ new MultiMod(new TaikoModDoubleTime(), new TaikoModNightcore()),
Mods = new Mod[]
{
new TaikoModSuddenDeath(),
new TaikoModPerfect(),
},
},
new MultiMod
{
Mods = new Mod[]
{
new TaikoModDoubleTime(),
new TaikoModNightcore(),
},
},
new TaikoModHidden(), new TaikoModHidden(),
new TaikoModFlashlight(), new TaikoModFlashlight(),
}; };
case ModType.Special: case ModType.Special:
return new Mod[] return new Mod[]
{ {
new TaikoModRelax(), new TaikoModRelax(),
null, null,
null, null,
new MultiMod new MultiMod(new TaikoModAutoplay(), new ModCinema()),
{
Mods = new Mod[]
{
new TaikoModAutoplay(),
new ModCinema(),
},
},
}; };
default: default:
return new Mod[] { }; return new Mod[] { };
} }
@ -145,9 +114,9 @@ namespace osu.Game.Rulesets.Taiko
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o }; public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o };
public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new TaikoDifficultyCalculator(beatmap, mods); public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap);
public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new TaikoPerformanceCalculator(this, beatmap, score); public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new TaikoPerformanceCalculator(this, beatmap, score);
public override int? LegacyID => 1; public override int? LegacyID => 1;

View File

@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Taiko.UI
/// </summary> /// </summary>
internal class HitExplosion : CircularContainer internal class HitExplosion : CircularContainer
{ {
public override bool RemoveWhenNotAlive => true;
public readonly DrawableHitObject JudgedObject; public readonly DrawableHitObject JudgedObject;
private readonly Box innerFill; private readonly Box innerFill;
@ -66,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.UI
this.ScaleTo(3f, 1000, Easing.OutQuint); this.ScaleTo(3f, 1000, Easing.OutQuint);
this.FadeOut(500); this.FadeOut(500);
Expire(); Expire(true);
} }
/// <summary> /// <summary>

View File

@ -14,6 +14,8 @@ namespace osu.Game.Rulesets.Taiko.UI
{ {
public class KiaiHitExplosion : CircularContainer public class KiaiHitExplosion : CircularContainer
{ {
public override bool RemoveWhenNotAlive => true;
public readonly DrawableHitObject JudgedObject; public readonly DrawableHitObject JudgedObject;
private readonly bool isRim; private readonly bool isRim;
@ -62,7 +64,7 @@ namespace osu.Game.Rulesets.Taiko.UI
this.ScaleTo(new Vector2(1, 3f), 500, Easing.OutQuint); this.ScaleTo(new Vector2(1, 3f), 500, Easing.OutQuint);
this.FadeOut(250); this.FadeOut(250);
Expire(); Expire(true);
} }
} }
} }

View File

@ -86,7 +86,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.AreEqual(string.Empty, metadata.Source); Assert.AreEqual(string.Empty, metadata.Source);
Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags); Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags);
Assert.AreEqual(557821, beatmapInfo.OnlineBeatmapID); Assert.AreEqual(557821, beatmapInfo.OnlineBeatmapID);
Assert.AreEqual(241526, metadata.OnlineBeatmapSetID); Assert.AreEqual(241526, beatmapInfo.BeatmapSet.OnlineBeatmapSetID);
} }
} }

View File

@ -28,7 +28,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
{ {
var beatmap = decodeAsJson(normal); var beatmap = decodeAsJson(normal);
var meta = beatmap.BeatmapInfo.Metadata; var meta = beatmap.BeatmapInfo.Metadata;
Assert.AreEqual(241526, meta.OnlineBeatmapSetID); Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID);
Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.Artist);
Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("Soleily", meta.ArtistUnicode);
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);

View File

@ -19,7 +19,7 @@ namespace osu.Game.Tests.Beatmaps.IO
[TestFixture] [TestFixture]
public class ImportBeatmapTest public class ImportBeatmapTest
{ {
private const string osz_path = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz"; public const string TEST_OSZ_PATH = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz";
[Test] [Test]
public void TestImportWhenClosed() public void TestImportWhenClosed()
@ -264,7 +264,8 @@ namespace osu.Game.Tests.Beatmaps.IO
private string createTemporaryBeatmap() private string createTemporaryBeatmap()
{ {
var temp = new FileInfo(osz_path).CopyTo(Path.GetTempFileName(), true).FullName; var temp = Path.GetTempFileName() + ".osz";
File.Copy(TEST_OSZ_PATH, temp, true);
Assert.IsTrue(File.Exists(temp)); Assert.IsTrue(File.Exists(temp));
return temp; return temp;
} }
@ -344,12 +345,12 @@ namespace osu.Game.Tests.Beatmaps.IO
private void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 60000) private void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 60000)
{ {
Action waitAction = () => Task task = Task.Run(() =>
{ {
while (!result()) Thread.Sleep(200); while (!result()) Thread.Sleep(200);
}; });
Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(timeout), failureMessage); Assert.IsTrue(task.Wait(timeout), failureMessage);
} }
} }
} }

View File

@ -48,17 +48,20 @@ namespace osu.Game.Tests.Beatmaps.IO
{ {
var reader = new ZipArchiveReader(osz); var reader = new ZipArchiveReader(osz);
BeatmapMetadata meta; Beatmap beatmap;
using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu")))
meta = Decoder.GetDecoder<Beatmap>(stream).Decode(stream).Metadata;
Assert.AreEqual(241526, meta.OnlineBeatmapSetID); using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu")))
beatmap = Decoder.GetDecoder<Beatmap>(stream).Decode(stream);
var meta = beatmap.Metadata;
Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID);
Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.Artist);
Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("Soleily", meta.ArtistUnicode);
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
Assert.AreEqual("Deif", meta.AuthorString); Assert.AreEqual("Deif", meta.AuthorString);
Assert.AreEqual("machinetop_background.jpg", meta.BackgroundFile); Assert.AreEqual("machinetop_background.jpg", meta.BackgroundFile);
Assert.AreEqual(164471 + LegacyBeatmapDecoder.UniversalOffset, meta.PreviewTime); Assert.AreEqual(164471, meta.PreviewTime);
Assert.AreEqual(string.Empty, meta.Source); Assert.AreEqual(string.Empty, meta.Source);
Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags); Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags);
Assert.AreEqual("Renatus", meta.Title); Assert.AreEqual("Renatus", meta.Title);

View File

@ -0,0 +1,152 @@
// 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 NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Tests.NonVisual
{
[TestFixture]
public class DifficultyAdjustmentModCombinationsTest
{
[Test]
public void TestNoMods()
{
var combinations = new TestDifficultyCalculator().CreateDifficultyAdjustmentModCombinations();
Assert.AreEqual(1, combinations.Length);
Assert.IsTrue(combinations[0] is NoModMod);
}
[Test]
public void TestSingleMod()
{
var combinations = new TestDifficultyCalculator(new ModA()).CreateDifficultyAdjustmentModCombinations();
Assert.AreEqual(2, combinations.Length);
Assert.IsTrue(combinations[0] is NoModMod);
Assert.IsTrue(combinations[1] is ModA);
}
[Test]
public void TestDoubleMod()
{
var combinations = new TestDifficultyCalculator(new ModA(), new ModB()).CreateDifficultyAdjustmentModCombinations();
Assert.AreEqual(4, combinations.Length);
Assert.IsTrue(combinations[0] is NoModMod);
Assert.IsTrue(combinations[1] is ModA);
Assert.IsTrue(combinations[2] is MultiMod);
Assert.IsTrue(combinations[3] is ModB);
Assert.IsTrue(((MultiMod)combinations[2]).Mods[0] is ModA);
Assert.IsTrue(((MultiMod)combinations[2]).Mods[1] is ModB);
}
[Test]
public void TestIncompatibleMods()
{
var combinations = new TestDifficultyCalculator(new ModA(), new ModIncompatibleWithA()).CreateDifficultyAdjustmentModCombinations();
Assert.AreEqual(3, combinations.Length);
Assert.IsTrue(combinations[0] is NoModMod);
Assert.IsTrue(combinations[1] is ModA);
Assert.IsTrue(combinations[2] is ModIncompatibleWithA);
}
[Test]
public void TestDoubleIncompatibleMods()
{
var combinations = new TestDifficultyCalculator(new ModA(), new ModB(), new ModIncompatibleWithA(), new ModIncompatibleWithAAndB()).CreateDifficultyAdjustmentModCombinations();
Assert.AreEqual(8, combinations.Length);
Assert.IsTrue(combinations[0] is NoModMod);
Assert.IsTrue(combinations[1] is ModA);
Assert.IsTrue(combinations[2] is MultiMod);
Assert.IsTrue(combinations[3] is ModB);
Assert.IsTrue(combinations[4] is MultiMod);
Assert.IsTrue(combinations[5] is ModIncompatibleWithA);
Assert.IsTrue(combinations[6] is MultiMod);
Assert.IsTrue(combinations[7] is ModIncompatibleWithAAndB);
Assert.IsTrue(((MultiMod)combinations[2]).Mods[0] is ModA);
Assert.IsTrue(((MultiMod)combinations[2]).Mods[1] is ModB);
Assert.IsTrue(((MultiMod)combinations[4]).Mods[0] is ModB);
Assert.IsTrue(((MultiMod)combinations[4]).Mods[1] is ModIncompatibleWithA);
Assert.IsTrue(((MultiMod)combinations[6]).Mods[0] is ModIncompatibleWithA);
Assert.IsTrue(((MultiMod)combinations[6]).Mods[1] is ModIncompatibleWithAAndB);
}
[Test]
public void TestIncompatibleThroughBaseType()
{
var combinations = new TestDifficultyCalculator(new ModAofA(), new ModIncompatibleWithAofA()).CreateDifficultyAdjustmentModCombinations();
Assert.AreEqual(3, combinations.Length);
Assert.IsTrue(combinations[0] is NoModMod);
Assert.IsTrue(combinations[1] is ModAofA);
Assert.IsTrue(combinations[2] is ModIncompatibleWithAofA);
}
private class ModA : Mod
{
public override string Name => nameof(ModA);
public override string ShortenedName => nameof(ModA);
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModIncompatibleWithA), typeof(ModIncompatibleWithAAndB) };
}
private class ModB : Mod
{
public override string Name => nameof(ModB);
public override string ShortenedName => nameof(ModB);
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModIncompatibleWithAAndB) };
}
private class ModIncompatibleWithA : Mod
{
public override string Name => $"Incompatible With {nameof(ModA)}";
public override string ShortenedName => $"Incompatible With {nameof(ModA)}";
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModA) };
}
private class ModAofA : ModA
{
}
private class ModIncompatibleWithAofA : ModIncompatibleWithA
{
// Incompatible through base type
}
private class ModIncompatibleWithAAndB : Mod
{
public override string Name => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}";
public override string ShortenedName => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}";
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(ModA), typeof(ModB) };
}
private class TestDifficultyCalculator : DifficultyCalculator
{
public TestDifficultyCalculator(params Mod[] mods)
: base(null, null)
{
DifficultyAdjustmentMods = mods;
}
protected override Mod[] DifficultyAdjustmentMods { get; }
protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) => throw new NotImplementedException();
}
}
}

View File

@ -3,7 +3,6 @@
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
@ -13,12 +12,11 @@ namespace osu.Game.Tests.Visual
[Description("Player instantiated with an autoplay mod.")] [Description("Player instantiated with an autoplay mod.")]
public class TestCaseAutoplay : TestCasePlayer public class TestCaseAutoplay : TestCasePlayer
{ {
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) protected override Player CreatePlayer(Ruleset ruleset)
{ {
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }); Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
return new ScoreAccessiblePlayer return new ScoreAccessiblePlayer
{ {
InitialBeatmap = beatmap,
AllowPause = false, AllowPause = false,
AllowLeadIn = false, AllowLeadIn = false,
AllowResults = false, AllowResults = false,

View File

@ -65,11 +65,7 @@ namespace osu.Game.Tests.Visual
carousel.SelectionChanged = s => currentSelection = s; carousel.SelectionChanged = s => currentSelection = s;
AddStep("Load Beatmaps", () => { carousel.BeatmapSets = beatmapSets; }); loadBeatmaps(beatmapSets);
bool changed = false;
carousel.BeatmapSetsChanged = () => changed = true;
AddUntilStep(() => changed, "Wait for load");
testTraversal(); testTraversal();
testFiltering(); testFiltering();
@ -84,6 +80,17 @@ namespace osu.Game.Tests.Visual
testCarouselRootIsRandom(); testCarouselRootIsRandom();
} }
private void loadBeatmaps(List<BeatmapSetInfo> beatmapSets)
{
bool changed = false;
AddStep($"Load {beatmapSets.Count} Beatmaps", () =>
{
carousel.BeatmapSetsChanged = () => changed = true;
carousel.BeatmapSets = beatmapSets;
});
AddUntilStep(() => changed, "Wait for load");
}
private void ensureRandomFetchSuccess() => private void ensureRandomFetchSuccess() =>
AddAssert("ensure prev random fetch worked", () => selectedSets.Peek() == carousel.SelectedBeatmapSet); AddAssert("ensure prev random fetch worked", () => selectedSets.Peek() == carousel.SelectedBeatmapSet);
@ -423,7 +430,7 @@ namespace osu.Game.Tests.Visual
for (int i = 1; i <= 50; i++) for (int i = 1; i <= 50; i++)
beatmapSets.Add(createTestBeatmapSet(i)); beatmapSets.Add(createTestBeatmapSet(i));
AddStep("Load 50 Beatmaps", () => { carousel.BeatmapSets = beatmapSets; }); loadBeatmaps(beatmapSets);
advanceSelection(direction: 1, diff: false); advanceSelection(direction: 1, diff: false);
checkNonmatchingFilter(); checkNonmatchingFilter();
checkNonmatchingFilter(); checkNonmatchingFilter();
@ -442,7 +449,6 @@ namespace osu.Game.Tests.Visual
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
{ {
OnlineBeatmapSetID = id,
// Create random metadata, then we can check if sorting works based on these // Create random metadata, then we can check if sorting works based on these
Artist = $"peppy{id.ToString().PadLeft(6, '0')}", Artist = $"peppy{id.ToString().PadLeft(6, '0')}",
Title = $"test set #{id}!", Title = $"test set #{id}!",
@ -496,7 +502,6 @@ namespace osu.Game.Tests.Visual
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
{ {
OnlineBeatmapSetID = id,
// Create random metadata, then we can check if sorting works based on these // Create random metadata, then we can check if sorting works based on these
Artist = $"peppy{id.ToString().PadLeft(6, '0')}", Artist = $"peppy{id.ToString().PadLeft(6, '0')}",
Title = $"test set #{id}!", Title = $"test set #{id}!",

View File

@ -6,7 +6,6 @@ using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using OpenTK; using OpenTK;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -29,14 +28,11 @@ namespace osu.Game.Tests.Visual
private RulesetStore rulesets; private RulesetStore rulesets;
private TestBeatmapInfoWedge infoWedge; private TestBeatmapInfoWedge infoWedge;
private readonly List<IBeatmap> beatmaps = new List<IBeatmap>(); private readonly List<IBeatmap> beatmaps = new List<IBeatmap>();
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game, RulesetStore rulesets) private void load(RulesetStore rulesets)
{ {
this.rulesets = rulesets; this.rulesets = rulesets;
beatmap.BindTo(game.Beatmap);
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -53,11 +49,11 @@ namespace osu.Game.Tests.Visual
AddStep("show", () => AddStep("show", () =>
{ {
infoWedge.State = Visibility.Visible; infoWedge.State = Visibility.Visible;
infoWedge.UpdateBeatmap(beatmap); infoWedge.Beatmap = Beatmap;
}); });
// select part is redundant, but wait for load isn't // select part is redundant, but wait for load isn't
selectBeatmap(beatmap.Value.Beatmap); selectBeatmap(Beatmap.Value.Beatmap);
AddWaitStep(3); AddWaitStep(3);
@ -120,8 +116,8 @@ namespace osu.Game.Tests.Visual
{ {
selectNullBeatmap(); selectNullBeatmap();
AddAssert("check empty version", () => string.IsNullOrEmpty(infoWedge.Info.VersionLabel.Text)); AddAssert("check empty version", () => string.IsNullOrEmpty(infoWedge.Info.VersionLabel.Text));
AddAssert("check default title", () => infoWedge.Info.TitleLabel.Text == beatmap.Default.BeatmapInfo.Metadata.Title); AddAssert("check default title", () => infoWedge.Info.TitleLabel.Text == Beatmap.Default.BeatmapInfo.Metadata.Title);
AddAssert("check default artist", () => infoWedge.Info.ArtistLabel.Text == beatmap.Default.BeatmapInfo.Metadata.Artist); AddAssert("check default artist", () => infoWedge.Info.ArtistLabel.Text == Beatmap.Default.BeatmapInfo.Metadata.Artist);
AddAssert("check empty author", () => !infoWedge.Info.MapperContainer.Children.Any()); AddAssert("check empty author", () => !infoWedge.Info.MapperContainer.Children.Any());
AddAssert("check no infolabels", () => !infoWedge.Info.InfoLabelContainer.Children.Any()); AddAssert("check no infolabels", () => !infoWedge.Info.InfoLabelContainer.Children.Any());
} }
@ -133,7 +129,7 @@ namespace osu.Game.Tests.Visual
AddStep($"select {b.Metadata.Title} beatmap", () => AddStep($"select {b.Metadata.Title} beatmap", () =>
{ {
infoBefore = infoWedge.Info; infoBefore = infoWedge.Info;
infoWedge.UpdateBeatmap(beatmap.Value = new TestWorkingBeatmap(b)); infoWedge.Beatmap = Beatmap.Value = new TestWorkingBeatmap(b);
}); });
AddUntilStep(() => infoWedge.Info != infoBefore, "wait for async load"); AddUntilStep(() => infoWedge.Info != infoBefore, "wait for async load");
@ -143,8 +139,8 @@ namespace osu.Game.Tests.Visual
{ {
AddStep("select null beatmap", () => AddStep("select null beatmap", () =>
{ {
beatmap.Value = beatmap.Default; Beatmap.Value = Beatmap.Default;
infoWedge.UpdateBeatmap(beatmap); infoWedge.Beatmap = Beatmap;
}); });
} }

View File

@ -6,7 +6,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.BeatmapSet.Scores; using osu.Game.Overlays.BeatmapSet.Scores;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Mods;
@ -15,6 +14,7 @@ using osu.Game.Users;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
@ -22,9 +22,9 @@ namespace osu.Game.Tests.Visual
[System.ComponentModel.Description("in BeatmapOverlay")] [System.ComponentModel.Description("in BeatmapOverlay")]
public class TestCaseBeatmapScoresContainer : OsuTestCase public class TestCaseBeatmapScoresContainer : OsuTestCase
{ {
private readonly IEnumerable<OnlineScore> scores; private readonly IEnumerable<APIScore> scores;
private readonly IEnumerable<OnlineScore> anotherScores; private readonly IEnumerable<APIScore> anotherScores;
private readonly OnlineScore topScore; private readonly APIScore topScore;
private readonly Box background; private readonly Box background;
public TestCaseBeatmapScoresContainer() public TestCaseBeatmapScoresContainer()
@ -52,12 +52,12 @@ namespace osu.Game.Tests.Visual
AddStep("remove scores", () => scoresContainer.Scores = null); AddStep("remove scores", () => scoresContainer.Scores = null);
AddStep("resize to big", () => container.ResizeWidthTo(1, 300)); AddStep("resize to big", () => container.ResizeWidthTo(1, 300));
AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300)); AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300));
AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapSetID = 1, OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo }); AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo });
scores = new[] scores = new[]
{ {
new OnlineScore new APIScore
{ {
User = new User User = new User
{ {
@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 1234567890, TotalScore = 1234567890,
Accuracy = 1, Accuracy = 1,
}, },
new OnlineScore new APIScore
{ {
User = new User User = new User
{ {
@ -102,7 +102,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 1234789, TotalScore = 1234789,
Accuracy = 0.9997, Accuracy = 0.9997,
}, },
new OnlineScore new APIScore
{ {
User = new User User = new User
{ {
@ -123,7 +123,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 12345678, TotalScore = 12345678,
Accuracy = 0.9854, Accuracy = 0.9854,
}, },
new OnlineScore new APIScore
{ {
User = new User User = new User
{ {
@ -143,7 +143,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 1234567, TotalScore = 1234567,
Accuracy = 0.8765, Accuracy = 0.8765,
}, },
new OnlineScore new APIScore
{ {
User = new User User = new User
{ {
@ -169,7 +169,7 @@ namespace osu.Game.Tests.Visual
anotherScores = new[] anotherScores = new[]
{ {
new OnlineScore new APIScore
{ {
User = new User User = new User
{ {
@ -191,7 +191,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 1234789, TotalScore = 1234789,
Accuracy = 0.9997, Accuracy = 0.9997,
}, },
new OnlineScore new APIScore
{ {
User = new User User = new User
{ {
@ -214,7 +214,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 1234567890, TotalScore = 1234567890,
Accuracy = 1, Accuracy = 1,
}, },
new OnlineScore new APIScore
{ {
User = new User User = new User
{ {
@ -230,7 +230,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 123456, TotalScore = 123456,
Accuracy = 0.6543, Accuracy = 0.6543,
}, },
new OnlineScore new APIScore
{ {
User = new User User = new User
{ {
@ -251,7 +251,7 @@ namespace osu.Game.Tests.Visual
TotalScore = 12345678, TotalScore = 12345678,
Accuracy = 0.9854, Accuracy = 0.9854,
}, },
new OnlineScore new APIScore
{ {
User = new User User = new User
{ {
@ -279,7 +279,7 @@ namespace osu.Game.Tests.Visual
s.Statistics.Add(HitResult.Meh, RNG.Next(2000)); s.Statistics.Add(HitResult.Meh, RNG.Next(2000));
} }
topScore = new OnlineScore topScore = new APIScore
{ {
User = new User User = new User
{ {

View File

@ -35,9 +35,6 @@ namespace osu.Game.Tests.Visual
typeof(MessageFormatter) typeof(MessageFormatter)
}; };
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent);
public TestCaseChatLink() public TestCaseChatLink()
{ {
Add(textContainer = new TestChatLineContainer Add(textContainer = new TestChatLineContainer

View File

@ -17,14 +17,10 @@ namespace osu.Game.Tests.Visual
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(Compose) }; public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(Compose) };
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase osuGame) private void load()
{ {
osuGame.Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo); Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo);
Child = new Compose();
var compose = new Compose();
compose.Beatmap.BindTo(osuGame.Beatmap);
Child = compose;
} }
} }
} }

View File

@ -4,45 +4,131 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using NUnit.Framework; using NUnit.Framework;
using OpenTK;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration;
using OpenTK;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Overlays; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Screens.Edit.Screens.Compose.Timeline; using osu.Game.Screens.Edit.Screens.Compose.Timeline;
using OpenTK.Graphics;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
{ {
[TestFixture] [TestFixture]
public class TestCaseEditorComposeTimeline : OsuTestCase public class TestCaseEditorComposeTimeline : EditorClockTestCase
{ {
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(ScrollableTimeline), typeof(ScrollingTimelineContainer), typeof(BeatmapWaveformGraph), typeof(TimelineButton) }; public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(TimelineArea), typeof(Timeline), typeof(TimelineButton) };
private readonly ScrollableTimeline timeline; [BackgroundDependencyLoader]
private void load()
public TestCaseEditorComposeTimeline()
{ {
Beatmap.Value = new WaveformTestBeatmap();
Children = new Drawable[] Children = new Drawable[]
{ {
new MusicController new FillFlowContainer
{ {
Anchor = Anchor.TopCentre, AutoSizeAxes = Axes.Both,
Origin = Anchor.TopCentre, Direction = FillDirection.Vertical,
State = Visibility.Visible Spacing = new Vector2(0, 5),
Children = new Drawable[]
{
new StartStopButton(),
new AudioVisualiser(),
}
}, },
timeline = new ScrollableTimeline new TimelineArea
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Size = new Vector2(1000, 100) RelativeSizeAxes = Axes.X,
Size = new Vector2(0.8f, 100)
} }
}; };
} }
[BackgroundDependencyLoader] private class AudioVisualiser : CompositeDrawable
private void load(OsuGameBase osuGame)
{ {
timeline.Beatmap.BindTo(osuGame.Beatmap); private readonly Drawable marker;
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
private IAdjustableClock adjustableClock;
public AudioVisualiser()
{
Size = new Vector2(250, 25);
InternalChildren = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0.25f,
},
marker = new Box
{
RelativePositionAxes = Axes.X,
RelativeSizeAxes = Axes.Y,
Width = 2,
}
};
}
[BackgroundDependencyLoader]
private void load(IAdjustableClock adjustableClock, IBindableBeatmap beatmap)
{
this.adjustableClock = adjustableClock;
this.beatmap.BindTo(beatmap);
}
protected override void Update()
{
base.Update();
if (beatmap.Value.Track.IsLoaded)
marker.X = (float)(adjustableClock.CurrentTime / beatmap.Value.Track.Length);
}
}
private class StartStopButton : Button
{
private IAdjustableClock adjustableClock;
private bool started;
public StartStopButton()
{
BackgroundColour = Color4.SlateGray;
Size = new Vector2(100, 50);
Text = "Start";
Action = onClick;
}
[BackgroundDependencyLoader]
private void load(IAdjustableClock adjustableClock)
{
this.adjustableClock = adjustableClock;
}
private void onClick()
{
if (started)
{
adjustableClock.Stop();
Text = "Start";
}
else
{
adjustableClock.Start();
Text = "Stop";
}
started = !started;
}
} }
} }
} }

View File

@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase osuGame) private void load()
{ {
var testBeatmap = new Beatmap var testBeatmap = new Beatmap
{ {
@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual
} }
}; };
osuGame.Beatmap.Value = new TestWorkingBeatmap(testBeatmap); Beatmap.Value = new TestWorkingBeatmap(testBeatmap);
Child = new TimingPointVisualiser(testBeatmap, 5000) { Clock = Clock }; Child = new TimingPointVisualiser(testBeatmap, 5000) { Clock = Clock };

View File

@ -19,19 +19,16 @@ namespace osu.Game.Tests.Visual
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(SummaryTimeline) }; public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(SummaryTimeline) };
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase osuGame) private void load()
{ {
osuGame.Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo); Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo);
SummaryTimeline summaryTimeline; Add(new SummaryTimeline
Add(summaryTimeline = new SummaryTimeline
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Size = new Vector2(500, 50) Size = new Vector2(500, 50)
}); });
summaryTimeline.Beatmap.BindTo(osuGame.Beatmap);
} }
} }
} }

View File

@ -32,15 +32,10 @@ namespace osu.Game.Tests.Visual
typeof(NotNullAttribute) typeof(NotNullAttribute)
}; };
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(parent);
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase osuGame) private void load()
{ {
osuGame.Beatmap.Value = new TestWorkingBeatmap(new Beatmap Beatmap.Value = new TestWorkingBeatmap(new Beatmap
{ {
HitObjects = new List<HitObject> HitObjects = new List<HitObject>
{ {
@ -63,8 +58,8 @@ namespace osu.Game.Tests.Visual
}); });
var clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; var clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
dependencies.CacheAs<IAdjustableClock>(clock); Dependencies.CacheAs<IAdjustableClock>(clock);
dependencies.CacheAs<IFrameBasedClock>(clock); Dependencies.CacheAs<IFrameBasedClock>(clock);
Child = new OsuHitObjectComposer(new OsuRuleset()); Child = new OsuHitObjectComposer(new OsuRuleset());
} }

View File

@ -0,0 +1,115 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Game.Screens;
using osu.Game.Screens.Menu;
using OpenTK.Graphics;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseLoaderAnimation : OsuTestCase
{
private TestLoader loader;
protected override void LoadComplete()
{
base.LoadComplete();
// required to preload the logo in a headless run (so it doesn't delay the loading itself).
Add(new OsuLogo());
bool logoVisible = false;
AddStep("almost instant display", () => Child = loader = new TestLoader(250));
AddUntilStep(() =>
{
logoVisible = loader.Logo?.Alpha > 0;
return loader.Logo != null && loader.ScreenLoaded;
}, "loaded");
AddAssert("logo not visible", () => !logoVisible);
AddStep("short load", () => Child = loader = new TestLoader(800));
AddUntilStep(() =>
{
logoVisible = loader.Logo?.Alpha > 0;
return loader.Logo != null && loader.ScreenLoaded;
}, "loaded");
AddAssert("logo visible", () => logoVisible);
AddUntilStep(() => loader.Logo?.Alpha == 0, "logo gone");
AddStep("longer load", () => Child = loader = new TestLoader(1400));
AddUntilStep(() =>
{
logoVisible = loader.Logo?.Alpha > 0;
return loader.Logo != null && loader.ScreenLoaded;
}, "loaded");
AddAssert("logo visible", () => logoVisible);
AddUntilStep(() => loader.Logo?.Alpha == 0, "logo gone");
}
private class TestLoader : Loader
{
private readonly double delay;
public OsuLogo Logo;
private TestScreen screen;
public bool ScreenLoaded => screen.IsCurrentScreen;
public TestLoader(double delay)
{
this.delay = delay;
}
protected override void LogoArriving(OsuLogo logo, bool resuming)
{
Logo = logo;
base.LogoArriving(logo, resuming);
}
protected override OsuScreen CreateLoadableScreen() => screen = new TestScreen();
protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler(delay);
private class TestShaderPrecompiler : ShaderPrecompiler
{
private readonly double delay;
private double startTime;
public TestShaderPrecompiler(double delay)
{
this.delay = delay;
}
protected override void LoadComplete()
{
base.LoadComplete();
startTime = Time.Current;
}
protected override bool AllLoaded => Time.Current > startTime + delay;
}
private class TestScreen : OsuScreen
{
public TestScreen()
{
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.DarkSlateGray,
Alpha = 0,
};
}
protected override void LogoArriving(OsuLogo logo, bool resuming)
{
base.LogoArriving(logo, resuming);
Child.FadeInFromZero(200);
}
}
}
}
}

View File

@ -2,12 +2,9 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Overlays; using osu.Game.Overlays;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
@ -15,8 +12,6 @@ namespace osu.Game.Tests.Visual
[TestFixture] [TestFixture]
public class TestCaseMusicController : OsuTestCase public class TestCaseMusicController : OsuTestCase
{ {
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
public TestCaseMusicController() public TestCaseMusicController()
{ {
Clock = new FramedClock(); Clock = new FramedClock();
@ -30,13 +25,7 @@ namespace osu.Game.Tests.Visual
AddToggleStep(@"toggle visibility", state => mc.State = state ? Visibility.Visible : Visibility.Hidden); AddToggleStep(@"toggle visibility", state => mc.State = state ? Visibility.Visible : Visibility.Hidden);
AddStep(@"show", () => mc.State = Visibility.Visible); AddStep(@"show", () => mc.State = Visibility.Visible);
AddToggleStep(@"toggle beatmap lock", state => beatmapBacking.Disabled = state); AddToggleStep(@"toggle beatmap lock", state => Beatmap.Disabled = state);
}
[BackgroundDependencyLoader]
private void load(OsuGameBase game)
{
beatmapBacking.BindTo(game.Beatmap);
} }
} }
} }

View File

@ -27,7 +27,6 @@ namespace osu.Game.Tests.Visual
private RulesetStore rulesets; private RulesetStore rulesets;
private DependencyContainer dependencies;
private WorkingBeatmap defaultBeatmap; private WorkingBeatmap defaultBeatmap;
public override IReadOnlyList<Type> RequiredTypes => new[] public override IReadOnlyList<Type> RequiredTypes => new[]
@ -48,8 +47,6 @@ namespace osu.Game.Tests.Visual
typeof(DrawableCarouselBeatmapSet), typeof(DrawableCarouselBeatmapSet),
}; };
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent);
private class TestSongSelect : PlaySongSelect private class TestSongSelect : PlaySongSelect
{ {
public WorkingBeatmap CurrentBeatmap => Beatmap.Value; public WorkingBeatmap CurrentBeatmap => Beatmap.Value;
@ -58,7 +55,7 @@ namespace osu.Game.Tests.Visual
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game) private void load()
{ {
TestSongSelect songSelect = null; TestSongSelect songSelect = null;
@ -67,10 +64,10 @@ namespace osu.Game.Tests.Visual
// this is by no means clean. should be replacing inside of OsuGameBase somehow. // this is by no means clean. should be replacing inside of OsuGameBase somehow.
IDatabaseContextFactory factory = new SingletonContextFactory(new OsuDbContext()); IDatabaseContextFactory factory = new SingletonContextFactory(new OsuDbContext());
dependencies.Cache(rulesets = new RulesetStore(factory)); Dependencies.Cache(rulesets = new RulesetStore(factory));
dependencies.Cache(manager = new BeatmapManager(storage, factory, rulesets, null, null) Dependencies.Cache(manager = new BeatmapManager(storage, factory, rulesets, null, null)
{ {
DefaultBeatmap = defaultBeatmap = game.Beatmap.Default DefaultBeatmap = defaultBeatmap = Beatmap.Default
}); });
void loadNewSongSelect(bool deleteMaps = false) => AddStep("reload song select", () => void loadNewSongSelect(bool deleteMaps = false) => AddStep("reload song select", () =>
@ -78,7 +75,7 @@ namespace osu.Game.Tests.Visual
if (deleteMaps) if (deleteMaps)
{ {
manager.Delete(manager.GetAllUsableBeatmapSets()); manager.Delete(manager.GetAllUsableBeatmapSets());
game.Beatmap.SetDefault(); Beatmap.SetDefault();
} }
if (songSelect != null) if (songSelect != null)
@ -125,7 +122,6 @@ namespace osu.Game.Tests.Visual
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
{ {
OnlineBeatmapSetID = 1234 + i,
// Create random metadata, then we can check if sorting works based on these // Create random metadata, then we can check if sorting works based on these
Artist = "MONACA " + RNG.Next(0, 9), Artist = "MONACA " + RNG.Next(0, 9),
Title = "Black Song " + RNG.Next(0, 9), Title = "Black Song " + RNG.Next(0, 9),

View File

@ -15,17 +15,12 @@ namespace osu.Game.Tests.Visual
[TestFixture] [TestFixture]
public class TestCasePlaybackControl : OsuTestCase public class TestCasePlaybackControl : OsuTestCase
{ {
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(parent);
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
var clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; var clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
dependencies.CacheAs<IAdjustableClock>(clock); Dependencies.CacheAs<IAdjustableClock>(clock);
dependencies.CacheAs<IFrameBasedClock>(clock); Dependencies.CacheAs<IFrameBasedClock>(clock);
var playback = new PlaybackControl var playback = new PlaybackControl
{ {
@ -34,7 +29,7 @@ namespace osu.Game.Tests.Visual
Size = new Vector2(200,100) Size = new Vector2(200,100)
}; };
playback.Beatmap.Value = new TestWorkingBeatmap(new Beatmap()); Beatmap.Value = new TestWorkingBeatmap(new Beatmap());
Child = playback; Child = playback;
} }

View File

@ -12,9 +12,10 @@ namespace osu.Game.Tests.Visual
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game) private void load(OsuGameBase game)
{ {
Beatmap.Value = new DummyWorkingBeatmap(game);
AddStep("load dummy beatmap", () => Add(new PlayerLoader(new Player AddStep("load dummy beatmap", () => Add(new PlayerLoader(new Player
{ {
InitialBeatmap = new DummyWorkingBeatmap(game),
AllowPause = false, AllowPause = false,
AllowLeadIn = false, AllowLeadIn = false,
AllowResults = false, AllowResults = false,

View File

@ -3,7 +3,6 @@
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
@ -13,23 +12,20 @@ namespace osu.Game.Tests.Visual
[Description("Player instantiated with a replay.")] [Description("Player instantiated with a replay.")]
public class TestCaseReplay : TestCasePlayer public class TestCaseReplay : TestCasePlayer
{ {
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset) protected override Player CreatePlayer(Ruleset ruleset)
{ {
// We create a dummy RulesetContainer just to get the replay - we don't want to use mods here // We create a dummy RulesetContainer just to get the replay - we don't want to use mods here
// to simulate setting a replay rather than having the replay already set for us // to simulate setting a replay rather than having the replay already set for us
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }); Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
var dummyRulesetContainer = ruleset.CreateRulesetContainerWith(beatmap); var dummyRulesetContainer = ruleset.CreateRulesetContainerWith(Beatmap.Value);
// We have the replay // We have the replay
var replay = dummyRulesetContainer.Replay; var replay = dummyRulesetContainer.Replay;
// Reset the mods // Reset the mods
beatmap.Mods.Value = beatmap.Mods.Value.Where(m => !(m is ModAutoplay)); Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Where(m => !(m is ModAutoplay));
return new ReplayPlayer(replay) return new ReplayPlayer(replay);
{
InitialBeatmap = beatmap
};
} }
} }
} }

View File

@ -32,18 +32,13 @@ namespace osu.Game.Tests.Visual
this.beatmaps = beatmaps; this.beatmaps = beatmaps;
} }
private WorkingBeatmap beatmap;
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
if (beatmap == null) var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0);
{ if (beatmapInfo != null)
var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0); Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmapInfo);
if (beatmapInfo != null)
beatmap = beatmaps.GetWorkingBeatmap(beatmapInfo);
}
Add(new Results(new Score Add(new Results(new Score
{ {
@ -63,10 +58,7 @@ namespace osu.Game.Tests.Visual
{ {
Username = "peppy", Username = "peppy",
} }
}) }));
{
InitialBeatmap = beatmap
});
} }
} }
} }

View File

@ -14,10 +14,6 @@ namespace osu.Game.Tests.Visual
private readonly SettingsOverlay settings; private readonly SettingsOverlay settings;
private readonly DialogOverlay dialogOverlay; private readonly DialogOverlay dialogOverlay;
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent);
public TestCaseSettings() public TestCaseSettings()
{ {
settings = new MainSettings settings = new MainSettings
@ -33,7 +29,7 @@ namespace osu.Game.Tests.Visual
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
dependencies.Cache(dialogOverlay); Dependencies.Cache(dialogOverlay);
Add(settings); Add(settings);
} }

View File

@ -3,7 +3,6 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -18,8 +17,6 @@ namespace osu.Game.Tests.Visual
[TestFixture] [TestFixture]
public class TestCaseStoryboard : OsuTestCase public class TestCaseStoryboard : OsuTestCase
{ {
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
private readonly Container<DrawableStoryboard> storyboardContainer; private readonly Container<DrawableStoryboard> storyboardContainer;
private DrawableStoryboard storyboard; private DrawableStoryboard storyboard;
@ -43,6 +40,7 @@ namespace osu.Game.Tests.Visual
}, },
}, },
}); });
Add(new MusicController Add(new MusicController
{ {
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
@ -55,10 +53,9 @@ namespace osu.Game.Tests.Visual
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game) private void load()
{ {
beatmapBacking.BindTo(game.Beatmap); Beatmap.ValueChanged += beatmapChanged;
beatmapBacking.ValueChanged += beatmapChanged;
} }
private void beatmapChanged(WorkingBeatmap working) private void beatmapChanged(WorkingBeatmap working)
@ -66,10 +63,10 @@ namespace osu.Game.Tests.Visual
private void restart() private void restart()
{ {
var track = beatmapBacking.Value.Track; var track = Beatmap.Value.Track;
track.Reset(); track.Reset();
loadStoryboard(beatmapBacking.Value); loadStoryboard(Beatmap);
track.Start(); track.Start();
} }
@ -81,7 +78,7 @@ namespace osu.Game.Tests.Visual
var decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true }; var decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true };
storyboardContainer.Clock = decoupledClock; storyboardContainer.Clock = decoupledClock;
storyboard = working.Storyboard.CreateDrawable(beatmapBacking); storyboard = working.Storyboard.CreateDrawable(Beatmap);
storyboard.Passing = false; storyboard.Passing = false;
storyboardContainer.Add(storyboard); storyboardContainer.Add(storyboard);

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