1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-13 08:32:57 +08:00

Merge branch 'master' into catch-droplet-fix

This commit is contained in:
Dan Balasescu 2018-06-13 15:18:52 +09:00 committed by GitHub
commit cbb883614a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
270 changed files with 4997 additions and 3413 deletions

5
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "osu-framework"]
path = osu-framework
url = https://github.com/ppy/osu-framework
[submodule "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">
<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="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests" />
<option name="PASS_PARENT_ENVS" value="1" />
<envs>
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
</envs>
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="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_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" />
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" />
<method />
</configuration>

View File

@ -1,21 +1,17 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (mania)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/net471/osu.Game.Rulesets.Mania.Tests.exe" />
<option name="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="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests" />
<option name="PASS_PARENT_ENVS" value="1" />
<envs>
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
</envs>
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="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_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" />
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" />
<method />
</configuration>

View File

@ -1,21 +1,17 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (osu!)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/net471/osu.Game.Rulesets.Osu.Tests.exe" />
<option name="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="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests" />
<option name="PASS_PARENT_ENVS" value="1" />
<envs>
<env name="ASPNETCORE_ENVIRONMENT" value="Development" />
<env name="ASPNETCORE_URLS" value="http://localhost:5000" />
</envs>
<option name="USE_MONO" value="0" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="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_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" />
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" />
<method />
</configuration>

View File

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

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

80
.vscode/launch.json vendored
View File

@ -2,110 +2,54 @@
"version": "0.2.0",
"configurations": [
{
"name": "VisualTests (Debug, net471)",
"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/Debug/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)",
"name": "VisualTests (Debug)",
"type": "coreclr",
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll"
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.1/osu.Game.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, dotnet)",
"preLaunchTask": "Build tests (Debug)",
"env": {},
"console": "internalConsole"
},
{
"name": "VisualTests (Release, netcoreapp2.0)",
"name": "VisualTests (Release)",
"type": "coreclr",
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.0/osu.Game.Tests.dll"
"${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.1/osu.Game.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, dotnet)",
"preLaunchTask": "Build tests (Release)",
"env": {},
"console": "internalConsole"
},
{
"name": "osu! (Debug, netcoreapp2.0)",
"name": "osu! (Debug)",
"type": "coreclr",
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.0/osu!.dll",
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll",
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, dotnet)",
"preLaunchTask": "Build osu! (Debug)",
"env": {},
"console": "internalConsole"
},
{
"name": "osu! (Release, netcoreapp2.0)",
"name": "osu! (Release)",
"type": "coreclr",
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.0/osu!.dll",
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1/osu!.dll",
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, dotnet)",
"preLaunchTask": "Build osu! (Release)",
"env": {},
"console": "internalConsole"
}

69
.vscode/tasks.json vendored
View File

@ -4,41 +4,14 @@
"version": "2.0.0",
"tasks": [
{
"label": "Build (Debug, msbuild)",
"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 (Debug, dotnet)",
"label": "Build osu! (Debug)",
"type": "shell",
"command": "dotnet",
"args": [
"build",
"--no-restore",
"osu.Desktop",
"/p:TargetFramework=netcoreapp2.0",
"/p:TargetFramework=netcoreapp2.1",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
@ -47,14 +20,14 @@
"problemMatcher": "$msCompile"
},
{
"label": "Build (Release, dotnet)",
"label": "Build osu! (Release)",
"type": "shell",
"command": "dotnet",
"args": [
"build",
"--no-restore",
"osu.Desktop",
"/p:TargetFramework=netcoreapp2.0",
"/p:TargetFramework=netcoreapp2.1",
"/p:Configuration=Release",
"/p:GenerateFullPaths=true",
"/m",
@ -64,16 +37,40 @@
"problemMatcher": "$msCompile"
},
{
"label": "Restore (net471)",
"label": "Build tests (Debug)",
"type": "shell",
"command": "nuget",
"command": "dotnet",
"args": [
"restore"
"build",
"--no-restore",
"osu.Game.Tests",
"/p:TargetFramework=netcoreapp2.1",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
],
"problemMatcher": []
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Restore (netcoreapp2.0)",
"label": "Build tests (Release)",
"type": "shell",
"command": "dotnet",
"args": [
"build",
"--no-restore",
"osu.Game.Tests",
"/p:TargetFramework=netcoreapp2.1",
"/p:Configuration=Release",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Restore (netcoreapp2.1)",
"type": "shell",
"command": "dotnet",
"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}'
image: Visual Studio 2017
configuration: Debug
cache:
- C:\ProgramData\chocolatey\bin -> appveyor.yml
- C:\ProgramData\chocolatey\lib -> appveyor.yml
- inspectcode -> appveyor.yml
- packages -> **\packages.config
install:
- cmd: git submodule update --init --recursive --depth=5
- cmd: choco install resharper-clt -y

View File

@ -1,29 +1,24 @@
branches:
only:
- release
skip_tags: true
skip_branch_with_pr: true
clone_depth: 1
version: '{branch}-{build}'
version: '{build}'
skip_non_tags: true
image: Visual Studio 2017
configuration: Debug
cache:
- packages -> **\packages.config
install:
- cmd: git submodule update --init --recursive --depth=5
- git clone https://github.com/ppy/osu-deploy
before_build:
- ps: if($env:appveyor_repo_tag -eq 'True') { Update-AppveyorBuild -Version $env:appveyor_repo_tag_name }
- cmd: git submodule update --init --recursive --depth=5
- cmd: nuget restore -verbosity quiet
build:
project: osu.Desktop.Deploy/osu.Desktop.Deploy.csproj
verbosity: minimal
after_build:
build_script:
- ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1'))
- appveyor DownloadFile https://puu.sh/A6g5K/4d08705438.enc # signing certificate
- cmd: appveyor-tools\secure-file -decrypt 4d08705438.enc -secret %decode_secret% -out %HOMEPATH%\deanherbert.pfx
- appveyor DownloadFile https://puu.sh/A6g75/fdc6f19b04.enc # deploy configuration
- cmd: appveyor-tools\secure-file -decrypt fdc6f19b04.enc -secret %decode_secret% -out osu.Desktop.Deploy\bin\Debug\net471\osu.Desktop.Deploy.exe.config
- cd osu.Desktop.Deploy\bin\Debug\net471\
- osu.Desktop.Deploy.exe %code_signing_password%
- cd osu-deploy
- nuget restore -verbosity quiet
- msbuild osu.Desktop.Deploy.csproj
- cmd: ..\appveyor-tools\secure-file -decrypt ..\fdc6f19b04.enc -secret %decode_secret% -out bin\Debug\net471\osu.Desktop.Deploy.exe.config
- cd bin\Debug\net471\
- osu.Desktop.Deploy.exe %code_signing_password% %APPVEYOR_REPO_TAG_NAME%
environment:
TargetFramework: net471
decode_secret:
@ -31,4 +26,7 @@ environment:
code_signing_password:
secure: 34tLNqvjmmZEi97MLKfrnQ==
artifacts:
- path: 'Releases\*'
- path: 'Releases\*'
deploy:
- provider: Environment
name: github

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

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

@ -12,6 +12,7 @@ using osu.Framework.Platform;
using osu.Game;
using OpenTK.Input;
using Microsoft.Win32;
using osu.Framework.Platform.Windows;
namespace osu.Desktop
{
@ -40,7 +41,7 @@ namespace osu.Desktop
/// <summary>
/// A method of accessing an osu-stable install in a controlled fashion.
/// </summary>
private class StableStorage : DesktopStorage
private class StableStorage : WindowsStorage
{
protected override string LocateBasePath()
{

View File

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

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\osu.Game.props" />
<PropertyGroup Label="Project">
<TargetFrameworks>net471;netcoreapp2.0</TargetFrameworks>
<TargetFrameworks>net471;netcoreapp2.1</TargetFrameworks>
<OutputType>WinExe</OutputType>
<PlatformTarget>AnyCPU</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@ -20,20 +20,19 @@
<StartupObject>osu.Desktop.Program</StartupObject>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj" />
<ProjectReference Include="..\osu.Game\osu.Game.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.Mania\osu.Game.Rulesets.Mania.csproj" />
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.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 Label="Package References">
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0" />
<PackageReference Include="squirrel.windows" Version="1.8.0" Condition="'$(TargetFramework)' == 'net471'" />
</ItemGroup>
<ItemGroup Label="Resources">
<EmbeddedResource Include="lazer.ico" />
</ItemGroup>
</Project>
</Project>

View File

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

View File

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

View File

@ -53,10 +53,10 @@ namespace osu.Game.Rulesets.Catch.Tests
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() });
return base.CreatePlayer(beatmap, ruleset);
Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
return base.CreatePlayer(ruleset);
}
}
}

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Catch.Tests
Child = catcherArea = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size })
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.BottomLeft
Origin = Anchor.TopLeft
},
};
}

View File

@ -25,6 +25,7 @@ namespace osu.Game.Rulesets.Catch.Tests
typeof(DrawableCatchHitObject),
typeof(DrawableFruit),
typeof(DrawableDroplet),
typeof(BananaShower),
typeof(Pulp),
};
@ -53,12 +54,19 @@ namespace osu.Game.Rulesets.Catch.Tests
private DrawableFruit createDrawable(int index)
{
var fruit = new Fruit
{
StartTime = 1000000000000,
IndexInBeatmap = index,
Scale = 1.5f,
};
Fruit fruit = index == 5
? new BananaShower.Banana
{
StartTime = 1000000000000,
IndexInBeatmap = index,
Scale = 1.5f,
}
: new Fruit
{
StartTime = 1000000000000,
IndexInBeatmap = index,
Scale = 1.5f,
};
return new DrawableFruit(fruit)
{

View File

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

View File

@ -28,7 +28,20 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
var endTime = obj as IHasEndTime;
if (positionData == null)
{
if (endTime != null)
{
yield return new BananaShower
{
StartTime = obj.StartTime,
Samples = obj.Samples,
Duration = endTime.Duration,
NewCombo = comboData?.NewCombo ?? false
};
}
yield break;
}
if (curveData != null)
{
@ -48,19 +61,6 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
yield break;
}
if (endTime != null)
{
yield return new BananaShower
{
StartTime = obj.StartTime,
Samples = obj.Samples,
Duration = endTime.Duration,
NewCombo = comboData?.NewCombo ?? false
};
yield break;
}
yield return new Fruit
{
StartTime = obj.StartTime,

View File

@ -82,56 +82,25 @@ namespace osu.Game.Rulesets.Catch
{
new CatchModEasy(),
new CatchModNoFail(),
new MultiMod
{
Mods = new Mod[]
{
new CatchModHalfTime(),
new CatchModDaycore(),
},
},
new MultiMod(new CatchModHalfTime(), new CatchModDaycore())
};
case ModType.DifficultyIncrease:
return new Mod[]
{
new CatchModHardRock(),
new MultiMod
{
Mods = new Mod[]
{
new CatchModSuddenDeath(),
new CatchModPerfect(),
},
},
new MultiMod
{
Mods = new Mod[]
{
new CatchModDoubleTime(),
new CatchModNightcore(),
},
},
new MultiMod(new CatchModSuddenDeath(), new CatchModPerfect()),
new MultiMod(new CatchModDoubleTime(), new CatchModNightcore()),
new CatchModHidden(),
new CatchModFlashlight(),
};
case ModType.Special:
return new Mod[]
{
new CatchModRelax(),
null,
null,
new MultiMod
{
Mods = new Mod[]
{
new CatchModAutoplay(),
new ModCinema(),
},
},
new MultiMod(new CatchModAutoplay(), new ModCinema()),
};
default:
return new Mod[] { };
}

View File

@ -18,12 +18,19 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
private Circle border;
private const float drawable_radius = (float)CatchHitObject.OBJECT_RADIUS * radius_adjust;
/// <summary>
/// Because we're adding a border around the fruit, we need to scale down some.
/// </summary>
private const float radius_adjust = 1.1f;
public DrawableFruit(Fruit h)
: base(h)
{
Origin = Anchor.Centre;
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS);
Size = new Vector2(drawable_radius);
Masking = false;
Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
@ -44,14 +51,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
Hollow = !HitObject.HyperDash,
Type = EdgeEffectType.Glow,
Radius = 4,
Radius = 4 * radius_adjust,
Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Darken(1).Opacity(0.6f)
},
Size = new Vector2(Height * 1.5f),
Size = new Vector2(Height),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
BorderColour = Color4.White,
BorderThickness = 4f,
BorderThickness = 3f * radius_adjust,
Children = new Framework.Graphics.Drawable[]
{
new Box
@ -82,8 +89,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
private Framework.Graphics.Drawable createPulp(FruitVisualRepresentation representation)
{
const float large_pulp_3 = 13f;
const float distance_from_centre_3 = 0.23f;
const float large_pulp_3 = 8f * radius_adjust;
const float distance_from_centre_3 = 0.15f;
const float large_pulp_4 = large_pulp_3 * 0.925f;
const float distance_from_centre_4 = distance_from_centre_3 / 0.925f;
@ -106,11 +113,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
new Pulp
{
Anchor = Anchor.TopCentre,
Origin = Anchor.BottomCentre,
AccentColour = AccentColour,
Size = new Vector2(small_pulp),
Y = 0.05f,
Y = -0.34f,
},
new Pulp
{
@ -146,11 +151,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
new Pulp
{
Anchor = Anchor.TopCentre,
Origin = Anchor.BottomCentre,
AccentColour = AccentColour,
Size = new Vector2(small_pulp),
Y = 0.1f,
Y = -0.3f,
},
new Pulp
{
@ -186,11 +189,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
new Pulp
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
AccentColour = AccentColour,
Size = new Vector2(small_pulp),
Y = -0.1f,
Y = -0.33f,
},
new Pulp
{
@ -220,10 +221,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
new Pulp
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
AccentColour = AccentColour,
Size = new Vector2(small_pulp),
Y = -0.25f,
},
new Pulp
{
@ -253,16 +253,15 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
new Pulp
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
AccentColour = AccentColour,
Size = new Vector2(small_pulp),
Y = -0.15f
Y = -0.3f
},
new Pulp
{
AccentColour = AccentColour,
Size = new Vector2(large_pulp_4 * 1.2f, large_pulp_4 * 3),
Size = new Vector2(large_pulp_4 * 0.8f, large_pulp_4 * 2.5f),
Y = 0.05f,
},
}
};

View File

@ -29,14 +29,24 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
set
{
accentColour = value;
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Radius = 8,
Colour = accentColour.Darken(0.2f).Opacity(0.75f)
};
if (IsLoaded) updateAccentColour();
}
}
private void updateAccentColour()
{
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Radius = Size.X / 2,
Colour = accentColour.Darken(0.2f).Opacity(0.75f)
};
}
protected override void LoadComplete()
{
base.LoadComplete();
updateAccentColour();
}
}
}

View File

@ -32,6 +32,8 @@ namespace osu.Game.Rulesets.Catch.UI
public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
protected override Vector2 PlayfieldArea => new Vector2(0.86f); // matches stable's vertical offset for catcher plate
protected override DrawableHitObject<CatchHitObject> GetVisualRepresentation(CatchHitObject h)
{
switch (h)

View File

@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.UI
{
public class CatcherArea : Container
{
public const float CATCHER_SIZE = 172;
public const float CATCHER_SIZE = 84;
protected readonly Catcher MovableCatcher;
@ -99,8 +99,6 @@ namespace osu.Game.Rulesets.Catch.UI
public class Catcher : Container, IKeyBindingHandler<CatchAction>
{
private Texture texture;
private Container<DrawableHitObject> caughtFruit;
public Container ExplodingFruitTarget;
@ -121,10 +119,8 @@ namespace osu.Game.Rulesets.Catch.UI
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
private void load()
{
texture = textures.Get(@"Play/Catch/fruit-catcher-idle");
Children = new Drawable[]
{
caughtFruit = new Container<DrawableHitObject>
@ -196,13 +192,7 @@ namespace osu.Game.Rulesets.Catch.UI
Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50);
}
private Sprite createCatcherSprite() => new Sprite
{
Size = new Vector2(CATCHER_SIZE),
FillMode = FillMode.Fill,
Texture = texture,
OriginPosition = new Vector2(-3, 10) // temporary until the sprite is aligned correctly.
};
private Sprite createCatcherSprite() => new CatcherSprite();
/// <summary>
/// Add a caught fruit to the catcher's stack.
@ -411,6 +401,23 @@ namespace osu.Game.Rulesets.Catch.UI
f.Expire();
}
}
private class CatcherSprite : Sprite
{
public CatcherSprite()
{
Size = new Vector2(CATCHER_SIZE);
// Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling.
OriginPosition = new Vector2(-0.02f, 0.06f) * CATCHER_SIZE;
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
Texture = textures.Get(@"Play/Catch/fruit-catcher-idle");
}
}
}
}
}

View File

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

View File

@ -40,7 +40,7 @@
"build",
"--no-restore",
"osu.Game.Rulesets.Mania.Tests.csproj",
"/p:TargetFramework=netcoreapp2.0",
"/p:TargetFramework=netcoreapp2.1",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
@ -56,7 +56,7 @@
"build",
"--no-restore",
"osu.Game.Rulesets.Mania.Tests.csproj",
"/p:TargetFramework=netcoreapp2.0",
"/p:TargetFramework=netcoreapp2.1",
"/p:Configuration=Release",
"/p:GenerateFullPaths=true",
"/m",
@ -75,7 +75,7 @@
"problemMatcher": []
},
{
"label": "Restore (netcoreapp2.0)",
"label": "Restore (netcoreapp2.1)",
"type": "shell",
"command": "dotnet",
"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]
private void load(RulesetStore rulesets, SettingsStore settings)
{
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)

View File

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

View File

@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Mania.Configuration
{
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)
{
}

View File

@ -7,6 +7,7 @@ using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods;
@ -141,5 +142,22 @@ namespace osu.Game.Rulesets.Mania.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

@ -105,7 +105,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty
private double computeAccuracyValue(double strainValue)
{
double hitWindowGreat = (Beatmap.HitObjects.First().HitWindows.Great / 2 - 0.5) / TimeRate;
// Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future
double hitWindowGreat = (int)(Beatmap.HitObjects.First().HitWindows.Great / 2) / TimeRate;
if (hitWindowGreat <= 0)
return 0;

View File

@ -15,8 +15,11 @@ using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Replays.Types;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Configuration;
using osu.Game.Rulesets.Configuration;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.Difficulty;
using osu.Game.Rulesets.Scoring;
@ -105,78 +108,34 @@ namespace osu.Game.Rulesets.Mania
{
new ManiaModEasy(),
new ManiaModNoFail(),
new MultiMod
{
Mods = new Mod[]
{
new ManiaModHalfTime(),
new ManiaModDaycore(),
},
},
new MultiMod(new ManiaModHalfTime(), new ManiaModDaycore()),
};
case ModType.DifficultyIncrease:
return new Mod[]
{
new ManiaModHardRock(),
new MultiMod
{
Mods = new Mod[]
{
new ManiaModSuddenDeath(),
new ManiaModPerfect(),
},
},
new MultiMod
{
Mods = new Mod[]
{
new ManiaModDoubleTime(),
new ManiaModNightcore(),
},
},
new MultiMod
{
Mods = new Mod[]
{
new ManiaModFadeIn(),
new ManiaModHidden(),
}
},
new MultiMod(new ManiaModSuddenDeath(), new ManiaModPerfect()),
new MultiMod(new ManiaModDoubleTime(), new ManiaModNightcore()),
new MultiMod(new ManiaModFadeIn(), new ManiaModHidden()),
new ManiaModFlashlight(),
};
case ModType.Special:
return new Mod[]
{
new MultiMod
{
Mods = new Mod[]
{
new ManiaModKey4(),
new ManiaModKey5(),
new ManiaModKey6(),
new ManiaModKey7(),
new ManiaModKey8(),
new ManiaModKey9(),
new ManiaModKey1(),
new ManiaModKey2(),
new ManiaModKey3(),
},
},
new MultiMod(new ManiaModKey4(),
new ManiaModKey5(),
new ManiaModKey6(),
new ManiaModKey7(),
new ManiaModKey8(),
new ManiaModKey9(),
new ManiaModKey1(),
new ManiaModKey2(),
new ManiaModKey3()),
new ManiaModRandom(),
new ManiaModDualStages(),
new ManiaModMirror(),
new MultiMod
{
Mods = new Mod[]
{
new ManiaModAutoplay(),
new ModCinema(),
},
},
new MultiMod(new ManiaModAutoplay(), new ModCinema()),
};
default:
return new Mod[] { };
}
@ -194,6 +153,8 @@ namespace osu.Game.Rulesets.Mania
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame();
public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new ManiaConfigManager(settings, RulesetInfo);
public ManiaRuleset(RulesetInfo rulesetInfo = null)
: base(rulesetInfo)
{

View File

@ -1,6 +1,8 @@
// 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.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mods;
@ -24,5 +26,18 @@ namespace osu.Game.Rulesets.Mania.Mods
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

@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Name => "Dual Stages";
public override string ShortenedName => "DS";
public override string Description => @"Double the stages, double the fun!";
public override double ScoreMultiplier => 0;
public override double ScoreMultiplier => 1;
private bool isForCurrentRuleset;

View File

@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string ShortenedName => "RD";
public override FontAwesome Icon => FontAwesome.fa_osu_dice;
public override string Description => @"Shuffle around the keys!";
public override double ScoreMultiplier => 0;
public override double ScoreMultiplier => 1;
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
{

View File

@ -5,6 +5,7 @@ using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Objects.Drawables;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
@ -28,7 +29,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
: base(barLine)
{
RelativeSizeAxes = Axes.X;
Height = 1;
Height = 2f;
AddInternal(new Box
{
@ -36,6 +37,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.Both,
Colour = new Color4(255, 204, 33, 255),
});
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
using System.Linq;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using OpenTK.Graphics;
@ -18,12 +18,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary>
public class DrawableHoldNote : DrawableManiaHitObject<HoldNote>, IKeyBindingHandler<ManiaAction>
{
public override bool DisplayJudgement => false;
private readonly DrawableNote head;
private readonly DrawableNote tail;
private readonly GlowPiece glowPiece;
private readonly BodyPiece bodyPiece;
private readonly Container fullHeightContainer;
/// <summary>
/// Time at which the user started holding this hold note. Null if the user is not holding this hold note.
@ -35,25 +35,17 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary>
private bool hasBroken;
private readonly Container<DrawableHoldNoteTick> tickContainer;
public DrawableHoldNote(HoldNote hitObject, ManiaAction action)
: base(hitObject, action)
{
Container<DrawableHoldNoteTick> tickContainer;
RelativeSizeAxes = Axes.X;
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
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
},
tickContainer = new Container<DrawableHoldNoteTick>
@ -90,21 +82,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
base.AccentColour = value;
glowPiece.AccentColour = value;
bodyPiece.AccentColour = value;
head.AccentColour = value;
tail.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;
tickContainer.ForEach(t => t.AccentColour = value);
}
}
@ -119,12 +100,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
base.Update();
// Make the body piece not lie under the head note
bodyPiece.Y = head.Height;
bodyPiece.Height = DrawHeight - head.Height;
// 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;
bodyPiece.Y = head.Height / 2;
bodyPiece.Height = DrawHeight - head.Height / 2 + tail.Height / 2;
}
public bool OnPressed(ManiaAction action)
@ -173,8 +150,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
: base(holdNote.HitObject.Head, action)
{
this.holdNote = holdNote;
GlowPiece.Alpha = 0;
}
public override bool OnPressed(ManiaAction action)
@ -192,11 +167,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
return true;
}
protected override void UpdateState(ArmedState state)
{
// The holdnote keeps scrolling through for now, so having the head disappear looks weird
}
}
/// <summary>
@ -217,8 +187,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
: base(holdNote.HitObject.Tail, action)
{
this.holdNote = holdNote;
GlowPiece.Alpha = 0;
}
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
@ -251,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 OnReleased(ManiaAction action)

View File

@ -8,7 +8,6 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Scoring;
@ -87,16 +86,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
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()
{
if (AllJudged)

View File

@ -27,5 +27,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (action != null)
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>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Extensions.Color4Extensions;
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Objects.Drawables
@ -16,9 +17,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary>
public class DrawableNote : DrawableManiaHitObject<Note>, IKeyBindingHandler<ManiaAction>
{
protected readonly GlowPiece GlowPiece;
private readonly LaneGlowPiece laneGlowPiece;
private readonly NotePiece headPiece;
public DrawableNote(Note hitObject, ManiaAction action)
@ -27,14 +25,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
CornerRadius = 5;
Masking = true;
InternalChildren = new Drawable[]
{
laneGlowPiece = new LaneGlowPiece
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
},
GlowPiece = new GlowPiece(),
headPiece = new NotePiece
{
Anchor = Anchor.TopCentre,
@ -49,9 +44,14 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
set
{
base.AccentColour = value;
laneGlowPiece.AccentColour = AccentColour;
GlowPiece.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 });
}
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)
{
if (action != Action)

View File

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

View File

@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
/// </summary>
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 readonly Box colouredBox;
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
public NotePiece()
{
RelativeSizeAxes = Axes.X;
Height = head_height;
Height = NOTE_HEIGHT;
Children = new[]
{

View File

@ -33,6 +33,7 @@ namespace osu.Game.Rulesets.Mania.UI
public ManiaAction Action;
private readonly Box background;
private readonly Box backgroundOverlay;
private readonly Container hitTargetBar;
private readonly Container keyIcon;
@ -42,22 +43,32 @@ namespace osu.Game.Rulesets.Mania.UI
protected override Container<Drawable> Content => content;
private readonly Container<Drawable> content;
private const float opacity_released = 0.1f;
private const float opacity_pressed = 0.25f;
public Column()
: base(ScrollingDirection.Up)
{
RelativeSizeAxes = Axes.Y;
Width = column_width;
Masking = true;
CornerRadius = 5;
InternalChildren = new Drawable[]
{
background = new Box
{
Name = "Background",
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
{
@ -182,6 +193,7 @@ namespace osu.Game.Rulesets.Mania.UI
accentColour = value;
background.Colour = accentColour;
backgroundOverlay.Colour = ColourInfo.GradientVertical(accentColour.Opacity(0.6f), accentColour.Opacity(0));
hitTargetBar.EdgeEffect = new EdgeEffectParameters
{
@ -213,7 +225,7 @@ namespace osu.Game.Rulesets.Mania.UI
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
{
if (!judgement.IsHit)
if (!judgement.IsHit || !judgedObject.DisplayJudgement)
return;
explosionContainer.Add(new HitExplosion(judgedObject));
@ -223,8 +235,8 @@ namespace osu.Game.Rulesets.Mania.UI
{
if (action == Action)
{
background.FadeTo(opacity_pressed, 50, Easing.OutQuint);
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint);
backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint);
}
return false;
@ -234,8 +246,8 @@ namespace osu.Game.Rulesets.Mania.UI
{
if (action == Action)
{
background.FadeTo(opacity_released, 800, Easing.OutQuart);
keyIcon.ScaleTo(1f, 400, Easing.OutQuart);
backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
}
return false;
@ -265,8 +277,13 @@ namespace osu.Game.Rulesets.Mania.UI
if (action != Action)
return false;
var hitObject = HitObjects.Objects.LastOrDefault(h => h.HitObject.StartTime > Time.Current) ?? HitObjects.Objects.FirstOrDefault();
hitObject?.PlaySamples();
var nextObject =
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;
}

View File

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

View File

@ -10,12 +10,9 @@ using osu.Framework.Input;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Configuration;
using osu.Game.Input.Handlers;
using osu.Game.Rulesets.Configuration;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.Configuration;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Replays;
@ -103,7 +100,5 @@ namespace osu.Game.Rulesets.Mania.UI
protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f);
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.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
@ -78,6 +77,7 @@ namespace osu.Game.Rulesets.Mania.UI
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Masking = true,
CornerRadius = 5,
Children = new Drawable[]
{
new Box
@ -171,6 +171,9 @@ namespace osu.Game.Rulesets.Mania.UI
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
{
if (!judgedObject.DisplayJudgement)
return;
judgements.Clear();
judgements.Add(new DrawableManiaJudgement(judgement, judgedObject)
{
@ -180,15 +183,15 @@ namespace osu.Game.Rulesets.Mania.UI
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load()
{
normalColumnColours = new List<Color4>
{
colours.RedDark,
colours.GreenDark
new Color4(94, 0, 57, 255),
new Color4(6, 84, 0, 255)
};
specialColumnColour = colours.BlueDark;
specialColumnColour = new Color4(0, 48, 63, 255);
// Set the special column + colour + key
foreach (var column in Columns)

View File

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

View File

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

View File

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

View File

@ -8,6 +8,7 @@ using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Difficulty.Skills;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Difficulty
@ -71,5 +72,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty
return starRating;
}
protected override Mod[] DifficultyAdjustmentMods => new Mod[]
{
new OsuModDoubleTime(),
new OsuModHalfTime(),
new OsuModEasy(),
new OsuModHardRock(),
};
}
}

View File

@ -61,11 +61,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty
if (mods.Any(m => !m.Ranked))
return 0;
double hitWindowGreat = (Beatmap.HitObjects.First().HitWindows.Great / 2 - 0.5) / TimeRate;
double preEmpt = BeatmapDifficulty.DifficultyRange(Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / TimeRate;
// Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future
double hitWindowGreat = (int)(Beatmap.HitObjects.First().HitWindows.Great / 2) / TimeRate;
double preEmpt = (int)BeatmapDifficulty.DifficultyRange(Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / TimeRate;
realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5;
realOverallDifficulty = (80 - 0.5 - hitWindowGreat) / 6;
realOverallDifficulty = (80 - hitWindowGreat) / 6;
// Custom multipliers for NoFail and SpunOut.
double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things

View File

@ -13,8 +13,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string ShortenedName => "AP";
public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot;
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
public override double ScoreMultiplier => 0;
public override bool Ranked => false;
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModSuddenDeath), typeof(ModNoFail), typeof(ModAutoplay) };
}
}

View File

@ -7,33 +7,34 @@ using System.Linq;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
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 double ScoreMultiplier => 1.06;
private const double fade_in_duration_multiplier = 0.4;
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>())
{
d.ApplyCustomUpdateState += ApplyHiddenState;
d.HitObject.TimeFadein = d.HitObject.TimePreempt * fade_in_duration_multiplier;
adjustFadeIn(d.HitObject);
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))
return;

View File

@ -93,57 +93,26 @@ namespace osu.Game.Rulesets.Osu
{
new OsuModEasy(),
new OsuModNoFail(),
new MultiMod
{
Mods = new Mod[]
{
new OsuModHalfTime(),
new OsuModDaycore(),
},
},
new MultiMod(new OsuModHalfTime(), new OsuModDaycore()),
};
case ModType.DifficultyIncrease:
return new Mod[]
{
new OsuModHardRock(),
new MultiMod
{
Mods = new Mod[]
{
new OsuModSuddenDeath(),
new OsuModPerfect(),
},
},
new MultiMod
{
Mods = new Mod[]
{
new OsuModDoubleTime(),
new OsuModNightcore(),
},
},
new MultiMod(new OsuModSuddenDeath(), new OsuModPerfect()),
new MultiMod(new OsuModDoubleTime(), new OsuModNightcore()),
new OsuModHidden(),
new OsuModFlashlight(),
};
case ModType.Special:
return new Mod[]
{
new OsuModRelax(),
new OsuModAutopilot(),
new OsuModSpunOut(),
new MultiMod
{
Mods = new Mod[]
{
new OsuModAutoplay(),
new ModCinema(),
},
},
new MultiMod(new OsuModAutoplay(), new ModCinema()),
new OsuModTarget(),
};
default:
return new Mod[] { };
}
@ -161,7 +130,7 @@ namespace osu.Game.Rulesets.Osu
public override string ShortName => "osu";
public override SettingsSubsection CreateSettings() => new OsuSettings();
public override RulesetSettingsSubsection CreateSettings() => new OsuSettings(this);
public override int? LegacyID => 0;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,7 @@
<Import Project="..\osu.TestProject.props" />
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFrameworks>netcoreapp2.0;net471</TargetFrameworks>
<TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
</PropertyGroup>
<ItemGroup Label="Project References">
<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.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Mods;
using osu.Game.Rulesets.Taiko.Objects;
namespace osu.Game.Rulesets.Taiko.Difficulty
@ -62,6 +63,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
return starRating;
}
protected override Mod[] DifficultyAdjustmentMods => new Mod[]
{
new TaikoModDoubleTime(),
new TaikoModHalfTime(),
new TaikoModEasy(),
new TaikoModHardRock(),
};
private bool calculateStrainValues()
{
// Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment.

View File

@ -94,7 +94,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
private double computeAccuracyValue()
{
double hitWindowGreat = (Beatmap.HitObjects.First().HitWindows.Great / 2 - 0.5) / TimeRate;
// Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be remoevd in the future
double hitWindowGreat = (int)(Beatmap.HitObjects.First().HitWindows.Great / 2) / TimeRate;
if (hitWindowGreat <= 0)
return 0;

View File

@ -84,56 +84,25 @@ namespace osu.Game.Rulesets.Taiko
{
new TaikoModEasy(),
new TaikoModNoFail(),
new MultiMod
{
Mods = new Mod[]
{
new TaikoModHalfTime(),
new TaikoModDaycore(),
},
},
new MultiMod(new TaikoModHalfTime(), new TaikoModDaycore()),
};
case ModType.DifficultyIncrease:
return new Mod[]
{
new TaikoModHardRock(),
new MultiMod
{
Mods = new Mod[]
{
new TaikoModSuddenDeath(),
new TaikoModPerfect(),
},
},
new MultiMod
{
Mods = new Mod[]
{
new TaikoModDoubleTime(),
new TaikoModNightcore(),
},
},
new MultiMod(new TaikoModSuddenDeath(), new TaikoModPerfect()),
new MultiMod(new TaikoModDoubleTime(), new TaikoModNightcore()),
new TaikoModHidden(),
new TaikoModFlashlight(),
};
case ModType.Special:
return new Mod[]
{
new TaikoModRelax(),
null,
null,
new MultiMod
{
Mods = new Mod[]
{
new TaikoModAutoplay(),
new ModCinema(),
},
},
new MultiMod(new TaikoModAutoplay(), new ModCinema()),
};
default:
return new Mod[] { };
}

View File

@ -86,7 +86,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.AreEqual(string.Empty, metadata.Source);
Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags);
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 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.ArtistUnicode);
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);

View File

@ -12,6 +12,7 @@ using osu.Framework.Platform;
using osu.Game.IPC;
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using SharpCompress.Archives.Zip;
namespace osu.Game.Tests.Beatmaps.IO
{
@ -77,8 +78,69 @@ namespace osu.Game.Tests.Beatmaps.IO
var manager = osu.Dependencies.Get<BeatmapManager>();
Assert.IsTrue(manager.GetAllUsableBeatmapSets().Count == 1);
Assert.IsTrue(manager.QueryBeatmapSets(_ => true).ToList().Count == 1);
Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count);
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
}
finally
{
host.Exit();
}
}
}
[Test]
public void TestRollbackOnFailure()
{
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestRollbackOnFailure"))
{
try
{
var osu = loadOsu(host);
var manager = osu.Dependencies.Get<BeatmapManager>();
int fireCount = 0;
// ReSharper disable once AccessToModifiedClosure
manager.ItemAdded += _ => fireCount++;
manager.ItemRemoved += _ => fireCount++;
var imported = loadOszIntoOsu(osu);
Assert.AreEqual(0, fireCount -= 1);
imported.Hash += "-changed";
manager.Update(imported);
Assert.AreEqual(0, fireCount -= 2);
var breakTemp = createTemporaryBeatmap();
MemoryStream brokenOsu = new MemoryStream(new byte[] { 1, 3, 3, 7 });
MemoryStream brokenOsz = new MemoryStream(File.ReadAllBytes(breakTemp));
File.Delete(breakTemp);
using (var outStream = File.Open(breakTemp, FileMode.CreateNew))
using (var zip = ZipArchive.Open(brokenOsz))
{
zip.AddEntry("broken.osu", brokenOsu, false);
zip.SaveTo(outStream, SharpCompress.Common.CompressionType.Deflate);
}
Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count);
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
Assert.AreEqual(12, manager.QueryBeatmaps(_ => true).ToList().Count);
// this will trigger purging of the existing beatmap (online set id match) but should rollback due to broken osu.
manager.Import(breakTemp);
// no events should be fired in the case of a rollback.
Assert.AreEqual(0, fireCount);
Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count);
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
Assert.AreEqual(12, manager.QueryBeatmaps(_ => true).ToList().Count);
}
finally
{
@ -100,18 +162,17 @@ namespace osu.Game.Tests.Beatmaps.IO
var imported = loadOszIntoOsu(osu);
//var change = manager.QueryBeatmapSets(_ => true).First();
imported.Hash += "-changed";
manager.Update(imported);
var importedSecondTime = loadOszIntoOsu(osu);
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
Assert.IsTrue(imported.ID != importedSecondTime.ID);
Assert.IsTrue(imported.Beatmaps.First().ID < importedSecondTime.Beatmaps.First().ID);
Assert.IsTrue(manager.GetAllUsableBeatmapSets().Count == 1);
Assert.IsTrue(manager.QueryBeatmapSets(_ => true).ToList().Count == 1);
// only one beatmap will exist as the online set ID matched, causing purging of the first import.
Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count);
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
}
finally
{
@ -162,8 +223,7 @@ namespace osu.Game.Tests.Beatmaps.IO
var osu = loadOsu(host);
var temp = prepareTempCopy(osz_path);
Assert.IsTrue(File.Exists(temp));
var temp = createTemporaryBeatmap();
var importer = new ArchiveImportIPCChannel(client);
if (!importer.ImportAsync(temp).Wait(10000))
@ -188,8 +248,7 @@ namespace osu.Game.Tests.Beatmaps.IO
try
{
var osu = loadOsu(host);
var temp = prepareTempCopy(osz_path);
Assert.IsTrue(File.Exists(temp), "Temporary file copy never substantiated");
var temp = createTemporaryBeatmap();
using (File.OpenRead(temp))
osu.Dependencies.Get<BeatmapManager>().Import(temp);
ensureLoaded(osu);
@ -203,11 +262,17 @@ namespace osu.Game.Tests.Beatmaps.IO
}
}
private BeatmapSetInfo loadOszIntoOsu(OsuGameBase osu)
private string createTemporaryBeatmap()
{
var temp = prepareTempCopy(osz_path);
var temp = Path.GetTempFileName() + ".osz";
File.Copy(osz_path, temp, true);
Assert.IsTrue(File.Exists(temp));
return temp;
}
private BeatmapSetInfo loadOszIntoOsu(OsuGameBase osu, string path = null)
{
var temp = path ?? createTemporaryBeatmap();
var manager = osu.Dependencies.Get<BeatmapManager>();
@ -219,7 +284,7 @@ namespace osu.Game.Tests.Beatmaps.IO
waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
return imported.FirstOrDefault();
return imported.LastOrDefault();
}
private void deleteBeatmapSet(BeatmapSetInfo imported, OsuGameBase osu)
@ -228,16 +293,10 @@ namespace osu.Game.Tests.Beatmaps.IO
manager.Delete(imported);
Assert.IsTrue(manager.GetAllUsableBeatmapSets().Count == 0);
Assert.IsTrue(manager.QueryBeatmapSets(_ => true).ToList().Count == 1);
Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
Assert.IsTrue(manager.QueryBeatmapSets(_ => true).First().DeletePending);
}
private string prepareTempCopy(string path)
{
var temp = Path.GetTempFileName();
return new FileInfo(path).CopyTo(temp, true).FullName;
}
private OsuGameBase loadOsu(GameHost host)
{
var osu = new OsuGameBase();
@ -286,12 +345,12 @@ namespace osu.Game.Tests.Beatmaps.IO
private void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 60000)
{
Action waitAction = () =>
Task task = Task.Run(() =>
{
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);
BeatmapMetadata meta;
using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu")))
meta = Decoder.GetDecoder<Beatmap>(stream).Decode(stream).Metadata;
Beatmap beatmap;
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.ArtistUnicode);
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
Assert.AreEqual("Deif", meta.AuthorString);
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("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags);
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 System.Collections.Generic;
using NUnit.Framework;
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)
{
DifficultyAdjustmentMods = mods;
}
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) => throw new NotImplementedException();
protected override Mod[] DifficultyAdjustmentMods { get; }
}
}
}

View File

@ -3,8 +3,8 @@
using System.ComponentModel;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual
@ -12,10 +12,22 @@ namespace osu.Game.Tests.Visual
[Description("Player instantiated with an autoplay mod.")]
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() });
return base.CreatePlayer(beatmap, ruleset);
Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
return new ScoreAccessiblePlayer
{
AllowPause = false,
AllowLeadIn = false,
AllowResults = false,
};
}
protected override bool ContinueCondition(Player player) => base.ContinueCondition(player) && ((ScoreAccessiblePlayer)player).ScoreProcessor.TotalScore > 0;
private class ScoreAccessiblePlayer : Player
{
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
}
}
}

View File

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

View File

@ -6,7 +6,6 @@ using System.Linq;
using NUnit.Framework;
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
@ -29,14 +28,11 @@ namespace osu.Game.Tests.Visual
private RulesetStore rulesets;
private TestBeatmapInfoWedge infoWedge;
private readonly List<IBeatmap> beatmaps = new List<IBeatmap>();
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
[BackgroundDependencyLoader]
private void load(OsuGameBase game, RulesetStore rulesets)
private void load(RulesetStore rulesets)
{
this.rulesets = rulesets;
beatmap.BindTo(game.Beatmap);
}
protected override void LoadComplete()
@ -53,11 +49,11 @@ namespace osu.Game.Tests.Visual
AddStep("show", () =>
{
infoWedge.State = Visibility.Visible;
infoWedge.UpdateBeatmap(beatmap);
infoWedge.Beatmap = Beatmap;
});
// select part is redundant, but wait for load isn't
selectBeatmap(beatmap.Value.Beatmap);
selectBeatmap(Beatmap.Value.Beatmap);
AddWaitStep(3);
@ -120,8 +116,8 @@ namespace osu.Game.Tests.Visual
{
selectNullBeatmap();
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 artist", () => infoWedge.Info.ArtistLabel.Text == beatmap.Default.BeatmapInfo.Metadata.Artist);
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 empty author", () => !infoWedge.Info.MapperContainer.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", () =>
{
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");
@ -143,8 +139,8 @@ namespace osu.Game.Tests.Visual
{
AddStep("select null beatmap", () =>
{
beatmap.Value = beatmap.Default;
infoWedge.UpdateBeatmap(beatmap);
Beatmap.Value = Beatmap.Default;
infoWedge.Beatmap = Beatmap;
});
}

View File

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

View File

@ -35,9 +35,6 @@ namespace osu.Game.Tests.Visual
typeof(MessageFormatter)
};
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent);
public TestCaseChatLink()
{
Add(textContainer = new TestChatLineContainer
@ -53,7 +50,7 @@ namespace osu.Game.Tests.Visual
private void load(OsuColour colours)
{
linkColour = colours.Blue;
dependencies.Cache(new ChatOverlay
Dependencies.Cache(new ChatOverlay
{
AvailableChannels =
{

View File

@ -19,12 +19,12 @@ namespace osu.Game.Tests.Visual
[TestFixture]
public class TestCaseCursors : ManualInputManagerTestCase
{
private readonly CursorOverrideContainer cursorOverrideContainer;
private readonly MenuCursorContainer menuCursorContainer;
private readonly CustomCursorBox[] cursorBoxes = new CustomCursorBox[6];
public TestCaseCursors()
{
Child = cursorOverrideContainer = new CursorOverrideContainer
Child = menuCursorContainer = new MenuCursorContainer
{
RelativeSizeAxes = Axes.Both,
Children = new[]
@ -99,7 +99,7 @@ namespace osu.Game.Tests.Visual
AddAssert("Check green cursor at mouse", () => checkAtMouse(cursorBoxes[0].Cursor));
AddStep("Move out", moveOut);
AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].Cursor));
AddAssert("Check global cursor visible", () => checkVisible(cursorOverrideContainer.Cursor));
AddAssert("Check global cursor visible", () => checkVisible(menuCursorContainer.Cursor));
}
/// <summary>
@ -112,11 +112,11 @@ namespace osu.Game.Tests.Visual
AddStep("Move to purple area", () => InputManager.MoveMouseTo(cursorBoxes[3]));
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].Cursor));
AddAssert("Check global cursor visible", () => checkVisible(cursorOverrideContainer.Cursor));
AddAssert("Check global cursor at mouse", () => checkAtMouse(cursorOverrideContainer.Cursor));
AddAssert("Check global cursor visible", () => checkVisible(menuCursorContainer.Cursor));
AddAssert("Check global cursor at mouse", () => checkAtMouse(menuCursorContainer.Cursor));
AddStep("Move out", moveOut);
AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor));
AddAssert("Check global cursor visible", () => checkVisible(cursorOverrideContainer.Cursor));
AddAssert("Check global cursor visible", () => checkVisible(menuCursorContainer.Cursor));
}
/// <summary>

View File

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

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using NUnit.Framework;
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Overlays;
@ -16,9 +15,7 @@ namespace osu.Game.Tests.Visual
[TestFixture]
public class TestCaseEditorComposeTimeline : OsuTestCase
{
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(ScrollableTimeline), typeof(ScrollingTimelineContainer), typeof(BeatmapWaveformGraph), typeof(TimelineButton) };
private readonly ScrollableTimeline timeline;
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(TimelineArea), typeof(Timeline), typeof(TimelineButton) };
public TestCaseEditorComposeTimeline()
{
@ -30,19 +27,14 @@ namespace osu.Game.Tests.Visual
Origin = Anchor.TopCentre,
State = Visibility.Visible
},
timeline = new ScrollableTimeline
new TimelineArea
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(1000, 100)
RelativeSizeAxes = Axes.X,
Size = new Vector2(0.8f, 100)
}
};
}
[BackgroundDependencyLoader]
private void load(OsuGameBase osuGame)
{
timeline.Beatmap.BindTo(osuGame.Beatmap);
}
}
}

View File

@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual
}
[BackgroundDependencyLoader]
private void load(OsuGameBase osuGame)
private void load()
{
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 };

View File

@ -19,19 +19,16 @@ namespace osu.Game.Tests.Visual
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(SummaryTimeline) };
[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(summaryTimeline = new SummaryTimeline
Add(new SummaryTimeline
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500, 50)
});
summaryTimeline.Beatmap.BindTo(osuGame.Beatmap);
}
}
}

View File

@ -32,15 +32,10 @@ namespace osu.Game.Tests.Visual
typeof(NotNullAttribute)
};
private DependencyContainer dependencies;
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(parent);
[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>
{
@ -63,8 +58,8 @@ namespace osu.Game.Tests.Visual
});
var clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
dependencies.CacheAs<IAdjustableClock>(clock);
dependencies.CacheAs<IFrameBasedClock>(clock);
Dependencies.CacheAs<IAdjustableClock>(clock);
Dependencies.CacheAs<IFrameBasedClock>(clock);
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

@ -0,0 +1,211 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets;
using osu.Game.Screens.Multi.Components;
using osu.Game.Screens.Multi.Screens.Lounge;
using osu.Game.Users;
using OpenTK.Input;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseLounge : ManualInputManagerTestCase
{
private TestLounge lounge;
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
lounge = new TestLounge();
Room[] rooms =
{
new Room
{
Name = { Value = @"Just Another Room" },
Host = { Value = new User { Username = @"DrabWeb", Id = 6946022, Country = new Country { FlagName = @"CA" } } },
Status = { Value = new RoomStatusPlaying() },
Availability = { Value = RoomAvailability.Public },
Type = { Value = new GameTypeTagTeam() },
Beatmap =
{
Value = new BeatmapInfo
{
StarDifficulty = 5.65,
Ruleset = rulesets.GetRuleset(0),
Metadata = new BeatmapMetadata
{
Title = @"Sidetracked Day (Short Ver.)",
Artist = @"VINXIS",
AuthorString = @"Hobbes2",
},
BeatmapSet = new BeatmapSetInfo
{
OnlineInfo = new BeatmapSetOnlineInfo
{
Covers = new BeatmapSetOnlineCovers
{
Cover = @"https://assets.ppy.sh/beatmaps/767600/covers/cover.jpg?1526243446",
},
},
},
}
},
MaxParticipants = { Value = 10 },
Participants =
{
Value = new[]
{
new User { Username = @"flyte", Id = 3103765, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 142 } } },
new User { Username = @"Cookiezi", Id = 124493, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 546 } } },
new User { Username = @"Angelsim", Id = 1777162, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 287 } } },
new User { Username = @"Rafis", Id = 2558286, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 468 } } },
new User { Username = @"hvick225", Id = 50265, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 325 } } },
new User { Username = @"peppy", Id = 2, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 625 } } },
}
}
},
new Room
{
Name = { Value = @"Not Just Any Room" },
Host = { Value = new User { Username = @"Monstrata", Id = 2706438, Country = new Country { FlagName = @"CA" } } },
Status = { Value = new RoomStatusOpen() },
Availability = { Value = RoomAvailability.FriendsOnly },
Type = { Value = new GameTypeTeamVersus() },
Beatmap =
{
Value = new BeatmapInfo
{
StarDifficulty = 2.73,
Ruleset = rulesets.GetRuleset(0),
Metadata = new BeatmapMetadata
{
Title = @"lit(var)",
Artist = @"kensuke ushio",
AuthorString = @"Monstrata",
},
BeatmapSet = new BeatmapSetInfo
{
OnlineInfo = new BeatmapSetOnlineInfo
{
Covers = new BeatmapSetOnlineCovers
{
Cover = @"https://assets.ppy.sh/beatmaps/623972/covers/cover.jpg?1521167183",
},
},
},
}
},
Participants =
{
Value = new[]
{
new User { Username = @"Jeby", Id = 3136279, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 3497 } } },
new User { Username = @"DualAkira", Id = 5220933, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 643 } } },
new User { Username = @"Datenshi Yohane", Id = 7171857, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 10555 } } },
}
}
},
new Room
{
Name = { Value = @"room THE FINAL" },
Host = { Value = new User { Username = @"Delis", Id = 1603923, Country = new Country { FlagName = @"JP" } } },
Status = { Value = new RoomStatusPlaying() },
Availability = { Value = RoomAvailability.Public },
Type = { Value = new GameTypeTagTeam() },
Beatmap =
{
Value = new BeatmapInfo
{
StarDifficulty = 4.48,
Ruleset = rulesets.GetRuleset(3),
Metadata = new BeatmapMetadata
{
Title = @"ONIGIRI FREEWAY",
Artist = @"OISHII",
AuthorString = @"Mentholzzz",
},
BeatmapSet = new BeatmapSetInfo
{
OnlineInfo = new BeatmapSetOnlineInfo
{
Covers = new BeatmapSetOnlineCovers
{
Cover = @"https://assets.ppy.sh/beatmaps/663098/covers/cover.jpg?1521898837",
},
},
},
}
},
MaxParticipants = { Value = 30 },
Participants =
{
Value = new[]
{
new User { Username = @"KizuA", Id = 6510442, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 5372 } } },
new User { Username = @"Colored", Id = 827563, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 810 } } },
new User { Username = @"Beryl", Id = 3817591, Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 10096 } } },
}
}
},
};
AddStep(@"show", () => Add(lounge));
AddStep(@"set rooms", () => lounge.Rooms = rooms);
selectAssert(0);
AddStep(@"clear rooms", () => lounge.Rooms = new Room[] {});
AddAssert(@"no room selected", () => lounge.SelectedRoom == null);
AddStep(@"set rooms", () => lounge.Rooms = rooms);
selectAssert(1);
AddStep(@"open room 1", () => clickRoom(1));
AddStep(@"make lounge current", lounge.MakeCurrent);
filterAssert(@"THE FINAL", LoungeTab.Public, 1);
filterAssert(string.Empty, LoungeTab.Public, 2);
filterAssert(string.Empty, LoungeTab.Private, 1);
filterAssert(string.Empty, LoungeTab.Public, 2);
filterAssert(@"no matches", LoungeTab.Public, 0);
AddStep(@"clear rooms", () => lounge.Rooms = new Room[] {});
AddStep(@"set rooms", () => lounge.Rooms = rooms);
AddAssert(@"no matches after clear", () => !lounge.ChildRooms.Any());
filterAssert(string.Empty, LoungeTab.Public, 2);
AddStep(@"exit", lounge.Exit);
}
private void clickRoom(int n)
{
InputManager.MoveMouseTo(lounge.ChildRooms.ElementAt(n));
InputManager.Click(MouseButton.Left);
}
private void selectAssert(int n)
{
AddStep($@"select room {n}", () => clickRoom(n));
AddAssert($@"room {n} selected", () => lounge.SelectedRoom == lounge.ChildRooms.ElementAt(n).Room);
}
private void filterAssert(string filter, LoungeTab tab, int endCount)
{
AddStep($@"filter '{filter}', {tab}", () => lounge.SetFilter(filter, tab));
AddAssert(@"filtered correctly", () => lounge.ChildRooms.Count() == endCount);
}
private class TestLounge : Lounge
{
public IEnumerable<DrawableRoom> ChildRooms => RoomsContainer.Children.Where(r => r.MatchingFilter);
public Room SelectedRoom => Inspector.Room;
public void SetFilter(string filter, LoungeTab tab)
{
Filter.Search.Current.Value = filter;
Filter.Tabs.Current.Value = tab;
}
}
}
}

View File

@ -39,8 +39,6 @@ namespace osu.Game.Tests.Visual
typeof(SpecialSection),
};
private const string unranked_suffix = " (Unranked)";
private RulesetStore rulesets;
private ModDisplay modDisplay;
private TestModSelectOverlay modSelect;
@ -121,7 +119,7 @@ namespace osu.Game.Tests.Visual
private void testManiaMods(ManiaRuleset ruleset)
{
testMultiplierTextUnranked(ruleset.GetModsFor(ModType.Special).First(m => m is ManiaModRandom));
testRankedText(ruleset.GetModsFor(ModType.Special).First(m => m is ManiaModRandom));
}
private void testSingleMod(Mod mod)
@ -198,13 +196,16 @@ namespace osu.Game.Tests.Visual
checkLabelColor(Color4.White);
}
private void testMultiplierTextUnranked(Mod mod)
private void testRankedText(Mod mod)
{
AddAssert("check for ranked", () => !modSelect.MultiplierLabel.Text.EndsWith(unranked_suffix));
AddWaitStep(1, "wait for fade");
AddAssert("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0);
selectNext(mod);
AddAssert("check for unranked", () => modSelect.MultiplierLabel.Text.EndsWith(unranked_suffix));
AddWaitStep(1, "wait for fade");
AddAssert("check for unranked", () => modSelect.UnrankedLabel.Alpha != 0);
selectPrevious(mod);
AddAssert("check for ranked", () => !modSelect.MultiplierLabel.Text.EndsWith(unranked_suffix));
AddWaitStep(1, "wait for fade");
AddAssert("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0);
}
private void selectNext(Mod mod) => AddStep($"left click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectNext(1));
@ -240,6 +241,7 @@ namespace osu.Game.Tests.Visual
}
public new OsuSpriteText MultiplierLabel => base.MultiplierLabel;
public new OsuSpriteText UnrankedLabel => base.UnrankedLabel;
public new TriangleButton DeselectAllButton => base.DeselectAllButton;
public new Color4 LowMultiplierColour => base.LowMultiplierColour;

View File

@ -4,7 +4,7 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Screens.Multi;
using osu.Game.Screens.Multi.Screens;
using osu.Game.Screens.Multi.Screens.Lounge;
namespace osu.Game.Tests.Visual
{
@ -13,14 +13,14 @@ namespace osu.Game.Tests.Visual
{
public TestCaseMultiHeader()
{
Lobby lobby;
Lounge lounge;
Children = new Drawable[]
{
lobby = new Lobby
lounge = new Lounge
{
Padding = new MarginPadding { Top = Header.HEIGHT },
},
new Header(lobby),
new Header(lounge),
};
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -31,10 +31,6 @@ namespace osu.Game.Tests.Visual
var text = quitButton.Children.OfType<SpriteText>().First();
// initial display
AddUntilStep(() => text.IsPresent && !exitAction, "Text visible");
AddUntilStep(() => !text.IsPresent && !exitAction, "Text is not visible");
AddStep("Trigger text fade in", () => InputManager.MoveMouseTo(quitButton));
AddUntilStep(() => text.IsPresent && !exitAction, "Text visible");
AddStep("Trigger text fade out", () => InputManager.MoveMouseTo(Vector2.One));

View File

@ -3,7 +3,6 @@
using System.ComponentModel;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play;
@ -13,23 +12,20 @@ namespace osu.Game.Tests.Visual
[Description("Player instantiated with a replay.")]
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
// to simulate setting a replay rather than having the replay already set for us
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
var dummyRulesetContainer = ruleset.CreateRulesetContainerWith(beatmap);
Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
var dummyRulesetContainer = ruleset.CreateRulesetContainerWith(Beatmap.Value);
// We have the replay
var replay = dummyRulesetContainer.Replay;
// 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)
{
InitialBeatmap = beatmap
};
return new ReplayPlayer(replay);
}
}
}

View File

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

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