diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000000..0c6b80e97e
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+custom: https://osu.ppy.sh/home/support
diff --git a/.gitignore b/.gitignore
index 0e2850a01c..e60058ab35 100644
--- a/.gitignore
+++ b/.gitignore
@@ -198,6 +198,7 @@ ClientBin/
*.publishsettings
node_modules/
orleans.codegen.cs
+Resource.designer.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
diff --git a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml b/.idea/.idea.osu/.idea/runConfigurations/CatchRuleset__Tests_.xml
similarity index 73%
rename from .idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml
rename to .idea/.idea.osu/.idea/runConfigurations/CatchRuleset__Tests_.xml
index 2eff16cc91..6463dd6ea5 100644
--- a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__catch_.xml
+++ b/.idea/.idea.osu/.idea/runConfigurations/CatchRuleset__Tests_.xml
@@ -1,18 +1,21 @@
-
+
+
-
+
-
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__mania_.xml b/.idea/.idea.osu/.idea/runConfigurations/ManiaRuleset__Tests_.xml
similarity index 73%
rename from .idea/.idea.osu/.idea/runConfigurations/RulesetTests__mania_.xml
rename to .idea/.idea.osu/.idea/runConfigurations/ManiaRuleset__Tests_.xml
index cae9754560..0b63b2d966 100644
--- a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__mania_.xml
+++ b/.idea/.idea.osu/.idea/runConfigurations/ManiaRuleset__Tests_.xml
@@ -1,18 +1,21 @@
-
+
+
-
+
-
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__osu__.xml b/.idea/.idea.osu/.idea/runConfigurations/OsuRuleset__Tests_.xml
similarity index 72%
rename from .idea/.idea.osu/.idea/runConfigurations/RulesetTests__osu__.xml
rename to .idea/.idea.osu/.idea/runConfigurations/OsuRuleset__Tests_.xml
index 49ec93e1b3..750ece648b 100644
--- a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__osu__.xml
+++ b/.idea/.idea.osu/.idea/runConfigurations/OsuRuleset__Tests_.xml
@@ -1,18 +1,21 @@
-
+
+
-
+
-
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__taiko_.xml b/.idea/.idea.osu/.idea/runConfigurations/TaikoRuleset__Tests_.xml
similarity index 73%
rename from .idea/.idea.osu/.idea/runConfigurations/RulesetTests__taiko_.xml
rename to .idea/.idea.osu/.idea/runConfigurations/TaikoRuleset__Tests_.xml
index d0964c6f68..7b359a1ca0 100644
--- a/.idea/.idea.osu/.idea/runConfigurations/RulesetTests__taiko_.xml
+++ b/.idea/.idea.osu/.idea/runConfigurations/TaikoRuleset__Tests_.xml
@@ -1,18 +1,21 @@
-
+
+
-
+
-
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/runConfigurations/Tournament.xml b/.idea/.idea.osu/.idea/runConfigurations/Tournament.xml
new file mode 100644
index 0000000000..3722f3dc04
--- /dev/null
+++ b/.idea/.idea.osu/.idea/runConfigurations/Tournament.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/runConfigurations/Tournament__Tests_.xml b/.idea/.idea.osu/.idea/runConfigurations/Tournament__Tests_.xml
new file mode 100644
index 0000000000..e2628a1bb4
--- /dev/null
+++ b/.idea/.idea.osu/.idea/runConfigurations/Tournament__Tests_.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu/.idea/runConfigurations/osu_.xml b/.idea/.idea.osu/.idea/runConfigurations/osu_.xml
index 2735f4ceb3..7ac6bb745d 100644
--- a/.idea/.idea.osu/.idea/runConfigurations/osu_.xml
+++ b/.idea/.idea.osu/.idea/runConfigurations/osu_.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/.idea/.idea.osu/.idea/runConfigurations/VisualTests.xml b/.idea/.idea.osu/.idea/runConfigurations/osu___Tests_.xml
similarity index 70%
rename from .idea/.idea.osu/.idea/runConfigurations/VisualTests.xml
rename to .idea/.idea.osu/.idea/runConfigurations/osu___Tests_.xml
index 95cb4c0e62..7fcb7c15ea 100644
--- a/.idea/.idea.osu/.idea/runConfigurations/VisualTests.xml
+++ b/.idea/.idea.osu/.idea/runConfigurations/osu___Tests_.xml
@@ -1,17 +1,20 @@
-
+
+
-
-
+
+
+
+
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
index c3306c2db7..57ff3e6b43 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -1,41 +1,6 @@
{
"version": "0.2.0",
- "configurations": [
- {
- "name": "VisualTests (Debug)",
- "type": "coreclr",
- "request": "launch",
- "program": "dotnet",
- "args": [
- "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.2/osu.Game.Tests.dll"
- ],
- "cwd": "${workspaceRoot}",
- "preLaunchTask": "Build tests (Debug)",
- "linux": {
- "env": {
- "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.2:${env:LD_LIBRARY_PATH}"
- }
- },
- "console": "internalConsole"
- },
- {
- "name": "VisualTests (Release)",
- "type": "coreclr",
- "request": "launch",
- "program": "dotnet",
- "args": [
- "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.2/osu.Game.Tests.dll"
- ],
- "cwd": "${workspaceRoot}",
- "preLaunchTask": "Build tests (Release)",
- "linux": {
- "env": {
- "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.2:${env:LD_LIBRARY_PATH}"
- }
- },
- "console": "internalConsole"
- },
- {
+ "configurations": [{
"name": "osu! (Debug)",
"type": "coreclr",
"request": "launch",
@@ -69,6 +34,111 @@
},
"console": "internalConsole"
},
+ {
+ "name": "osu! (Tests, Debug)",
+ "type": "coreclr",
+ "request": "launch",
+ "program": "dotnet",
+ "args": [
+ "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.2/osu.Game.Tests.dll"
+ ],
+ "cwd": "${workspaceRoot}",
+ "preLaunchTask": "Build tests (Debug)",
+ "linux": {
+ "env": {
+ "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.2:${env:LD_LIBRARY_PATH}"
+ }
+ },
+ "console": "internalConsole"
+ }, {
+ "name": "osu! (Tests, Release)",
+ "type": "coreclr",
+ "request": "launch",
+ "program": "dotnet",
+ "args": [
+ "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.2/osu.Game.Tests.dll"
+ ],
+ "cwd": "${workspaceRoot}",
+ "preLaunchTask": "Build tests (Release)",
+ "linux": {
+ "env": {
+ "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.2:${env:LD_LIBRARY_PATH}"
+ }
+ },
+ "console": "internalConsole"
+ },
+ {
+ "name": "Tournament (Debug)",
+ "type": "coreclr",
+ "request": "launch",
+ "program": "dotnet",
+ "args": [
+ "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.2/osu!.dll",
+ "--tournament"
+ ],
+ "cwd": "${workspaceRoot}",
+ "preLaunchTask": "Build osu! (Debug)",
+ "linux": {
+ "env": {
+ "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.2:${env:LD_LIBRARY_PATH}"
+ }
+ },
+ "console": "internalConsole"
+ },
+ {
+ "name": "Tournament (Release)",
+ "type": "coreclr",
+ "request": "launch",
+ "program": "dotnet",
+ "args": [
+ "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.2/osu!.dll",
+ "--tournament"
+ ],
+ "cwd": "${workspaceRoot}",
+ "preLaunchTask": "Build osu! (Release)",
+ "linux": {
+ "env": {
+ "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.2:${env:LD_LIBRARY_PATH}"
+ }
+ },
+ "console": "internalConsole"
+ },
+ {
+ "name": "Tournament (Tests, Debug)",
+ "type": "coreclr",
+ "request": "launch",
+ "program": "dotnet",
+ "args": [
+ "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp2.2/osu.Game.Tournament.Tests.dll",
+ "--tournament"
+ ],
+ "cwd": "${workspaceRoot}",
+ "preLaunchTask": "Build tournament tests (Debug)",
+ "linux": {
+ "env": {
+ "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp2.2:${env:LD_LIBRARY_PATH}"
+ }
+ },
+ "console": "internalConsole"
+ },
+ {
+ "name": "Tournament (Tests, Release)",
+ "type": "coreclr",
+ "request": "launch",
+ "program": "dotnet",
+ "args": [
+ "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp2.2/osu.Game.Tournament.Tests.dll",
+ "--tournament"
+ ],
+ "cwd": "${workspaceRoot}",
+ "preLaunchTask": "Build tournament tests (Release)",
+ "linux": {
+ "env": {
+ "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp2.2:${env:LD_LIBRARY_PATH}"
+ }
+ },
+ "console": "internalConsole"
+ },
{
"name": "Cake: Debug Script",
"type": "coreclr",
@@ -84,4 +154,4 @@
"externalConsole": false
}
]
-}
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index de799a7c03..aba590f466 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -2,8 +2,7 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
- "tasks": [
- {
+ "tasks": [{
"label": "Build osu! (Debug)",
"type": "shell",
"command": "dotnet",
@@ -65,6 +64,36 @@
"group": "build",
"problemMatcher": "$msCompile"
},
+ {
+ "label": "Build tournament tests (Debug)",
+ "type": "shell",
+ "command": "dotnet",
+ "args": [
+ "build",
+ "--no-restore",
+ "osu.Game.Tournament.Tests",
+ "/p:GenerateFullPaths=true",
+ "/m",
+ "/verbosity:m"
+ ],
+ "group": "build",
+ "problemMatcher": "$msCompile"
+ }, {
+ "label": "Build tournament tests (Release)",
+ "type": "shell",
+ "command": "dotnet",
+ "args": [
+ "build",
+ "--no-restore",
+ "osu.Game.Tournament.Tests",
+ "/p:Configuration=Release",
+ "/p:GenerateFullPaths=true",
+ "/m",
+ "/verbosity:m"
+ ],
+ "group": "build",
+ "problemMatcher": "$msCompile"
+ },
{
"label": "Restore (netcoreapp2.2)",
"type": "shell",
diff --git a/README.md b/README.md
index abddb1faa1..52fc29cb98 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,7 @@
+
+
+
+
# osu!
[![Build status](https://ci.appveyor.com/api/projects/status/u2p01nx7l6og8buh?svg=true)](https://ci.appveyor.com/project/peppy/osu) [![CodeFactor](https://www.codefactor.io/repository/github/ppy/osu/badge)](https://www.codefactor.io/repository/github/ppy/osu) [![dev chat](https://discordapp.com/api/guilds/188630481301012481/widget.png?style=shield)](https://discord.gg/ppy)
@@ -10,6 +14,8 @@ This project is still heavily under development, but is in a state where users a
We are accepting bug reports (please report with as much detail as possible). Feature requests are welcome as long as you read and understand the contribution guidelines listed below.
+Detailed changelogs are published on the [official osu! site](https://osu.ppy.sh/home/changelog).
+
## Requirements
- A desktop platform with the [.NET Core SDK 2.2](https://www.microsoft.com/net/learn/get-started) or higher installed.
@@ -20,17 +26,22 @@ We are accepting bug reports (please report with as much detail as possible). Fe
### Releases
-If you are not interested in developing the game, please head over to the [releases](https://github.com/ppy/osu/releases) to download a precompiled build with automatic updating enabled.
+If you are not interested in developing the game, you can still consume our [binary releases](https://github.com/ppy/osu/releases).
-- Windows (x64) users should download and run `install.exe`.
-- macOS users (10.12 "Sierra" and higher) should download and run `osu.app.zip`.
-- iOS users can join the [TestFlight beta program](https://t.co/xQJmHkfC18).
+**Latest build:**
+
+| [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) |
+| ------------- | ------------- |
+
+- **Linux** users are recommended to self-compile until we have official deployment in place.
+- **iOS** users can join the [TestFlight beta program](https://t.co/PasE1zrHhw) (note that due to high demand this is regularly full).
+- **Android** users can self-compile, and expect a public beta soon.
If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
### Downloading the source code
-Clone the repository **including submodules**:
+Clone the repository:
```shell
git clone https://github.com/ppy/osu
@@ -45,7 +56,7 @@ git pull
### Building
-Build configurations for the recommended IDEs (listed above) are included. You should use the provided Build/Run functionality of your IDE to get things going. When testing or building new components, it's highly encouraged you use the `VisualTests` project/configuration. More information on this provided below.
+Build configurations for the recommended IDEs (listed above) are included. You should use the provided Build/Run functionality of your IDE to get things going. When testing or building new components, it's highly encouraged you use the `VisualTests` project/configuration. More information on this provided [below](#contributing).
> Visual Studio Code users must run the `Restore` task before any build attempt.
@@ -63,7 +74,7 @@ If the build fails, try to restore nuget packages with `dotnet restore`.
On Linux, the environment variable `LD_LIBRARY_PATH` must point to the build directory, located at `osu.Desktop/bin/Debug/$NETCORE_VERSION`.
-`$NETCORE_VERSION` is the version of .NET Core SDK. You can have it with `grep TargetFramework osu.Desktop/osu.Desktop.csproj | sed -r 's/.*>(.*)<\/.*/\1/'`.
+`$NETCORE_VERSION` is the version of the targeted .NET Core SDK. You can check it by running `grep TargetFramework osu.Desktop/osu.Desktop.csproj | sed -r 's/.*>(.*)<\/.*/\1/'`.
For example, you can run osu! with the following command:
@@ -83,11 +94,13 @@ Code analysis can be run with `powershell ./build.ps1` or `build.sh`. This is cu
We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention on having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time, to ensure no effort is wasted.
-Please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have set up. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**.
+If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues) (especially those with the ["good first issue"](https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22good+first+issue%22) label).
-Contributions can be made via pull requests to this repository. We hope to credit and reward larger contributions via a [bounty system](https://www.bountysource.com/teams/ppy). If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues).
+Before starting, please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have set up. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**.
-Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured; with any libraries we are using; with any processes involved with contributing, *please* bring it up. I welcome all feedback so we can make contributing to this project as pain-free as possible.
+Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured; with any libraries we are using; with any processes involved with contributing, *please* bring it up. We welcome all feedback so we can make contributing to this project as pain-free as possible.
+
+For those interested, we love to reward quality contributions via [bounties](https://docs.google.com/spreadsheets/d/1jNXfj_S3Pb5PErA-czDdC9DUu4IgUbe1Lt8E7CYUJuE/view?&rm=minimal#gid=523803337), paid out via paypal or osu! supporter tags. Don't hesitate to [request a bounty](https://docs.google.com/forms/d/e/1FAIpQLSet_8iFAgPMG526pBZ2Kic6HSh7XPM3fE8xPcnWNkMzINDdYg/viewform) for your work on this project.
## Licence
diff --git a/assets/lazer.png b/assets/lazer.png
new file mode 100644
index 0000000000..1e40e844cc
Binary files /dev/null and b/assets/lazer.png differ
diff --git a/osu.Android.props b/osu.Android.props
new file mode 100644
index 0000000000..98f9bf1a42
--- /dev/null
+++ b/osu.Android.props
@@ -0,0 +1,68 @@
+
+
+ bin\$(Configuration)
+ 4
+ 2.0
+ false
+ false
+ default
+ Library
+ 512
+ Off
+ True
+ Xamarin.Android.Net.AndroidClientHandler
+ v9.0
+ false
+
+
+ True
+ portable
+ False
+ DEBUG;TRACE
+ prompt
+ false
+ false
+ SdkOnly
+ true
+ false
+ cjk,mideast,other,rare,west
+ true
+ armeabi-v7a;x86;arm64-v8a
+ true
+
+
+ false
+ None
+ True
+ prompt
+ true
+ false
+ SdkOnly
+ False
+ true
+ cjk,mideast,other,rare,west
+ true
+ armeabi-v7a;x86;arm64-v8a
+ true
+
+
+
+ osu.licenseheader
+
+
+ Always
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/osu.Android.sln b/osu.Android.sln
new file mode 100644
index 0000000000..ebf2c55cb4
--- /dev/null
+++ b/osu.Android.sln
@@ -0,0 +1,126 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.28516.95
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game", "osu.Game\osu.Game.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Osu", "osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj", "{C92A607B-1FDD-4954-9F92-03FF547D9080}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Catch", "osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj", "{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Taiko", "osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj", "{F167E17A-7DE6-4AF5-B920-A5112296C695}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Rulesets.Mania", "osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj", "{48F4582B-7687-4621-9CBE-5C24197CB536}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Android", "osu.Android\osu.Android.csproj", "{D1D5F9A8-B40B-40E6-B02F-482D03346D3D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Catch.Tests.Android", "osu.Game.Rulesets.Catch.Tests.Android\osu.Game.Rulesets.Catch.Tests.Android.csproj", "{C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Mania.Tests.Android", "osu.Game.Rulesets.Mania.Tests.Android\osu.Game.Rulesets.Mania.Tests.Android.csproj", "{531F1092-DB27-445D-AA33-2A77C7187C99}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Osu.Tests.Android", "osu.Game.Rulesets.Osu.Tests.Android\osu.Game.Rulesets.Osu.Tests.Android.csproj", "{90CAB706-39CB-4B93-9629-3218A6FF8E9B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Rulesets.Taiko.Tests.Android", "osu.Game.Rulesets.Taiko.Tests.Android\osu.Game.Rulesets.Taiko.Tests.Android.csproj", "{3701A0A1-8476-42C6-B5C4-D24129B4A484}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "osu.Game.Tests.Android", "osu.Game.Tests.Android\osu.Game.Tests.Android.csproj", "{5CC222DC-5716-4499-B897-DCBDDA4A5CF9}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C92A607B-1FDD-4954-9F92-03FF547D9080}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C92A607B-1FDD-4954-9F92-03FF547D9080}.Release|Any CPU.Build.0 = Release|Any CPU
+ {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {58F6C80C-1253-4A0E-A465-B8C85EBEADF3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F167E17A-7DE6-4AF5-B920-A5112296C695}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F167E17A-7DE6-4AF5-B920-A5112296C695}.Release|Any CPU.Build.0 = Release|Any CPU
+ {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {48F4582B-7687-4621-9CBE-5C24197CB536}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {48F4582B-7687-4621-9CBE-5C24197CB536}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|Any CPU.Build.0 = Release|Any CPU
+ {531F1092-DB27-445D-AA33-2A77C7187C99}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {671B0BEC-2403-45B0-9357-2C97CC517668}
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ Policies = $0
+ $0.TextStylePolicy = $1
+ $1.EolMarker = Windows
+ $1.inheritsSet = VisualStudio
+ $1.inheritsScope = text/plain
+ $1.scope = text/x-csharp
+ $0.CSharpFormattingPolicy = $2
+ $2.IndentSwitchSection = True
+ $2.NewLinesForBracesInProperties = True
+ $2.NewLinesForBracesInAccessors = True
+ $2.NewLinesForBracesInAnonymousMethods = True
+ $2.NewLinesForBracesInControlBlocks = True
+ $2.NewLinesForBracesInAnonymousTypes = True
+ $2.NewLinesForBracesInObjectCollectionArrayInitializers = True
+ $2.NewLinesForBracesInLambdaExpressionBody = True
+ $2.NewLineForElse = True
+ $2.NewLineForCatch = True
+ $2.NewLineForFinally = True
+ $2.NewLineForMembersInObjectInit = True
+ $2.NewLineForMembersInAnonymousTypes = True
+ $2.NewLineForClausesInQuery = True
+ $2.SpacingAfterMethodDeclarationName = False
+ $2.SpaceAfterMethodCallName = False
+ $2.SpaceBeforeOpenSquareBracket = False
+ $2.inheritsSet = Mono
+ $2.inheritsScope = text/x-csharp
+ $2.scope = text/x-csharp
+ EndGlobalSection
+EndGlobal
diff --git a/osu.Android.sln.DotSettings b/osu.Android.sln.DotSettings
new file mode 100644
index 0000000000..3f5bd9d34d
--- /dev/null
+++ b/osu.Android.sln.DotSettings
@@ -0,0 +1,815 @@
+
+ True
+ True
+ True
+ True
+ ExplicitlyExcluded
+ ExplicitlyExcluded
+ SOLUTION
+ HINT
+ WARNING
+
+ True
+ WARNING
+ WARNING
+ HINT
+ HINT
+ HINT
+ HINT
+ WARNING
+ WARNING
+ WARNING
+ HINT
+ WARNING
+ HINT
+ SUGGESTION
+ HINT
+ HINT
+ HINT
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ HINT
+ WARNING
+ WARNING
+ HINT
+ WARNING
+ WARNING
+ DO_NOT_SHOW
+ HINT
+ WARNING
+ DO_NOT_SHOW
+ WARNING
+ HINT
+ HINT
+ HINT
+ ERROR
+ HINT
+ HINT
+ HINT
+ WARNING
+ WARNING
+ HINT
+ DO_NOT_SHOW
+ HINT
+ HINT
+ HINT
+ HINT
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ HINT
+ HINT
+ HINT
+ HINT
+ HINT
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ HINT
+ DO_NOT_SHOW
+ DO_NOT_SHOW
+ DO_NOT_SHOW
+ WARNING
+
+ WARNING
+ WARNING
+ WARNING
+ ERROR
+ WARNING
+ WARNING
+ HINT
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ HINT
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ HINT
+ DO_NOT_SHOW
+ DO_NOT_SHOW
+ DO_NOT_SHOW
+ WARNING
+ WARNING
+ HINT
+ WARNING
+ HINT
+ HINT
+ HINT
+ HINT
+ HINT
+ HINT
+ HINT
+
+ HINT
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ WARNING
+ HINT
+ WARNING
+ WARNING
+ HINT
+ HINT
+ WARNING
+ <?xml version="1.0" encoding="utf-16"?><Profile name="Code Cleanup (peppy)"><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSUseVar><BehavourStyle>CAN_CHANGE_TO_EXPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_EXPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_EXPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSUpdateFileHeader>True</CSUpdateFileHeader><CSCodeStyleAttributes ArrangeTypeAccessModifier="False" ArrangeTypeMemberAccessModifier="False" SortModifiers="True" RemoveRedundantParentheses="True" AddMissingParentheses="False" ArrangeBraces="False" ArrangeAttributes="False" ArrangeArgumentsStyle="False" /><XAMLCollapseEmptyTags>False</XAMLCollapseEmptyTags><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CSArrangeQualifiers>True</CSArrangeQualifiers></Profile>
+ Code Cleanup (peppy)
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ NEXT_LINE
+ NEXT_LINE
+ True
+ NEVER
+ NEVER
+ False
+ NEVER
+ False
+ True
+ False
+ False
+ True
+ True
+ False
+ CHOP_IF_LONG
+ True
+ 200
+ CHOP_IF_LONG
+ False
+ False
+ AABB
+ API
+ BPM
+ GC
+ GL
+ GLSL
+ HID
+ HUD
+ ID
+ IP
+ IPC
+ LTRB
+ MD5
+ NS
+ OS
+ RGB
+ RNG
+ SHA
+ SRGB
+ TK
+ SS
+ PP
+ GMT
+ QAT
+ BNG
+ UI
+ HINT
+ <?xml version="1.0" encoding="utf-16"?>
+<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">
+ <TypePattern DisplayName="COM interfaces or structs">
+ <TypePattern.Match>
+ <Or>
+ <And>
+ <Kind Is="Interface" />
+ <Or>
+ <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" />
+ <HasAttribute Name="System.Runtime.InteropServices.ComImport" />
+ </Or>
+ </And>
+ <Kind Is="Struct" />
+ </Or>
+ </TypePattern.Match>
+ </TypePattern>
+ <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All">
+ <TypePattern.Match>
+ <And>
+ <Kind Is="Class" />
+ <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" />
+ </And>
+ </TypePattern.Match>
+ <Entry DisplayName="Setup/Teardown Methods">
+ <Entry.Match>
+ <And>
+ <Kind Is="Method" />
+ <Or>
+ <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" />
+ <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" />
+ <HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" />
+ <HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" />
+ </Or>
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="All other members" />
+ <Entry Priority="100" DisplayName="Test Methods">
+ <Entry.Match>
+ <And>
+ <Kind Is="Method" />
+ <HasAttribute Name="NUnit.Framework.TestAttribute" />
+ </And>
+ </Entry.Match>
+ <Entry.SortBy>
+ <Name />
+ </Entry.SortBy>
+ </Entry>
+ </TypePattern>
+ <TypePattern DisplayName="Default Pattern">
+ <Group DisplayName="Fields/Properties">
+ <Group DisplayName="Public Fields">
+ <Entry DisplayName="Constant Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Or>
+ <Kind Is="Constant" />
+ <Readonly />
+ <And>
+ <Static />
+ <Readonly />
+ </And>
+ </Or>
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Static Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Static />
+ <Not>
+ <Readonly />
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Normal Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Not>
+ <Or>
+ <Static />
+ <Readonly />
+ </Or>
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Entry DisplayName="Public Properties">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Kind Is="Property" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Group DisplayName="Internal Fields">
+ <Entry DisplayName="Constant Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Internal" />
+ <Or>
+ <Kind Is="Constant" />
+ <Readonly />
+ <And>
+ <Static />
+ <Readonly />
+ </And>
+ </Or>
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Static Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Internal" />
+ <Static />
+ <Not>
+ <Readonly />
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Normal Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Internal" />
+ <Not>
+ <Or>
+ <Static />
+ <Readonly />
+ </Or>
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Entry DisplayName="Internal Properties">
+ <Entry.Match>
+ <And>
+ <Access Is="Internal" />
+ <Kind Is="Property" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Group DisplayName="Protected Fields">
+ <Entry DisplayName="Constant Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Protected" />
+ <Or>
+ <Kind Is="Constant" />
+ <Readonly />
+ <And>
+ <Static />
+ <Readonly />
+ </And>
+ </Or>
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Static Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Protected" />
+ <Static />
+ <Not>
+ <Readonly />
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Normal Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Protected" />
+ <Not>
+ <Or>
+ <Static />
+ <Readonly />
+ </Or>
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Entry DisplayName="Protected Properties">
+ <Entry.Match>
+ <And>
+ <Access Is="Protected" />
+ <Kind Is="Property" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Group DisplayName="Private Fields">
+ <Entry DisplayName="Constant Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Private" />
+ <Or>
+ <Kind Is="Constant" />
+ <Readonly />
+ <And>
+ <Static />
+ <Readonly />
+ </And>
+ </Or>
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Static Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Private" />
+ <Static />
+ <Not>
+ <Readonly />
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Normal Fields">
+ <Entry.Match>
+ <And>
+ <Access Is="Private" />
+ <Not>
+ <Or>
+ <Static />
+ <Readonly />
+ </Or>
+ </Not>
+ <Kind Is="Field" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Entry DisplayName="Private Properties">
+ <Entry.Match>
+ <And>
+ <Access Is="Private" />
+ <Kind Is="Property" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Group DisplayName="Constructor/Destructor">
+ <Entry DisplayName="Ctor">
+ <Entry.Match>
+ <Kind Is="Constructor" />
+ </Entry.Match>
+ </Entry>
+ <Region Name="Disposal">
+ <Entry DisplayName="Dtor">
+ <Entry.Match>
+ <Kind Is="Destructor" />
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Dispose()">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Kind Is="Method" />
+ <Name Is="Dispose" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Dispose(true)">
+ <Entry.Match>
+ <And>
+ <Access Is="Protected" />
+ <Or>
+ <Virtual />
+ <Override />
+ </Or>
+ <Kind Is="Method" />
+ <Name Is="Dispose" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Region>
+ </Group>
+ <Group DisplayName="Methods">
+ <Group DisplayName="Public">
+ <Entry DisplayName="Static Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Static />
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Public" />
+ <Not>
+ <Static />
+ </Not>
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Group DisplayName="Internal">
+ <Entry DisplayName="Static Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Internal" />
+ <Static />
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Internal" />
+ <Not>
+ <Static />
+ </Not>
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Group DisplayName="Protected">
+ <Entry DisplayName="Static Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Protected" />
+ <Static />
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Protected" />
+ <Not>
+ <Static />
+ </Not>
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ <Group DisplayName="Private">
+ <Entry DisplayName="Static Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Private" />
+ <Static />
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ <Entry DisplayName="Methods">
+ <Entry.Match>
+ <And>
+ <Access Is="Private" />
+ <Not>
+ <Static />
+ </Not>
+ <Kind Is="Method" />
+ </And>
+ </Entry.Match>
+ </Entry>
+ </Group>
+ </Group>
+ </TypePattern>
+</Patterns>
+ Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
+See the LICENCE file in the repository root for full licence text.
+
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" />
+ <Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb"><ExtraRule Prefix="_" Suffix="" Style="aaBb" /></Policy>
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="private methods"><ElementKinds><Kind Name="ASYNC_METHOD" /><Kind Name="METHOD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy>
+ <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public" Description="internal/protected/public methods"><ElementKinds><Kind Name="ASYNC_METHOD" /><Kind Name="METHOD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy>
+ <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="private properties"><ElementKinds><Kind Name="PROPERTY" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy>
+ <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public" Description="internal/protected/public properties"><ElementKinds><Kind Name="PROPERTY" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy>
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ o!f – Object Initializer: Anchor&Origin
+ True
+ constant("Centre")
+ 0
+ True
+ True
+ 2.0
+ InCSharpFile
+ ofao
+ True
+ Anchor = Anchor.$anchor$,
+Origin = Anchor.$anchor$,
+ True
+ True
+ o!f – InternalChildren = []
+ True
+ True
+ 2.0
+ InCSharpFile
+ ofic
+ True
+ InternalChildren = new Drawable[]
+{
+ $END$
+};
+ True
+ True
+ o!f – new GridContainer { .. }
+ True
+ True
+ 2.0
+ InCSharpFile
+ ofgc
+ True
+ new GridContainer
+{
+ RelativeSizeAxes = Axes.Both,
+ Content = new[]
+ {
+ new Drawable[] { $END$ },
+ new Drawable[] { }
+ }
+};
+ True
+ True
+ o!f – new FillFlowContainer { .. }
+ True
+ True
+ 2.0
+ InCSharpFile
+ offf
+ True
+ new FillFlowContainer
+{
+ RelativeSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ $END$
+ }
+},
+ True
+ True
+ o!f – new Container { .. }
+ True
+ True
+ 2.0
+ InCSharpFile
+ ofcont
+ True
+ new Container
+{
+ RelativeSizeAxes = Axes.Both,
+ Children = new Drawable[]
+ {
+ $END$
+ }
+},
+ True
+ True
+ o!f – BackgroundDependencyLoader load()
+ True
+ True
+ 2.0
+ InCSharpFile
+ ofbdl
+ True
+ [BackgroundDependencyLoader]
+private void load()
+{
+ $END$
+}
+ True
+ True
+ o!f – new Box { .. }
+ True
+ True
+ 2.0
+ InCSharpFile
+ ofbox
+ True
+ new Box
+{
+ Colour = Color4.Black,
+ RelativeSizeAxes = Axes.Both,
+},
+ True
+ True
+ o!f – Children = []
+ True
+ True
+ 2.0
+ InCSharpFile
+ ofc
+ True
+ Children = new Drawable[]
+{
+ $END$
+};
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs
new file mode 100644
index 0000000000..762a9c418d
--- /dev/null
+++ b/osu.Android/OsuGameActivity.cs
@@ -0,0 +1,25 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using Android.App;
+using Android.Content.PM;
+using Android.OS;
+using Android.Views;
+using osu.Framework.Android;
+
+namespace osu.Android
+{
+ [Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullSensor, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = true)]
+ public class OsuGameActivity : AndroidGameActivity
+ {
+ protected override Framework.Game CreateGame() => new OsuGameAndroid();
+
+ protected override void OnCreate(Bundle savedInstanceState)
+ {
+ base.OnCreate(savedInstanceState);
+
+ Window.AddFlags(WindowManagerFlags.Fullscreen);
+ Window.AddFlags(WindowManagerFlags.KeepScreenOn);
+ }
+ }
+}
diff --git a/osu.Android/OsuGameAndroid.cs b/osu.Android/OsuGameAndroid.cs
new file mode 100644
index 0000000000..d9bdd9c0c2
--- /dev/null
+++ b/osu.Android/OsuGameAndroid.cs
@@ -0,0 +1,14 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using Android.App;
+using osu.Game;
+
+namespace osu.Android
+{
+ public class OsuGameAndroid : OsuGame
+ {
+ public override Version AssemblyVersion => new Version(Application.Context.ApplicationContext.PackageManager.GetPackageInfo(Application.Context.ApplicationContext.PackageName, 0).VersionName);
+ }
+}
diff --git a/osu.Android/Properties/AndroidManifest.xml b/osu.Android/Properties/AndroidManifest.xml
new file mode 100644
index 0000000000..acd21f9587
--- /dev/null
+++ b/osu.Android/Properties/AndroidManifest.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Android/Resources/drawable/lazer.png b/osu.Android/Resources/drawable/lazer.png
new file mode 100644
index 0000000000..fc7aa8a092
Binary files /dev/null and b/osu.Android/Resources/drawable/lazer.png differ
diff --git a/osu.Android/lib/arm64-v8a/libbass.so b/osu.Android/lib/arm64-v8a/libbass.so
new file mode 100644
index 0000000000..d5c24b3e4b
Binary files /dev/null and b/osu.Android/lib/arm64-v8a/libbass.so differ
diff --git a/osu.Android/lib/arm64-v8a/libbass_fx.so b/osu.Android/lib/arm64-v8a/libbass_fx.so
new file mode 100644
index 0000000000..e498b10117
Binary files /dev/null and b/osu.Android/lib/arm64-v8a/libbass_fx.so differ
diff --git a/osu.Android/lib/armeabi-v7a/libbass.so b/osu.Android/lib/armeabi-v7a/libbass.so
new file mode 100644
index 0000000000..f7d23b9052
Binary files /dev/null and b/osu.Android/lib/armeabi-v7a/libbass.so differ
diff --git a/osu.Android/lib/armeabi-v7a/libbass_fx.so b/osu.Android/lib/armeabi-v7a/libbass_fx.so
new file mode 100644
index 0000000000..006e2feb30
Binary files /dev/null and b/osu.Android/lib/armeabi-v7a/libbass_fx.so differ
diff --git a/osu.Android/lib/x86/libbass.so b/osu.Android/lib/x86/libbass.so
new file mode 100644
index 0000000000..b0f758a42b
Binary files /dev/null and b/osu.Android/lib/x86/libbass.so differ
diff --git a/osu.Android/lib/x86/libbass_fx.so b/osu.Android/lib/x86/libbass_fx.so
new file mode 100644
index 0000000000..526dca39ca
Binary files /dev/null and b/osu.Android/lib/x86/libbass_fx.so differ
diff --git a/osu.Android/osu.Android.csproj b/osu.Android/osu.Android.csproj
new file mode 100644
index 0000000000..ac3905a372
--- /dev/null
+++ b/osu.Android/osu.Android.csproj
@@ -0,0 +1,55 @@
+
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {D1D5F9A8-B40B-40E6-B02F-482D03346D3D}
+ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ {122416d6-6b49-4ee2-a1e8-b825f31c79fe}
+ osu.Android
+ osu.Android
+ Properties\AndroidManifest.xml
+ armeabi-v7a;x86;arm64-v8a
+
+
+ cjk;mideast;other;rare;west
+ d8
+ r8
+
+
+
+
+
+
+
+
+
+
+ {58f6c80c-1253-4a0e-a465-b8c85ebeadf3}
+ osu.Game.Rulesets.Catch
+
+
+ {48f4582b-7687-4621-9cbe-5c24197cb536}
+ osu.Game.Rulesets.Mania
+
+
+ {c92a607b-1fdd-4954-9f92-03ff547d9080}
+ osu.Game.Rulesets.Osu
+
+
+ {f167e17a-7de6-4af5-b920-a5112296c695}
+ osu.Game.Rulesets.Taiko
+
+
+ {2a66dd92-adb1-4994-89e2-c94e04acda0d}
+ osu.Game
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs
index 00cabbadf7..975b7f9f5a 100644
--- a/osu.Desktop/OsuGameDesktop.cs
+++ b/osu.Desktop/OsuGameDesktop.cs
@@ -7,7 +7,6 @@ using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using osu.Desktop.Overlays;
-using osu.Framework.Graphics.Containers;
using osu.Framework.Platform;
using osu.Game;
using osuTK.Input;
@@ -56,7 +55,7 @@ namespace osu.Desktop
LoadComponentAsync(versionManager = new VersionManager { Depth = int.MinValue }, v =>
{
Add(v);
- v.State = Visibility.Visible;
+ v.Show();
});
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows)
@@ -74,13 +73,11 @@ namespace osu.Desktop
{
case Intro _:
case MainMenu _:
- if (versionManager != null)
- versionManager.State = Visibility.Visible;
+ versionManager?.Show();
break;
default:
- if (versionManager != null)
- versionManager.State = Visibility.Hidden;
+ versionManager?.Hide();
break;
}
}
diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs
index d2aad99f41..1f1d2cea5f 100644
--- a/osu.Desktop/Overlays/VersionManager.cs
+++ b/osu.Desktop/Overlays/VersionManager.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
+using osu.Framework.Development;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
@@ -12,7 +13,6 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
-using osu.Game.Utils;
using osuTK;
using osuTK.Graphics;
@@ -61,7 +61,7 @@ namespace osu.Desktop.Overlays
},
new OsuSpriteText
{
- Colour = DebugUtils.IsDebug ? colours.Red : Color4.White,
+ Colour = DebugUtils.IsDebugBuild ? colours.Red : Color4.White,
Text = game.Version
},
}
@@ -120,7 +120,7 @@ namespace osu.Desktop.Overlays
Activated = delegate
{
- changelog.ShowBuild("lazer", version);
+ changelog.ShowBuild(OsuGameBase.CLIENT_STREAM_NAME, version);
return true;
};
}
diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs
index 29554df64c..cb488fea52 100644
--- a/osu.Desktop/Program.cs
+++ b/osu.Desktop/Program.cs
@@ -11,6 +11,7 @@ using osu.Framework.Development;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.IPC;
+using osu.Game.Tournament;
namespace osu.Desktop
{
@@ -46,6 +47,10 @@ namespace osu.Desktop
default:
host.Run(new OsuGameDesktop(args));
break;
+
+ case "--tournament":
+ host.Run(new TournamentGame());
+ break;
}
}
diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs
index e2c7a5e892..78a1e680ec 100644
--- a/osu.Desktop/Updater/SquirrelUpdateManager.cs
+++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs
@@ -1,4 +1,4 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
@@ -25,11 +25,7 @@ namespace osu.Desktop.Updater
private UpdateManager updateManager;
private NotificationOverlay notificationOverlay;
- public void PrepareUpdate()
- {
- // Squirrel returns execution to us after the update process is started, so it's safe to use Wait() here
- UpdateManager.RestartAppWhenExited().Wait();
- }
+ public Task PrepareUpdateAsync() => UpdateManager.RestartAppWhenExited();
[BackgroundDependencyLoader]
private void load(NotificationOverlay notification, OsuGameBase game)
@@ -46,7 +42,7 @@ namespace osu.Desktop.Updater
private async void checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null)
{
//should we schedule a retry on completion of this check?
- bool scheduleRetry = true;
+ bool scheduleRecheck = true;
try
{
@@ -86,10 +82,11 @@ namespace osu.Desktop.Updater
//could fail if deltas are unavailable for full update path (https://github.com/Squirrel/Squirrel.Windows/issues/959)
//try again without deltas.
checkForUpdateAsync(false, notification);
- scheduleRetry = false;
+ scheduleRecheck = false;
}
else
{
+ notification.State = ProgressNotificationState.Cancelled;
Logger.Error(e, @"update failed!");
}
}
@@ -100,11 +97,8 @@ namespace osu.Desktop.Updater
}
finally
{
- if (scheduleRetry)
+ if (scheduleRecheck)
{
- if (notification != null)
- notification.State = ProgressNotificationState.Cancelled;
-
//check again in 30 minutes.
Scheduler.AddDelayed(() => checkForUpdateAsync(), 60000 * 30);
}
@@ -134,8 +128,8 @@ namespace osu.Desktop.Updater
Text = @"Update ready to install. Click to restart!",
Activated = () =>
{
- updateManager.PrepareUpdate();
- game.GracefullyExit();
+ updateManager.PrepareUpdateAsync()
+ .ContinueWith(_ => updateManager.Schedule(() => game.GracefullyExit()));
return true;
}
};
diff --git a/osu.Desktop/lazer.ico b/osu.Desktop/lazer.ico
old mode 100644
new mode 100755
index 0c894dca41..a6aa8abb9f
Binary files a/osu.Desktop/lazer.ico and b/osu.Desktop/lazer.ico differ
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index aa8848c55f..8c9e1f279f 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -17,6 +17,7 @@
osu.Desktop.Program
+
diff --git a/osu.Game.Rulesets.Catch.Tests.Android/MainActivity.cs b/osu.Game.Rulesets.Catch.Tests.Android/MainActivity.cs
new file mode 100644
index 0000000000..d918305f3d
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests.Android/MainActivity.cs
@@ -0,0 +1,16 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using Android.App;
+using Android.Content.PM;
+using osu.Framework.Android;
+using osu.Game.Tests;
+
+namespace osu.Game.Rulesets.Catch.Tests.Android
+{
+ [Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.SensorLandscape, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
+ public class MainActivity : AndroidGameActivity
+ {
+ protected override Framework.Game CreateGame() => new OsuTestBrowser();
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Rulesets.Catch.Tests.Android/Properties/AndroidManifest.xml
new file mode 100644
index 0000000000..db95e18f13
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests.Android/Properties/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch.Tests.Android/osu.Game.Rulesets.Catch.Tests.Android.csproj b/osu.Game.Rulesets.Catch.Tests.Android/osu.Game.Rulesets.Catch.Tests.Android.csproj
new file mode 100644
index 0000000000..88b420ffad
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests.Android/osu.Game.Rulesets.Catch.Tests.Android.csproj
@@ -0,0 +1,39 @@
+
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D}
+ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ {122416d6-6b49-4ee2-a1e8-b825f31c79fe}
+ osu.Game.Rulesets.Catch.Tests
+ osu.Game.Rulesets.Catch.Tests.Android
+ Properties\AndroidManifest.xml
+ armeabi-v7a;x86;arm64-v8a
+
+
+
+
+
+
+
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+
+
+ {58f6c80c-1253-4a0e-a465-b8c85ebeadf3}
+ osu.Game.Rulesets.Catch
+
+
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}
+ osu.Game
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs b/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs
index 44817c1304..beca477943 100644
--- a/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs
+++ b/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs
@@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Catch.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, null, "AppDelegate");
+ UIApplication.Main(args, "GameUIApplication", "AppDelegate");
}
}
}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
index 9cec0d280d..ab3c040b4e 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
@@ -20,14 +20,14 @@ namespace osu.Game.Rulesets.Catch.Tests
{
}
- protected override IBeatmap CreateBeatmap(Ruleset ruleset)
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = new Beatmap
{
BeatmapInfo = new BeatmapInfo
{
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6, SliderMultiplier = 3 },
- Ruleset = ruleset.RulesetInfo
+ Ruleset = ruleset
}
};
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
index 035bbe4b4e..0ad72412fc 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
@@ -29,14 +29,14 @@ namespace osu.Game.Rulesets.Catch.Tests
{
}
- protected override IBeatmap CreateBeatmap(Ruleset ruleset)
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = new Beatmap
{
BeatmapInfo = new BeatmapInfo
{
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
- Ruleset = ruleset.RulesetInfo
+ Ruleset = ruleset
}
};
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs
index 7d7528372a..9ce46ad6ba 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs
@@ -16,14 +16,14 @@ namespace osu.Game.Rulesets.Catch.Tests
{
}
- protected override IBeatmap CreateBeatmap(Ruleset ruleset)
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = new Beatmap
{
BeatmapInfo = new BeatmapInfo
{
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
- Ruleset = ruleset.RulesetInfo
+ Ruleset = ruleset
}
};
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs
new file mode 100644
index 0000000000..33f93cdb4a
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs
@@ -0,0 +1,105 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Tests.Visual;
+using System;
+using System.Collections.Generic;
+using osu.Game.Skinning;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.Sprites;
+using osuTK.Graphics;
+using osu.Framework.Audio.Sample;
+using osu.Framework.Graphics.Textures;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ [TestFixture]
+ public class TestSceneCatcher : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(CatcherSprite),
+ };
+
+ private readonly Container container;
+
+ public TestSceneCatcher()
+ {
+ Child = container = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ AddStep("show default catcher implementation", () => { container.Child = new CatcherSprite(); });
+
+ AddStep("show custom catcher implementation", () =>
+ {
+ container.Child = new CatchCustomSkinSourceContainer
+ {
+ Child = new CatcherSprite()
+ };
+ });
+ }
+
+ private class CatcherCustomSkin : Container
+ {
+ public CatcherCustomSkin()
+ {
+ RelativeSizeAxes = Axes.Both;
+
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Blue
+ },
+ new SpriteText
+ {
+ Text = "custom"
+ }
+ };
+ }
+ }
+
+ [Cached(typeof(ISkinSource))]
+ private class CatchCustomSkinSourceContainer : Container, ISkinSource
+ {
+ public event Action SourceChanged
+ {
+ add { }
+ remove { }
+ }
+
+ public Drawable GetDrawableComponent(string componentName)
+ {
+ switch (componentName)
+ {
+ case "Play/Catch/fruit-catcher-idle":
+ return new CatcherCustomSkin();
+ }
+
+ return null;
+ }
+
+ public SampleChannel GetSample(string sampleName) =>
+ throw new NotImplementedException();
+
+ public Texture GetTexture(string componentName) =>
+ throw new NotImplementedException();
+
+ public TValue GetValue(Func query) where TConfiguration : SkinConfiguration =>
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs
new file mode 100644
index 0000000000..7a9b61c60c
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs
@@ -0,0 +1,160 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Catch.Objects.Drawable;
+using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Tests.Visual;
+using osuTK;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ public class TestSceneDrawableHitObjects : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(CatcherArea.Catcher),
+ typeof(DrawableCatchRuleset),
+ typeof(DrawableFruit),
+ typeof(DrawableJuiceStream),
+ typeof(DrawableBanana)
+ };
+
+ private DrawableCatchRuleset drawableRuleset;
+ private double playfieldTime => drawableRuleset.Playfield.Time.Current;
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ var controlPointInfo = new ControlPointInfo();
+ controlPointInfo.TimingPoints.Add(new TimingControlPoint());
+
+ WorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap
+ {
+ HitObjects = new List { new Fruit() },
+ BeatmapInfo = new BeatmapInfo
+ {
+ BaseDifficulty = new BeatmapDifficulty(),
+ Metadata = new BeatmapMetadata
+ {
+ Artist = @"Unknown",
+ Title = @"You're breathtaking",
+ AuthorString = @"Everyone",
+ },
+ Ruleset = new CatchRuleset().RulesetInfo
+ },
+ ControlPointInfo = controlPointInfo
+ });
+
+ Add(new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Children = new[]
+ {
+ drawableRuleset = new DrawableCatchRuleset(new CatchRuleset(), beatmap, Array.Empty())
+ }
+ });
+
+ AddStep("miss fruits", () => spawnFruits());
+ AddStep("hit fruits", () => spawnFruits(true));
+ AddStep("miss juicestream", () => spawnJuiceStream());
+ AddStep("hit juicestream", () => spawnJuiceStream(true));
+ AddStep("miss bananas", () => spawnBananas());
+ AddStep("hit bananas", () => spawnBananas(true));
+ }
+
+ private void spawnFruits(bool hit = false)
+ {
+ for (int i = 1; i <= 4; i++)
+ {
+ var fruit = new Fruit
+ {
+ X = getXCoords(hit),
+ LastInCombo = i % 4 == 0,
+ StartTime = playfieldTime + 800 + (200 * i)
+ };
+
+ fruit.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
+
+ addToPlayfield(new DrawableFruit(fruit));
+ }
+ }
+
+ private void spawnJuiceStream(bool hit = false)
+ {
+ var xCoords = getXCoords(hit);
+
+ var juice = new JuiceStream
+ {
+ X = xCoords,
+ StartTime = playfieldTime + 1000,
+ Path = new SliderPath(PathType.Linear, new[]
+ {
+ Vector2.Zero,
+ new Vector2(0, 200)
+ })
+ };
+
+ juice.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
+
+ if (juice.NestedHitObjects.Last() is CatchHitObject tail)
+ tail.LastInCombo = true; // usually the (Catch)BeatmapProcessor would do this for us when necessary
+
+ addToPlayfield(new DrawableJuiceStream(juice, drawableRuleset.CreateDrawableRepresentation));
+ }
+
+ private void spawnBananas(bool hit = false)
+ {
+ for (int i = 1; i <= 4; i++)
+ {
+ var banana = new Banana
+ {
+ X = getXCoords(hit),
+ LastInCombo = i % 4 == 0,
+ StartTime = playfieldTime + 800 + (200 * i)
+ };
+
+ banana.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
+
+ addToPlayfield(new DrawableBanana(banana));
+ }
+ }
+
+ private float getXCoords(bool hit)
+ {
+ const float x_offset = 0.2f;
+ float xCoords = drawableRuleset.Playfield.Width / 2;
+
+ if (drawableRuleset.Playfield is CatchPlayfield catchPlayfield)
+ catchPlayfield.CatcherArea.MovableCatcher.X = xCoords - x_offset;
+
+ if (hit)
+ xCoords -= x_offset;
+ else
+ xCoords += x_offset;
+
+ return xCoords;
+ }
+
+ private void addToPlayfield(DrawableCatchHitObject drawable)
+ {
+ foreach (var mod in Mods.Value.OfType())
+ mod.ApplyToDrawableHitObjects(new[] { drawable });
+
+ drawableRuleset.Playfield.Add(drawable);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjectsHidden.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjectsHidden.cs
new file mode 100644
index 0000000000..f6d26addaa
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjectsHidden.cs
@@ -0,0 +1,20 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using osu.Game.Rulesets.Catch.Mods;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ public class TestSceneDrawableHitObjectsHidden : TestSceneDrawableHitObjects
+ {
+ public override IReadOnlyList RequiredTypes => base.RequiredTypes.Concat(new[] { typeof(CatchModHidden) }).ToList();
+
+ public TestSceneDrawableHitObjectsHidden()
+ {
+ Mods.Value = new[] { new CatchModHidden() };
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs
index 7393f75e5a..a603d96201 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
-using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Tests.Visual;
@@ -17,19 +16,19 @@ namespace osu.Game.Rulesets.Catch.Tests
{
}
- [BackgroundDependencyLoader]
- private void load()
+ [Test]
+ public void TestHyperDash()
{
AddAssert("First note is hyperdash", () => Beatmap.Value.Beatmap.HitObjects[0] is Fruit f && f.HyperDash);
}
- protected override IBeatmap CreateBeatmap(Ruleset ruleset)
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = new Beatmap
{
BeatmapInfo =
{
- Ruleset = ruleset.RulesetInfo,
+ Ruleset = ruleset,
BaseDifficulty = new BeatmapDifficulty { CircleSize = 3.6f }
}
};
diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
index 265ecb7688..9acf47a67c 100644
--- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
+++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
index d6a1ed632b..44e1a8e5cc 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
{
if (beatmap.HitObjects.Count == 0)
- return new CatchDifficultyAttributes { Mods = mods };
+ return new CatchDifficultyAttributes { Mods = mods, Skills = skills };
// this is the same as osu!, so there's potential to share the implementation... maybe
double preempt = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / clockRate;
@@ -41,7 +41,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty
StarRating = Math.Sqrt(skills[0].DifficultyValue()) * star_scaling_factor,
Mods = mods,
ApproachRate = preempt > 1200.0 ? -(preempt - 1800.0) / 120.0 : -(preempt - 1200.0) / 150.0 + 5.0,
- MaxCombo = beatmap.HitObjects.Count(h => h is Fruit) + beatmap.HitObjects.OfType().SelectMany(j => j.NestedHitObjects).Count(h => !(h is TinyDroplet))
+ MaxCombo = beatmap.HitObjects.Count(h => h is Fruit) + beatmap.HitObjects.OfType().SelectMany(j => j.NestedHitObjects).Count(h => !(h is TinyDroplet)),
+ Skills = skills
};
}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
index 9990b01427..606a935229 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
@@ -1,7 +1,11 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.Linq;
+using osu.Framework.Graphics;
+using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Catch.Mods
{
@@ -9,5 +13,36 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public override string Description => @"Play with fading fruits.";
public override double ScoreMultiplier => 1.06;
+
+ private const double fade_out_offset_multiplier = 0.6;
+ private const double fade_out_duration_multiplier = 0.44;
+
+ protected override void ApplyHiddenState(DrawableHitObject drawable, ArmedState state)
+ {
+ if (!(drawable is DrawableCatchHitObject catchDrawable))
+ return;
+
+ if (catchDrawable.NestedHitObjects.Any())
+ {
+ foreach (var nestedDrawable in catchDrawable.NestedHitObjects)
+ {
+ if (nestedDrawable is DrawableCatchHitObject nestedCatchDrawable)
+ fadeOutHitObject(nestedCatchDrawable);
+ }
+ }
+ else
+ fadeOutHitObject(catchDrawable);
+ }
+
+ private void fadeOutHitObject(DrawableCatchHitObject drawable)
+ {
+ var hitObject = drawable.HitObject;
+
+ var offset = hitObject.TimePreempt * fade_out_offset_multiplier;
+ var duration = offset - hitObject.TimePreempt * fade_out_duration_multiplier;
+
+ using (drawable.BeginAbsoluteSequence(hitObject.StartTime - offset, true))
+ drawable.FadeOut(duration);
+ }
}
}
diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
index 2153b8dc85..be76edc01b 100644
--- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
@@ -14,6 +14,8 @@ namespace osu.Game.Rulesets.Catch.Objects
public float X { get; set; }
+ public double TimePreempt = 1000;
+
public int IndexInBeatmap { get; set; }
public virtual FruitVisualRepresentation VisualRepresentation => (FruitVisualRepresentation)(ComboIndex % 4);
@@ -54,6 +56,8 @@ namespace osu.Game.Rulesets.Catch.Objects
{
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
+ TimePreempt = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450);
+
Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
index 2f8ccec48b..5785d9a9ca 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
@@ -68,11 +68,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
AccentColour = skin.GetValue(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
}
- private const float preempt = 1000;
-
protected override void UpdateState(ArmedState state)
{
- using (BeginAbsoluteSequence(HitObject.StartTime - preempt))
+ using (BeginAbsoluteSequence(HitObject.StartTime - HitObject.TimePreempt))
this.FadeIn(200);
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
index a9fd34455a..0952e8981a 100644
--- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
@@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Catch.Objects
{
base.CreateNestedHitObjects();
- var tickSamples = Samples.Select(s => new SampleInfo
+ var tickSamples = Samples.Select(s => new HitSampleInfo
{
Bank = s.Bank,
Name = @"slidertick",
@@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Catch.Objects
public double Distance => Path.Distance;
- public List> NodeSamples { get; set; } = new List>();
+ public List> NodeSamples { get; set; } = new List>();
public double? LegacyLastTickOffset { get; set; }
}
diff --git a/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
index dba76eef49..26f20b223a 100644
--- a/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
+++ b/osu.Game.Rulesets.Catch/Properties/AssemblyInfo.cs
@@ -10,3 +10,4 @@ using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Catch.Tests")]
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Catch.Tests.Dynamic")]
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Catch.Tests.iOS")]
+[assembly: InternalsVisibleTo("osu.Game.Rulesets.Catch.Tests.Android")]
diff --git a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
index daa3f61de3..8dd00756f2 100644
--- a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
+++ b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
@@ -43,10 +43,13 @@ namespace osu.Game.Rulesets.Catch.Replays
float positionChange = Math.Abs(lastPosition - h.X);
double timeAvailable = h.StartTime - lastTime;
- //So we can either make it there without a dash or not.
- double speedRequired = positionChange / timeAvailable;
+ // So we can either make it there without a dash or not.
+ // If positionChange is 0, we don't need to move, so speedRequired should also be 0 (could be NaN if timeAvailable is 0 too)
+ // The case where positionChange > 0 and timeAvailable == 0 results in PositiveInfinity which provides expected beheaviour.
+ double speedRequired = positionChange == 0 ? 0 : positionChange / timeAvailable;
- bool dashRequired = speedRequired > movement_speed && h.StartTime != 0;
+ bool dashRequired = speedRequired > movement_speed;
+ bool impossibleJump = speedRequired > movement_speed * 2;
// todo: get correct catcher size, based on difficulty CS.
const float catcher_width_half = CatcherArea.CATCHER_SIZE / CatchPlayfield.BASE_WIDTH * 0.3f * 0.5f;
@@ -59,9 +62,8 @@ namespace osu.Game.Rulesets.Catch.Replays
return;
}
- if (h is Banana)
+ if (impossibleJump)
{
- // auto bananas unrealistically warp to catch 100% combo.
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
}
else if (h.HyperDash)
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
index e7c7fd77df..0b06e958e6 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
@@ -6,8 +6,6 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
-using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
@@ -141,7 +139,7 @@ namespace osu.Game.Rulesets.Catch.UI
[BackgroundDependencyLoader]
private void load()
{
- Children = new Drawable[]
+ Children = new[]
{
caughtFruit = new Container
{
@@ -212,7 +210,7 @@ namespace osu.Game.Rulesets.Catch.UI
Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50);
}
- private Sprite createCatcherSprite() => new CatcherSprite();
+ private Drawable createCatcherSprite() => new CatcherSprite();
///
/// Add a caught fruit to the catcher's stack.
@@ -379,8 +377,8 @@ namespace osu.Game.Rulesets.Catch.UI
X = (float)MathHelper.Clamp(X + direction * Clock.ElapsedFrameTime * speed, 0, 1);
// Correct overshooting.
- if (hyperDashDirection > 0 && hyperDashTargetPosition < X ||
- hyperDashDirection < 0 && hyperDashTargetPosition > X)
+ if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) ||
+ (hyperDashDirection < 0 && hyperDashTargetPosition > X))
{
X = hyperDashTargetPosition;
SetHyperDashState();
@@ -444,23 +442,6 @@ namespace osu.Game.Rulesets.Catch.UI
fruit.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");
- }
- }
}
}
}
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs b/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs
new file mode 100644
index 0000000000..c0c1952064
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/UI/CatcherSprite.cs
@@ -0,0 +1,33 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Skinning;
+using osuTK;
+
+namespace osu.Game.Rulesets.Catch.UI
+{
+ public class CatcherSprite : CompositeDrawable
+ {
+ public CatcherSprite()
+ {
+ Size = new Vector2(CatcherArea.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) * CatcherArea.CATCHER_SIZE;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ InternalChild = new SkinnableSprite(@"Play/Catch/fruit-catcher-idle")
+ {
+ RelativeSizeAxes = Axes.Both,
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ };
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania.Tests.Android/MainActivity.cs b/osu.Game.Rulesets.Mania.Tests.Android/MainActivity.cs
new file mode 100644
index 0000000000..0a3f05ae54
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests.Android/MainActivity.cs
@@ -0,0 +1,16 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using Android.App;
+using Android.Content.PM;
+using osu.Framework.Android;
+using osu.Game.Tests;
+
+namespace osu.Game.Rulesets.Mania.Tests.Android
+{
+ [Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.SensorLandscape, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
+ public class MainActivity : AndroidGameActivity
+ {
+ protected override Framework.Game CreateGame() => new OsuTestBrowser();
+ }
+}
diff --git a/osu.Game.Rulesets.Mania.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Rulesets.Mania.Tests.Android/Properties/AndroidManifest.xml
new file mode 100644
index 0000000000..e6728c801d
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests.Android/Properties/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania.Tests.Android/osu.Game.Rulesets.Mania.Tests.Android.csproj b/osu.Game.Rulesets.Mania.Tests.Android/osu.Game.Rulesets.Mania.Tests.Android.csproj
new file mode 100644
index 0000000000..0e557cb260
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests.Android/osu.Game.Rulesets.Mania.Tests.Android.csproj
@@ -0,0 +1,39 @@
+
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {531F1092-DB27-445D-AA33-2A77C7187C99}
+ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ {122416d6-6b49-4ee2-a1e8-b825f31c79fe}
+ osu.Game.Rulesets.Mania.Tests
+ osu.Game.Rulesets.Mania.Tests.Android
+ Properties\AndroidManifest.xml
+ armeabi-v7a;x86;arm64-v8a
+
+
+
+
+
+
+
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+
+
+ {48f4582b-7687-4621-9cbe-5c24197cb536}
+ osu.Game.Rulesets.Mania
+
+
+ {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}
+ osu.Game
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs b/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs
index d47ac4643f..0362402320 100644
--- a/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs
+++ b/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs
@@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Mania.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, null, "AppDelegate");
+ UIApplication.Main(args, "GameUIApplication", "AppDelegate");
}
}
}
diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
index dbade6ff8d..df5131dd8b 100644
--- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
+++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs
index 704deba78b..e10602312e 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs
@@ -255,7 +255,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
///
/// The time to retrieve the sample info list from.
///
- private List sampleInfoListAt(double time)
+ private List sampleInfoListAt(double time)
{
var curveData = HitObject as IHasCurve;
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs
index 1b6ff16388..ea418eedb4 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs
@@ -364,7 +364,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
break;
}
- bool isDoubleSample(SampleInfo sample) => sample.Name == SampleInfo.HIT_CLAP || sample.Name == SampleInfo.HIT_FINISH;
+ bool isDoubleSample(HitSampleInfo sample) => sample.Name == HitSampleInfo.HIT_CLAP || sample.Name == HitSampleInfo.HIT_FINISH;
bool canGenerateTwoNotes = !convertType.HasFlag(PatternType.LowProbability);
canGenerateTwoNotes &= HitObject.Samples.Any(isDoubleSample) || sampleInfoListAt(HitObject.StartTime).Any(isDoubleSample);
@@ -443,7 +443,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
noteCount = 0;
noteCount = Math.Min(TotalColumns - 1, noteCount);
- bool ignoreHead = !sampleInfoListAt(startTime).Any(s => s.Name == SampleInfo.HIT_WHISTLE || s.Name == SampleInfo.HIT_FINISH || s.Name == SampleInfo.HIT_CLAP);
+ bool ignoreHead = !sampleInfoListAt(startTime).Any(s => s.Name == HitSampleInfo.HIT_WHISTLE || s.Name == HitSampleInfo.HIT_FINISH || s.Name == HitSampleInfo.HIT_CLAP);
var rowPattern = new Pattern();
@@ -472,7 +472,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
///
/// The time to retrieve the sample info list from.
///
- private List sampleInfoListAt(double time)
+ private List sampleInfoListAt(double time)
{
var curveData = HitObject as IHasCurve;
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs
index 9e95be35fa..b3be08e1f7 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/EndTimeObjectPatternGenerator.cs
@@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
switch (TotalColumns)
{
- case 8 when HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && endTime - HitObject.StartTime < 1000:
+ case 8 when HitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH) && endTime - HitObject.StartTime < 1000:
addToPattern(pattern, 0, generateHold);
break;
@@ -72,9 +72,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
};
if (hold.Head.Samples == null)
- hold.Head.Samples = new List();
+ hold.Head.Samples = new List();
- hold.Head.Samples.Add(new SampleInfo { Name = SampleInfo.HIT_NORMAL });
+ hold.Head.Samples.Add(new HitSampleInfo { Name = HitSampleInfo.HIT_NORMAL });
hold.Tail.Samples = HitObject.Samples;
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs
index d13b21183b..decd159ee9 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs
@@ -79,9 +79,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
if (!convertType.HasFlag(PatternType.KeepSingle))
{
- if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && TotalColumns != 8)
+ if (HitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH) && TotalColumns != 8)
convertType |= PatternType.Mirror;
- else if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP))
+ else if (HitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP))
convertType |= PatternType.Gathered;
}
}
@@ -263,7 +263,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
///
/// Whether this hit object can generate a note in the special column.
///
- private bool hasSpecialColumn => HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP) && HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH);
+ private bool hasSpecialColumn => HitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP) && HitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH);
///
/// Generates a random pattern.
@@ -364,7 +364,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
break;
}
- if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_CLAP))
+ if (HitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP))
p2 = 1;
return GetRandomNoteCount(p2, p3, p4, p5);
diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs
index 59fed1031f..4a9c22d339 100644
--- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
{
if (beatmap.HitObjects.Count == 0)
- return new ManiaDifficultyAttributes { Mods = mods };
+ return new ManiaDifficultyAttributes { Mods = mods, Skills = skills };
return new ManiaDifficultyAttributes
{
@@ -38,6 +38,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
Mods = mods,
// Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be removed in the future
GreatHitWindow = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / clockRate,
+ Skills = skills
};
}
diff --git a/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs
index f3ea6c7b71..ca1f7036c7 100644
--- a/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs
+++ b/osu.Game.Rulesets.Mania/Properties/AssemblyInfo.cs
@@ -10,3 +10,4 @@ using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Mania.Tests")]
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Mania.Tests.Dynamic")]
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Mania.Tests.iOS")]
+[assembly: InternalsVisibleTo("osu.Game.Rulesets.Mania.Tests.Android")]
diff --git a/osu.Game.Rulesets.Osu.Tests.Android/MainActivity.cs b/osu.Game.Rulesets.Osu.Tests.Android/MainActivity.cs
new file mode 100644
index 0000000000..e6c508d99e
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests.Android/MainActivity.cs
@@ -0,0 +1,16 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using Android.App;
+using Android.Content.PM;
+using osu.Framework.Android;
+using osu.Game.Tests;
+
+namespace osu.Game.Rulesets.Osu.Tests.Android
+{
+ [Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.SensorLandscape, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
+ public class MainActivity : AndroidGameActivity
+ {
+ protected override Framework.Game CreateGame() => new OsuTestBrowser();
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Rulesets.Osu.Tests.Android/Properties/AndroidManifest.xml
new file mode 100644
index 0000000000..aad907b241
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests.Android/Properties/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Osu.Tests.Android/osu.Game.Rulesets.Osu.Tests.Android.csproj b/osu.Game.Rulesets.Osu.Tests.Android/osu.Game.Rulesets.Osu.Tests.Android.csproj
new file mode 100644
index 0000000000..dcf1573522
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests.Android/osu.Game.Rulesets.Osu.Tests.Android.csproj
@@ -0,0 +1,39 @@
+
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {90CAB706-39CB-4B93-9629-3218A6FF8E9B}
+ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ {122416d6-6b49-4ee2-a1e8-b825f31c79fe}
+ osu.Game.Rulesets.Osu.Tests
+ osu.Game.Rulesets.Osu.Tests.Android
+ Properties\AndroidManifest.xml
+ armeabi-v7a;x86;arm64-v8a
+
+
+
+
+
+
+
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+
+
+ {c92a607b-1fdd-4954-9f92-03ff547d9080}
+ osu.Game.Rulesets.Osu
+
+
+ {2a66dd92-adb1-4994-89e2-c94e04acda0d}
+ osu.Game
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs b/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs
index 7a0797a909..3718264a42 100644
--- a/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs
+++ b/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs
@@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Osu.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, null, "AppDelegate");
+ UIApplication.Main(args, "GameUIApplication", "AppDelegate");
}
}
}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs
index 921246751c..399cf22599 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs
@@ -17,14 +17,14 @@ namespace osu.Game.Rulesets.Osu.Tests
{
}
- protected override IBeatmap CreateBeatmap(Ruleset ruleset)
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = new Beatmap
{
BeatmapInfo = new BeatmapInfo
{
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
- Ruleset = ruleset.RulesetInfo
+ Ruleset = ruleset
}
};
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneResumeOverlay.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneResumeOverlay.cs
index 12a3a8d27e..8e73d6152f 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneResumeOverlay.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneResumeOverlay.cs
@@ -46,11 +46,11 @@ namespace osu.Game.Rulesets.Osu.Tests
AddStep("move mouse away", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.TopLeft));
AddStep("click", () => osuInputManager.GameClick());
- AddAssert("not dismissed", () => !resumeFired && resume.State == Visibility.Visible);
+ AddAssert("not dismissed", () => !resumeFired && resume.State.Value == Visibility.Visible);
AddStep("move mouse back", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.Centre));
AddStep("click", () => osuInputManager.GameClick());
- AddAssert("dismissed", () => resumeFired && resume.State == Visibility.Hidden);
+ AddAssert("dismissed", () => resumeFired && resume.State.Value == Visibility.Hidden);
}
private class ManualOsuInputManager : OsuInputManager
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs
index 1ba6d107be..c5a27205d6 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs
@@ -248,9 +248,9 @@ namespace osu.Game.Rulesets.Osu.Tests
private void createCatmull(int repeats = 0)
{
- var repeatSamples = new List>();
+ var repeatSamples = new List>();
for (int i = 0; i < repeats; i++)
- repeatSamples.Add(new List());
+ repeatSamples.Add(new List());
var slider = new Slider
{
@@ -270,11 +270,11 @@ namespace osu.Game.Rulesets.Osu.Tests
addSlider(slider, 3, 1);
}
- private List> createEmptySamples(int repeats)
+ private List> createEmptySamples(int repeats)
{
- var repeatSamples = new List>();
+ var repeatSamples = new List>();
for (int i = 0; i < repeats; i++)
- repeatSamples.Add(new List());
+ repeatSamples.Add(new List());
return repeatSamples;
}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs
index 193cfe9c94..2eb783233a 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs
@@ -20,7 +20,6 @@ using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.Play;
-using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Visual;
using osuTK;
@@ -299,7 +298,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{
AddStep("load player", () =>
{
- Beatmap.Value = new TestWorkingBeatmap(new Beatmap
+ Beatmap.Value = CreateWorkingBeatmap(new Beatmap
{
HitObjects =
{
@@ -323,7 +322,7 @@ namespace osu.Game.Rulesets.Osu.Tests
BaseDifficulty = new BeatmapDifficulty { SliderTickRate = 3 },
Ruleset = new OsuRuleset().RulesetInfo
},
- }, Clock);
+ });
var p = new ScoreAccessibleReplayPlayer(new Score { Replay = new Replay { Frames = frames } });
diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
index a99a93c3e9..bb3e5a66f3 100644
--- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
+++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs
index b2beda18f4..7bb1f42802 100644
--- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs
+++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs
@@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
break;
if (Vector2Extensions.Distance(stackBaseObject.Position, objectN.Position) < stack_distance
- || stackBaseObject is Slider && Vector2Extensions.Distance(stackBaseObject.EndPosition, objectN.Position) < stack_distance)
+ || (stackBaseObject is Slider && Vector2Extensions.Distance(stackBaseObject.EndPosition, objectN.Position) < stack_distance))
{
stackBaseIndex = n;
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
index e2a1542574..c197933233 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
@@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
{
if (beatmap.HitObjects.Count == 0)
- return new OsuDifficultyAttributes { Mods = mods };
+ return new OsuDifficultyAttributes { Mods = mods, Skills = skills };
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
@@ -50,7 +50,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
SpeedStrain = speedRating,
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
OverallDifficulty = (80 - hitWindowGreat) / 6,
- MaxCombo = maxCombo
+ MaxCombo = maxCombo,
+ Skills = skills
};
}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs
new file mode 100644
index 0000000000..adca95cf8a
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs
@@ -0,0 +1,20 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics.Sprites;
+
+namespace osu.Game.Rulesets.Osu.Mods
+{
+ public class OsuModDeflate : OsuModeObjectScaleTween
+ {
+ public override string Name => "Deflate";
+
+ public override string Acronym => "DF";
+
+ public override IconUsage Icon => FontAwesome.Solid.CompressArrowsAlt;
+
+ public override string Description => "Hit them at the right size!";
+
+ protected override float StartScale => 2f;
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs
index a2da2bbf53..3c81203ad7 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs
@@ -1,17 +1,11 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System.Collections.Generic;
-using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
-using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Osu.Objects;
-using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Mods
{
- internal class OsuModGrow : Mod, IApplicableToDrawableHitObjects
+ internal class OsuModGrow : OsuModeObjectScaleTween
{
public override string Name => "Grow";
@@ -19,58 +13,8 @@ namespace osu.Game.Rulesets.Osu.Mods
public override IconUsage Icon => FontAwesome.Solid.ArrowsAltV;
- public override ModType Type => ModType.Fun;
-
public override string Description => "Hit them at the right size!";
- public override double ScoreMultiplier => 1;
-
- public void ApplyToDrawableHitObjects(IEnumerable drawables)
- {
- foreach (var drawable in drawables)
- {
- switch (drawable)
- {
- case DrawableSpinner _:
- continue;
-
- default:
- drawable.ApplyCustomUpdateState += ApplyCustomState;
- break;
- }
- }
- }
-
- protected virtual void ApplyCustomState(DrawableHitObject drawable, ArmedState state)
- {
- var h = (OsuHitObject)drawable.HitObject;
-
- // apply grow effect
- switch (drawable)
- {
- case DrawableSliderHead _:
- case DrawableSliderTail _:
- // special cases we should *not* be scaling.
- break;
-
- case DrawableSlider _:
- case DrawableHitCircle _:
- {
- using (drawable.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true))
- drawable.ScaleTo(0.5f).Then().ScaleTo(1, h.TimePreempt, Easing.OutSine);
- break;
- }
- }
-
- // remove approach circles
- switch (drawable)
- {
- case DrawableHitCircle circle:
- // we don't want to see the approach circle
- using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true))
- circle.ApproachCircle.Hide();
- break;
- }
- }
+ protected override float StartScale => 0.5f;
}
}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
index ec23570f54..5625028707 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs
@@ -13,13 +13,11 @@ using static osu.Game.Input.Handlers.ReplayInputHandler;
namespace osu.Game.Rulesets.Osu.Mods
{
- public class OsuModRelax : ModRelax, IApplicableFailOverride, IUpdatableByPlayfield, IApplicableToDrawableRuleset
+ public class OsuModRelax : ModRelax, IUpdatableByPlayfield, IApplicableToDrawableRuleset
{
public override string Description => @"You don't need to click. Give your clicking/tapping fingers a break from the heat of things.";
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).ToArray();
- public bool AllowFail => false;
-
public void Update(Playfield playfield)
{
bool requiresHold = false;
@@ -37,11 +35,11 @@ namespace osu.Game.Rulesets.Osu.Mods
if (time < osuHit.HitObject.StartTime - relax_leniency) continue;
- if (osuHit.HitObject is IHasEndTime hasEnd && time > hasEnd.EndTime || osuHit.IsHit)
+ if ((osuHit.HitObject is IHasEndTime hasEnd && time > hasEnd.EndTime) || osuHit.IsHit)
continue;
requiresHit |= osuHit is DrawableHitCircle && osuHit.IsHovered && osuHit.HitObject.HitWindows.CanBeHit(relativetime);
- requiresHold |= osuHit is DrawableSlider slider && (slider.Ball.IsHovered || osuHit.IsHovered) || osuHit is DrawableSpinner;
+ requiresHold |= (osuHit is DrawableSlider slider && (slider.Ball.IsHovered || osuHit.IsHovered)) || osuHit is DrawableSpinner;
}
if (requiresHit)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs b/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs
new file mode 100644
index 0000000000..ad6a15718a
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModeObjectScaleTween.cs
@@ -0,0 +1,84 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using System.Linq;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Game.Configuration;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.Osu.Objects.Drawables;
+
+namespace osu.Game.Rulesets.Osu.Mods
+{
+ ///
+ /// Adjusts the size of hit objects during their fade in animation.
+ ///
+ public abstract class OsuModeObjectScaleTween : Mod, IReadFromConfig, IApplicableToDrawableHitObjects
+ {
+ public override ModType Type => ModType.Fun;
+
+ public override double ScoreMultiplier => 1;
+
+ protected virtual float StartScale => 1;
+
+ protected virtual float EndScale => 1;
+
+ private Bindable increaseFirstObjectVisibility = new Bindable();
+
+ public void ReadFromConfig(OsuConfigManager config)
+ {
+ increaseFirstObjectVisibility = config.GetBindable(OsuSetting.IncreaseFirstObjectVisibility);
+ }
+
+ public void ApplyToDrawableHitObjects(IEnumerable drawables)
+ {
+ foreach (var drawable in drawables.Skip(increaseFirstObjectVisibility.Value ? 1 : 0))
+ {
+ switch (drawable)
+ {
+ case DrawableSpinner _:
+ continue;
+
+ default:
+ drawable.ApplyCustomUpdateState += ApplyCustomState;
+ break;
+ }
+ }
+ }
+
+ protected virtual void ApplyCustomState(DrawableHitObject drawable, ArmedState state)
+ {
+ var h = (OsuHitObject)drawable.HitObject;
+
+ // apply grow effect
+ switch (drawable)
+ {
+ case DrawableSliderHead _:
+ case DrawableSliderTail _:
+ // special cases we should *not* be scaling.
+ break;
+
+ case DrawableSlider _:
+ case DrawableHitCircle _:
+ {
+ using (drawable.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true))
+ drawable.ScaleTo(StartScale).Then().ScaleTo(EndScale, h.TimePreempt, Easing.OutSine);
+ break;
+ }
+ }
+
+ // remove approach circles
+ switch (drawable)
+ {
+ case DrawableHitCircle circle:
+ // we don't want to see the approach circle
+ using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt, true))
+ circle.ApproachCircle.Hide();
+ break;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
index 10b37af957..f372cb65ce 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
@@ -18,6 +18,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
private readonly ShakeContainer shakeContainer;
+ // Must be set to update IsHovered as it's used in relax mdo to detect osu hit objects.
+ public override bool HandlePositionalInput => true;
+
protected DrawableOsuHitObject(OsuHitObject hitObject)
: base(hitObject)
{
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs
index 8ee065aaea..9981585f9e 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ApproachCircle.cs
@@ -4,7 +4,6 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Skinning;
@@ -25,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
- Child = new SkinnableDrawable("Play/osu/approachcircle", name => new Sprite { Texture = textures.Get(name) });
+ Child = new SkinnableSprite("Play/osu/approachcircle");
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs
index 25e1aebd18..33b3667c4f 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs
@@ -2,13 +2,10 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
-using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Lines;
-using osu.Framework.Graphics.Primitives;
using osuTK;
using osuTK.Graphics;
-using osuTK.Graphics.ES30;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
@@ -19,8 +16,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
private readonly SliderPath path;
protected Path Path => path;
- private readonly BufferedContainer container;
-
public float PathRadius
{
get => path.PathRadius;
@@ -44,8 +39,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
return;
path.AccentColour = value;
-
- container.ForceRedraw();
}
}
@@ -61,8 +54,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
return;
path.BorderColour = value;
-
- container.ForceRedraw();
}
}
@@ -78,23 +69,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
return;
path.BorderSize = value;
-
- container.ForceRedraw();
}
}
- public Quad PathDrawQuad => container.ScreenSpaceDrawQuad;
-
protected SliderBody()
{
- InternalChild = container = new BufferedContainer
- {
- RelativeSizeAxes = Axes.Both,
- CacheDrawnFrameBuffer = true,
- Child = path = new SliderPath { Blending = BlendingMode.None }
- };
-
- container.Attach(RenderbufferInternalFormat.DepthComponent16);
+ InternalChild = path = new SliderPath();
}
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => path.ReceivePositionalInputAt(screenSpacePos);
@@ -103,11 +83,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
/// Sets the vertices of the path which should be drawn by this .
///
/// The vertices
- protected void SetVertices(IReadOnlyList vertices)
- {
- path.Vertices = vertices;
- container.ForceRedraw();
- }
+ protected void SetVertices(IReadOnlyList vertices) => path.Vertices = vertices;
private class SliderPath : SmoothPath
{
diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs
index a8aec005d1..a4638c31f2 100644
--- a/osu.Game.Rulesets.Osu/Objects/Slider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs
@@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.Objects
///
internal float LazyTravelDistance;
- public List> NodeSamples { get; set; } = new List>();
+ public List> NodeSamples { get; set; } = new List>();
private int repeatCount;
@@ -157,12 +157,12 @@ namespace osu.Game.Rulesets.Osu.Objects
foreach (var e in
SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset))
{
- var firstSample = Samples.Find(s => s.Name == SampleInfo.HIT_NORMAL)
+ var firstSample = Samples.Find(s => s.Name == HitSampleInfo.HIT_NORMAL)
?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933)
- var sampleList = new List();
+ var sampleList = new List();
if (firstSample != null)
- sampleList.Add(new SampleInfo
+ sampleList.Add(new HitSampleInfo
{
Bank = firstSample.Bank,
Volume = firstSample.Volume,
@@ -225,7 +225,7 @@ namespace osu.Game.Rulesets.Osu.Objects
}
}
- private List getNodeSamples(int nodeIndex) =>
+ private List getNodeSamples(int nodeIndex) =>
nodeIndex < NodeSamples.Count ? NodeSamples[nodeIndex] : Samples;
public override Judgement CreateJudgement() => new OsuJudgement();
diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs
index 83d29c156d..baa4aff413 100644
--- a/osu.Game.Rulesets.Osu/OsuRuleset.cs
+++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs
@@ -134,7 +134,7 @@ namespace osu.Game.Rulesets.Osu
{
new OsuModTransform(),
new OsuModWiggle(),
- new OsuModGrow(),
+ new MultiMod(new OsuModGrow(), new OsuModDeflate()),
new MultiMod(new ModWindUp(), new ModWindDown()),
};
diff --git a/osu.Game.Rulesets.Osu/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Osu/Properties/AssemblyInfo.cs
index b9a7096330..c842874635 100644
--- a/osu.Game.Rulesets.Osu/Properties/AssemblyInfo.cs
+++ b/osu.Game.Rulesets.Osu/Properties/AssemblyInfo.cs
@@ -10,3 +10,4 @@ using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Osu.Tests")]
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Osu.Tests.Dynamic")]
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Osu.Tests.iOS")]
+[assembly: InternalsVisibleTo("osu.Game.Rulesets.Osu.Tests.Android")]
diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
index 1b8fa0de01..b986076593 100644
--- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
+++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
@@ -6,7 +6,7 @@ using System.Diagnostics;
using System.Runtime.InteropServices;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.OpenGL.Buffers;
+using osu.Framework.Graphics.Batches;
using osu.Framework.Graphics.OpenGL.Vertices;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Shaders;
@@ -54,8 +54,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
for (int i = 0; i < max_sprites; i++)
{
- parts[i].InvalidationID = 0;
- parts[i].WasUpdated = true;
+ // InvalidationID 1 forces an update of each part of the cursor trail the first time ApplyState is run on the draw node
+ // This is to prevent garbage data from being sent to the vertex shader, resulting in visual issues on some platforms
+ parts[i].InvalidationID = 1;
}
}
@@ -147,7 +148,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
public Vector2 Position;
public float Time;
public long InvalidationID;
- public bool WasUpdated;
}
private class TrailDrawNode : DrawNode
@@ -162,16 +162,13 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private readonly TrailPart[] parts = new TrailPart[max_sprites];
private Vector2 size;
- private readonly VertexBuffer vertexBuffer = new QuadVertexBuffer(max_sprites, BufferUsageHint.DynamicDraw);
+ private readonly VertexBatch vertexBatch = new QuadBatch(max_sprites, 1);
public TrailDrawNode(CursorTrail source)
: base(source)
{
for (int i = 0; i < max_sprites; i++)
- {
parts[i].InvalidationID = 0;
- parts[i].WasUpdated = false;
- }
}
public override void ApplyState()
@@ -192,55 +189,29 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
public override void Draw(Action vertexAction)
{
- shader.GetUniform("g_FadeClock").UpdateValue(ref time);
-
- int updateStart = -1, updateEnd = 0;
-
- for (int i = 0; i < parts.Length; ++i)
- {
- if (parts[i].WasUpdated)
- {
- if (updateStart == -1)
- updateStart = i;
- updateEnd = i + 1;
-
- int start = i * 4;
- int end = start;
-
- Vector2 pos = parts[i].Position;
- float localTime = parts[i].Time;
-
- texture.DrawQuad(
- new Quad(pos.X - size.X / 2, pos.Y - size.Y / 2, size.X, size.Y),
- DrawColourInfo.Colour,
- null,
- v => vertexBuffer.Vertices[end++] = new TexturedTrailVertex
- {
- Position = v.Position,
- TexturePosition = v.TexturePosition,
- Time = localTime + 1,
- Colour = v.Colour,
- });
-
- parts[i].WasUpdated = false;
- }
- else if (updateStart != -1)
- {
- vertexBuffer.UpdateRange(updateStart * 4, updateEnd * 4);
- updateStart = -1;
- }
- }
-
- // Update all remaining vertices that have been changed.
- if (updateStart != -1)
- vertexBuffer.UpdateRange(updateStart * 4, updateEnd * 4);
-
base.Draw(vertexAction);
shader.Bind();
+ shader.GetUniform("g_FadeClock").UpdateValue(ref time);
- texture.TextureGL.Bind();
- vertexBuffer.Draw();
+ for (int i = 0; i < parts.Length; ++i)
+ {
+ Vector2 pos = parts[i].Position;
+ float localTime = parts[i].Time;
+
+ DrawQuad(
+ texture,
+ new Quad(pos.X - size.X / 2, pos.Y - size.Y / 2, size.X, size.Y),
+ DrawColourInfo.Colour,
+ null,
+ v => vertexBatch.Add(new TexturedTrailVertex
+ {
+ Position = v.Position,
+ TexturePosition = v.TexturePosition,
+ Time = localTime + 1,
+ Colour = v.Colour,
+ }));
+ }
shader.Unbind();
}
@@ -249,7 +220,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
{
base.Dispose(isDisposing);
- vertexBuffer.Dispose();
+ vertexBatch.Dispose();
}
}
diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs
index d72c334ed3..893c7875fa 100644
--- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs
+++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@@ -73,7 +74,10 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
{
case OsuAction.LeftButton:
case OsuAction.RightButton:
- if (--downCount == 0)
+ // Todo: Math.Max() is required as a temporary measure to address https://github.com/ppy/osu-framework/issues/2576
+ downCount = Math.Max(0, downCount - 1);
+
+ if (downCount == 0)
updateExpandedState();
break;
}
diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
index 0d4e7edb7b..9e5df0d6b1 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.UI
private GameplayCursorContainer localCursorContainer;
- public override CursorContainer LocalCursor => State == Visibility.Visible ? localCursorContainer : null;
+ public override CursorContainer LocalCursor => State.Value == Visibility.Visible ? localCursorContainer : null;
protected override string Message => "Click the orange cursor to resume";
diff --git a/osu.Game.Rulesets.Taiko.Tests.Android/MainActivity.cs b/osu.Game.Rulesets.Taiko.Tests.Android/MainActivity.cs
new file mode 100644
index 0000000000..1128a0d37f
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests.Android/MainActivity.cs
@@ -0,0 +1,16 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using Android.App;
+using Android.Content.PM;
+using osu.Framework.Android;
+using osu.Game.Tests;
+
+namespace osu.Game.Rulesets.Taiko.Tests.Android
+{
+ [Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.SensorLandscape, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
+ public class MainActivity : AndroidGameActivity
+ {
+ protected override Framework.Game CreateGame() => new OsuTestBrowser();
+ }
+}
diff --git a/osu.Game.Rulesets.Taiko.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Rulesets.Taiko.Tests.Android/Properties/AndroidManifest.xml
new file mode 100644
index 0000000000..cd4b74aa16
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests.Android/Properties/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko.Tests.Android/osu.Game.Rulesets.Taiko.Tests.Android.csproj b/osu.Game.Rulesets.Taiko.Tests.Android/osu.Game.Rulesets.Taiko.Tests.Android.csproj
new file mode 100644
index 0000000000..392442b713
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests.Android/osu.Game.Rulesets.Taiko.Tests.Android.csproj
@@ -0,0 +1,39 @@
+
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {3701A0A1-8476-42C6-B5C4-D24129B4A484}
+ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ {122416d6-6b49-4ee2-a1e8-b825f31c79fe}
+ osu.Game.Rulesets.Taiko.Tests
+ osu.Game.Rulesets.Taiko.Tests.Android
+ Properties\AndroidManifest.xml
+ armeabi-v7a;x86;arm64-v8a
+
+
+
+
+
+
+
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+
+
+ {f167e17a-7de6-4af5-b920-a5112296c695}
+ osu.Game.Rulesets.Taiko
+
+
+ {2a66dd92-adb1-4994-89e2-c94e04acda0d}
+ osu.Game
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs b/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs
index 6613e9e2b4..330cb42901 100644
--- a/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs
+++ b/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs
@@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, null, "AppDelegate");
+ UIApplication.Main(args, "GameUIApplication", "AppDelegate");
}
}
}
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneInputDrum.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneInputDrum.cs
index 02300a5dde..8c1b0c4c62 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TestSceneInputDrum.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneInputDrum.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
{
typeof(InputDrum),
typeof(DrumSampleMapping),
- typeof(SampleInfo),
+ typeof(HitSampleInfo),
typeof(SampleControlPoint)
};
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs
index 3634ec7d4a..6f9856df83 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs
@@ -18,7 +18,6 @@ using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.Objects.Drawables;
using osu.Game.Rulesets.Taiko.UI;
-using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Visual;
using osuTK;
using osu.Game.Rulesets.Scoring;
@@ -64,7 +63,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
var controlPointInfo = new ControlPointInfo();
controlPointInfo.TimingPoints.Add(new TimingControlPoint());
- WorkingBeatmap beatmap = new TestWorkingBeatmap(new Beatmap
+ WorkingBeatmap beatmap = CreateWorkingBeatmap(new Beatmap
{
HitObjects = new List { new CentreHit() },
BeatmapInfo = new BeatmapInfo
@@ -79,7 +78,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
Ruleset = new TaikoRuleset().RulesetInfo
},
ControlPointInfo = controlPointInfo
- }, Clock);
+ });
Add(playfieldContainer = new Container
{
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs
new file mode 100644
index 0000000000..d0db193738
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs
@@ -0,0 +1,68 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Rulesets.Taiko.Beatmaps;
+using osu.Game.Rulesets.Taiko.Mods;
+using osu.Game.Rulesets.Taiko.Objects;
+using osu.Game.Screens.Play;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Taiko.Tests
+{
+ public class TestSceneTaikoSuddenDeath : PlayerTestScene
+ {
+ public TestSceneTaikoSuddenDeath()
+ : base(new TaikoRuleset())
+ {
+ }
+
+ protected override bool AllowFail => true;
+
+ protected override Player CreatePlayer(Ruleset ruleset)
+ {
+ Mods.Value = Mods.Value.Concat(new[] { new TaikoModSuddenDeath() }).ToArray();
+ return new ScoreAccessiblePlayer();
+ }
+
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) =>
+ new TaikoBeatmap
+ {
+ HitObjects =
+ {
+ new Swell { StartTime = 1500 },
+ new Hit { StartTime = 100000 },
+ },
+ BeatmapInfo =
+ {
+ Ruleset = new TaikoRuleset().RulesetInfo
+ }
+ };
+
+ [Test]
+ public void TestSpinnerDoesNotFail()
+ {
+ bool judged = false;
+ AddStep("Setup judgements", () =>
+ {
+ judged = false;
+ ((ScoreAccessiblePlayer)Player).ScoreProcessor.NewJudgement += b => judged = true;
+ });
+ AddUntilStep("swell judged", () => judged);
+ AddAssert("not failed", () => !Player.HasFailed);
+ }
+
+ private class ScoreAccessiblePlayer : TestPlayer
+ {
+ public ScoreAccessiblePlayer()
+ : base(false, false)
+ {
+ }
+
+ public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
index 216cc0222f..5510c3a9d9 100644
--- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
+++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs
index d7fa661e8a..ad2596931d 100644
--- a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs
+++ b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs
@@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Taiko.Audio
foreach (var s in samplePoints)
{
var centre = s.GetSampleInfo();
- var rim = s.GetSampleInfo(SampleInfo.HIT_CLAP);
+ var rim = s.GetSampleInfo(HitSampleInfo.HIT_CLAP);
// todo: this is ugly
centre.Namespace = "taiko";
@@ -43,9 +43,9 @@ namespace osu.Game.Rulesets.Taiko.Audio
}
}
- private SkinnableSound addSound(SampleInfo sampleInfo)
+ private SkinnableSound addSound(HitSampleInfo hitSampleInfo)
{
- var drawable = new SkinnableSound(sampleInfo);
+ var drawable = new SkinnableSound(hitSampleInfo);
Sounds.Add(drawable);
return drawable;
}
diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs
index f8672037cd..f0cf8d9c7d 100644
--- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs
+++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs
@@ -79,9 +79,9 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
var curveData = obj as IHasCurve;
// Old osu! used hit sounding to determine various hit type information
- List samples = obj.Samples;
+ List samples = obj.Samples;
- bool strong = samples.Any(s => s.Name == SampleInfo.HIT_FINISH);
+ bool strong = samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH);
if (distanceData != null)
{
@@ -117,15 +117,15 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength)
{
- List> allSamples = curveData != null ? curveData.NodeSamples : new List>(new[] { samples });
+ List> allSamples = curveData != null ? curveData.NodeSamples : new List>(new[] { samples });
int i = 0;
for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing)
{
- List currentSamples = allSamples[i];
- bool isRim = currentSamples.Any(s => s.Name == SampleInfo.HIT_CLAP || s.Name == SampleInfo.HIT_WHISTLE);
- strong = currentSamples.Any(s => s.Name == SampleInfo.HIT_FINISH);
+ List currentSamples = allSamples[i];
+ bool isRim = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE);
+ strong = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_FINISH);
if (isRim)
{
@@ -175,7 +175,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
}
else
{
- bool isRim = samples.Any(s => s.Name == SampleInfo.HIT_CLAP || s.Name == SampleInfo.HIT_WHISTLE);
+ bool isRim = samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE);
if (isRim)
{
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
index 685ad9949b..c8f3e18911 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
{
if (beatmap.HitObjects.Count == 0)
- return new TaikoDifficultyAttributes { Mods = mods };
+ return new TaikoDifficultyAttributes { Mods = mods, Skills = skills };
return new TaikoDifficultyAttributes
{
@@ -36,6 +36,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
// Todo: This int cast is temporary to achieve 1:1 results with osu!stable, and should be removed in the future
GreatHitWindow = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / clockRate,
MaxCombo = beatmap.HitObjects.Count(h => h is Hit),
+ Skills = skills
};
}
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs
index 502dd54e9e..a6f902208c 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs
@@ -9,5 +9,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
{
public override string Description => @"Beats fade out before you hit them!";
public override double ScoreMultiplier => 1.06;
+ public override bool HasImplementation => false;
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
index 119940536e..bd45b52d7b 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
@@ -122,7 +122,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
}
// Normal and clap samples are handled by the drum
- protected override IEnumerable GetSamples() => HitObject.Samples.Where(s => s.Name != SampleInfo.HIT_NORMAL && s.Name != SampleInfo.HIT_CLAP);
+ protected override IEnumerable GetSamples() => HitObject.Samples.Where(s => s.Name != HitSampleInfo.HIT_NORMAL && s.Name != HitSampleInfo.HIT_CLAP);
protected override string SampleNamespace => "Taiko";
diff --git a/osu.Game.Rulesets.Taiko/Properties/AssemblyInfo.cs b/osu.Game.Rulesets.Taiko/Properties/AssemblyInfo.cs
index 81f15fb293..ca7d04876e 100644
--- a/osu.Game.Rulesets.Taiko/Properties/AssemblyInfo.cs
+++ b/osu.Game.Rulesets.Taiko/Properties/AssemblyInfo.cs
@@ -10,3 +10,4 @@ using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Taiko.Tests")]
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Taiko.Tests.Dynamic")]
[assembly: InternalsVisibleTo("osu.Game.Rulesets.Taiko.Tests.iOS")]
+[assembly: InternalsVisibleTo("osu.Game.Rulesets.Taiko.Tests.Android")]
diff --git a/osu.Game.Tests.Android/MainActivity.cs b/osu.Game.Tests.Android/MainActivity.cs
new file mode 100644
index 0000000000..0695c8e37b
--- /dev/null
+++ b/osu.Game.Tests.Android/MainActivity.cs
@@ -0,0 +1,15 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using Android.App;
+using Android.Content.PM;
+using osu.Framework.Android;
+
+namespace osu.Game.Tests.Android
+{
+ [Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.SensorLandscape, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = true)]
+ public class MainActivity : AndroidGameActivity
+ {
+ protected override Framework.Game CreateGame() => new OsuTestBrowser();
+ }
+}
diff --git a/osu.Game.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Tests.Android/Properties/AndroidManifest.xml
new file mode 100644
index 0000000000..bb996dc5ca
--- /dev/null
+++ b/osu.Game.Tests.Android/Properties/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj b/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj
new file mode 100644
index 0000000000..c2dd194e09
--- /dev/null
+++ b/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj
@@ -0,0 +1,77 @@
+
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {5CC222DC-5716-4499-B897-DCBDDA4A5CF9}
+ {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ {122416d6-6b49-4ee2-a1e8-b825f31c79fe}
+ osu.Game.Tests
+ osu.Game.Tests.Android
+ Properties\AndroidManifest.xml
+ armeabi-v7a;x86;arm64-v8a
+
+
+
+
+
+
+
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+ %(RecursiveDir)%(Filename)%(Extension)
+
+
+
+
+ {58f6c80c-1253-4a0e-a465-b8c85ebeadf3}
+ osu.Game.Rulesets.Catch
+
+
+ {48f4582b-7687-4621-9cbe-5c24197cb536}
+ osu.Game.Rulesets.Mania
+
+
+ {c92a607b-1fdd-4954-9f92-03ff547d9080}
+ osu.Game.Rulesets.Osu
+
+
+ {f167e17a-7de6-4af5-b920-a5112296c695}
+ osu.Game.Rulesets.Taiko
+
+
+ {2a66dd92-adb1-4994-89e2-c94e04acda0d}
+ osu.Game
+
+
+
+
+ 2.0.0
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Tests.iOS/Application.cs b/osu.Game.Tests.iOS/Application.cs
index a23fe4e129..d96a3e27a4 100644
--- a/osu.Game.Tests.iOS/Application.cs
+++ b/osu.Game.Tests.iOS/Application.cs
@@ -9,7 +9,7 @@ namespace osu.Game.Tests.iOS
{
public static void Main(string[] args)
{
- UIApplication.Main(args, null, "AppDelegate");
+ UIApplication.Main(args, "GameUIApplication", "AppDelegate");
}
}
}
diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
index 5fd5fe342d..d087251e7e 100644
--- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
@@ -354,14 +354,14 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.IsNotNull(curveData);
Assert.AreEqual(new Vector2(192, 168), positionData.Position);
Assert.AreEqual(956, hitObjects[0].StartTime);
- Assert.IsTrue(hitObjects[0].Samples.Any(s => s.Name == SampleInfo.HIT_NORMAL));
+ Assert.IsTrue(hitObjects[0].Samples.Any(s => s.Name == HitSampleInfo.HIT_NORMAL));
positionData = hitObjects[1] as IHasPosition;
Assert.IsNotNull(positionData);
Assert.AreEqual(new Vector2(304, 56), positionData.Position);
Assert.AreEqual(1285, hitObjects[1].StartTime);
- Assert.IsTrue(hitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP));
+ Assert.IsTrue(hitObjects[1].Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP));
}
}
@@ -384,7 +384,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.AreEqual("soft-hitnormal8", getTestableSampleInfo(hitObjects[4]).LookupNames.First());
}
- SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
+ HitSampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
}
[Test]
@@ -402,7 +402,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.AreEqual("normal-hitnormal3", getTestableSampleInfo(hitObjects[2]).LookupNames.First());
}
- SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
+ HitSampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
}
[Test]
@@ -422,7 +422,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.AreEqual(70, getTestableSampleInfo(hitObjects[3]).Volume);
}
- SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
+ HitSampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]);
}
[Test]
@@ -438,34 +438,34 @@ namespace osu.Game.Tests.Beatmaps.Formats
var slider1 = (ConvertSlider)hitObjects[0];
Assert.AreEqual(1, slider1.NodeSamples[0].Count);
- Assert.AreEqual(SampleInfo.HIT_NORMAL, slider1.NodeSamples[0][0].Name);
+ Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider1.NodeSamples[0][0].Name);
Assert.AreEqual(1, slider1.NodeSamples[1].Count);
- Assert.AreEqual(SampleInfo.HIT_NORMAL, slider1.NodeSamples[1][0].Name);
+ Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider1.NodeSamples[1][0].Name);
Assert.AreEqual(1, slider1.NodeSamples[2].Count);
- Assert.AreEqual(SampleInfo.HIT_NORMAL, slider1.NodeSamples[2][0].Name);
+ Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider1.NodeSamples[2][0].Name);
var slider2 = (ConvertSlider)hitObjects[1];
Assert.AreEqual(2, slider2.NodeSamples[0].Count);
- Assert.AreEqual(SampleInfo.HIT_NORMAL, slider2.NodeSamples[0][0].Name);
- Assert.AreEqual(SampleInfo.HIT_CLAP, slider2.NodeSamples[0][1].Name);
+ Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[0][0].Name);
+ Assert.AreEqual(HitSampleInfo.HIT_CLAP, slider2.NodeSamples[0][1].Name);
Assert.AreEqual(2, slider2.NodeSamples[1].Count);
- Assert.AreEqual(SampleInfo.HIT_NORMAL, slider2.NodeSamples[1][0].Name);
- Assert.AreEqual(SampleInfo.HIT_CLAP, slider2.NodeSamples[1][1].Name);
+ Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[1][0].Name);
+ Assert.AreEqual(HitSampleInfo.HIT_CLAP, slider2.NodeSamples[1][1].Name);
Assert.AreEqual(2, slider2.NodeSamples[2].Count);
- Assert.AreEqual(SampleInfo.HIT_NORMAL, slider2.NodeSamples[2][0].Name);
- Assert.AreEqual(SampleInfo.HIT_CLAP, slider2.NodeSamples[2][1].Name);
+ Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider2.NodeSamples[2][0].Name);
+ Assert.AreEqual(HitSampleInfo.HIT_CLAP, slider2.NodeSamples[2][1].Name);
var slider3 = (ConvertSlider)hitObjects[2];
Assert.AreEqual(2, slider3.NodeSamples[0].Count);
- Assert.AreEqual(SampleInfo.HIT_NORMAL, slider3.NodeSamples[0][0].Name);
- Assert.AreEqual(SampleInfo.HIT_WHISTLE, slider3.NodeSamples[0][1].Name);
+ Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider3.NodeSamples[0][0].Name);
+ Assert.AreEqual(HitSampleInfo.HIT_WHISTLE, slider3.NodeSamples[0][1].Name);
Assert.AreEqual(1, slider3.NodeSamples[1].Count);
- Assert.AreEqual(SampleInfo.HIT_NORMAL, slider3.NodeSamples[1][0].Name);
+ Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider3.NodeSamples[1][0].Name);
Assert.AreEqual(2, slider3.NodeSamples[2].Count);
- Assert.AreEqual(SampleInfo.HIT_NORMAL, slider3.NodeSamples[2][0].Name);
- Assert.AreEqual(SampleInfo.HIT_CLAP, slider3.NodeSamples[2][1].Name);
+ Assert.AreEqual(HitSampleInfo.HIT_NORMAL, slider3.NodeSamples[2][0].Name);
+ Assert.AreEqual(HitSampleInfo.HIT_CLAP, slider3.NodeSamples[2][1].Name);
}
}
diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
index 39b7735a55..a725c58462 100644
--- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
@@ -101,14 +101,14 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.IsNotNull(curveData);
Assert.AreEqual(new Vector2(192, 168), positionData.Position);
Assert.AreEqual(956, beatmap.HitObjects[0].StartTime);
- Assert.IsTrue(beatmap.HitObjects[0].Samples.Any(s => s.Name == SampleInfo.HIT_NORMAL));
+ Assert.IsTrue(beatmap.HitObjects[0].Samples.Any(s => s.Name == HitSampleInfo.HIT_NORMAL));
positionData = beatmap.HitObjects[1] as IHasPosition;
Assert.IsNotNull(positionData);
Assert.AreEqual(new Vector2(304, 56), positionData.Position);
Assert.AreEqual(1285, beatmap.HitObjects[1].StartTime);
- Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == SampleInfo.HIT_CLAP));
+ Assert.IsTrue(beatmap.HitObjects[1].Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP));
}
[TestCase(normal)]
diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
index f020c2a805..ad0ed00989 100644
--- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
@@ -11,7 +11,9 @@ using NUnit.Framework;
using osu.Framework.Platform;
using osu.Game.IPC;
using osu.Framework.Allocation;
+using osu.Framework.Logging;
using osu.Game.Beatmaps;
+using osu.Game.IO;
using osu.Game.Tests.Resources;
using SharpCompress.Archives.Zip;
@@ -21,14 +23,14 @@ namespace osu.Game.Tests.Beatmaps.IO
public class ImportBeatmapTest
{
[Test]
- public void TestImportWhenClosed()
+ public async Task TestImportWhenClosed()
{
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportWhenClosed"))
{
try
{
- LoadOszIntoOsu(loadOsu(host));
+ await LoadOszIntoOsu(loadOsu(host));
}
finally
{
@@ -38,7 +40,7 @@ namespace osu.Game.Tests.Beatmaps.IO
}
[Test]
- public void TestImportThenDelete()
+ public async Task TestImportThenDelete()
{
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportThenDelete"))
@@ -47,7 +49,7 @@ namespace osu.Game.Tests.Beatmaps.IO
{
var osu = loadOsu(host);
- var imported = LoadOszIntoOsu(osu);
+ var imported = await LoadOszIntoOsu(osu);
deleteBeatmapSet(imported, osu);
}
@@ -59,7 +61,7 @@ namespace osu.Game.Tests.Beatmaps.IO
}
[Test]
- public void TestImportThenImport()
+ public async Task TestImportThenImport()
{
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportThenImport"))
@@ -68,17 +70,15 @@ namespace osu.Game.Tests.Beatmaps.IO
{
var osu = loadOsu(host);
- var imported = LoadOszIntoOsu(osu);
- var importedSecondTime = LoadOszIntoOsu(osu);
+ var imported = await LoadOszIntoOsu(osu);
+ var importedSecondTime = await 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);
- var manager = osu.Dependencies.Get();
-
- Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count);
- Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
+ checkBeatmapSetCount(osu, 1);
+ checkSingleReferencedFileCount(osu, 18);
}
finally
{
@@ -88,30 +88,41 @@ namespace osu.Game.Tests.Beatmaps.IO
}
[Test]
- public void TestRollbackOnFailure()
+ public async Task 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
{
+ int itemAddRemoveFireCount = 0;
+ int loggedExceptionCount = 0;
+
+ Logger.NewEntry += l =>
+ {
+ if (l.Target == LoggingTarget.Database && l.Exception != null)
+ Interlocked.Increment(ref loggedExceptionCount);
+ };
+
var osu = loadOsu(host);
var manager = osu.Dependencies.Get();
- int fireCount = 0;
-
// ReSharper disable once AccessToModifiedClosure
- manager.ItemAdded += (_, __) => fireCount++;
- manager.ItemRemoved += _ => fireCount++;
+ manager.ItemAdded += _ => Interlocked.Increment(ref itemAddRemoveFireCount);
+ manager.ItemRemoved += _ => Interlocked.Increment(ref itemAddRemoveFireCount);
- var imported = LoadOszIntoOsu(osu);
+ var imported = await LoadOszIntoOsu(osu);
- Assert.AreEqual(0, fireCount -= 1);
+ Assert.AreEqual(0, itemAddRemoveFireCount -= 1);
imported.Hash += "-changed";
manager.Update(imported);
- Assert.AreEqual(0, fireCount -= 2);
+ Assert.AreEqual(0, itemAddRemoveFireCount -= 2);
+
+ checkBeatmapSetCount(osu, 1);
+ checkBeatmapCount(osu, 12);
+ checkSingleReferencedFileCount(osu, 18);
var breakTemp = TestResources.GetTestBeatmapForImport();
@@ -127,19 +138,24 @@ namespace osu.Game.Tests.Beatmaps.IO
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);
+ try
+ {
+ await manager.Import(breakTemp);
+ }
+ catch
+ {
+ }
// no events should be fired in the case of a rollback.
- Assert.AreEqual(0, fireCount);
+ Assert.AreEqual(0, itemAddRemoveFireCount);
- Assert.AreEqual(1, manager.GetAllUsableBeatmapSets().Count);
- Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
- Assert.AreEqual(12, manager.QueryBeatmaps(_ => true).ToList().Count);
+ checkBeatmapSetCount(osu, 1);
+ checkBeatmapCount(osu, 12);
+
+ checkSingleReferencedFileCount(osu, 18);
+
+ Assert.AreEqual(1, loggedExceptionCount);
}
finally
{
@@ -149,7 +165,7 @@ namespace osu.Game.Tests.Beatmaps.IO
}
[Test]
- public void TestImportThenImportDifferentHash()
+ public async Task TestImportThenImportDifferentHash()
{
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportThenImportDifferentHash"))
@@ -159,19 +175,18 @@ namespace osu.Game.Tests.Beatmaps.IO
var osu = loadOsu(host);
var manager = osu.Dependencies.Get();
- var imported = LoadOszIntoOsu(osu);
+ var imported = await LoadOszIntoOsu(osu);
imported.Hash += "-changed";
manager.Update(imported);
- var importedSecondTime = LoadOszIntoOsu(osu);
+ var importedSecondTime = await LoadOszIntoOsu(osu);
Assert.IsTrue(imported.ID != importedSecondTime.ID);
Assert.IsTrue(imported.Beatmaps.First().ID < importedSecondTime.Beatmaps.First().ID);
// 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);
+ checkBeatmapSetCount(osu, 1);
}
finally
{
@@ -181,7 +196,7 @@ namespace osu.Game.Tests.Beatmaps.IO
}
[Test]
- public void TestImportThenDeleteThenImport()
+ public async Task TestImportThenDeleteThenImport()
{
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportThenDeleteThenImport"))
@@ -190,11 +205,11 @@ namespace osu.Game.Tests.Beatmaps.IO
{
var osu = loadOsu(host);
- var imported = LoadOszIntoOsu(osu);
+ var imported = await LoadOszIntoOsu(osu);
deleteBeatmapSet(imported, osu);
- var importedSecondTime = LoadOszIntoOsu(osu);
+ var importedSecondTime = await LoadOszIntoOsu(osu);
// check the newly "imported" beatmap is actually just the restored previous import. since it matches hash.
Assert.IsTrue(imported.ID == importedSecondTime.ID);
@@ -209,7 +224,7 @@ namespace osu.Game.Tests.Beatmaps.IO
[TestCase(true)]
[TestCase(false)]
- public void TestImportThenDeleteThenImportWithOnlineIDMismatch(bool set)
+ public async Task TestImportThenDeleteThenImportWithOnlineIDMismatch(bool set)
{
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
using (HeadlessGameHost host = new CleanRunHeadlessGameHost($"TestImportThenDeleteThenImport-{set}"))
@@ -218,7 +233,7 @@ namespace osu.Game.Tests.Beatmaps.IO
{
var osu = loadOsu(host);
- var imported = LoadOszIntoOsu(osu);
+ var imported = await LoadOszIntoOsu(osu);
if (set)
imported.OnlineBeatmapSetID = 1234;
@@ -229,7 +244,7 @@ namespace osu.Game.Tests.Beatmaps.IO
deleteBeatmapSet(imported, osu);
- var importedSecondTime = LoadOszIntoOsu(osu);
+ var importedSecondTime = await LoadOszIntoOsu(osu);
// check the newly "imported" beatmap has been reimported due to mismatch (even though hashes matched)
Assert.IsTrue(imported.ID != importedSecondTime.ID);
@@ -243,7 +258,7 @@ namespace osu.Game.Tests.Beatmaps.IO
}
[Test]
- public void TestImportWithDuplicateBeatmapIDs()
+ public async Task TestImportWithDuplicateBeatmapIDs()
{
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportWithDuplicateBeatmapID"))
@@ -284,7 +299,7 @@ namespace osu.Game.Tests.Beatmaps.IO
var manager = osu.Dependencies.Get();
- var imported = manager.Import(toImport);
+ var imported = await manager.Import(toImport);
Assert.NotNull(imported);
Assert.AreEqual(null, imported.Beatmaps[0].OnlineBeatmapID);
@@ -330,7 +345,7 @@ namespace osu.Game.Tests.Beatmaps.IO
}
[Test]
- public void TestImportWhenFileOpen()
+ public async Task TestImportWhenFileOpen()
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportWhenFileOpen"))
{
@@ -339,7 +354,7 @@ namespace osu.Game.Tests.Beatmaps.IO
var osu = loadOsu(host);
var temp = TestResources.GetTestBeatmapForImport();
using (File.OpenRead(temp))
- osu.Dependencies.Get().Import(temp);
+ await osu.Dependencies.Get().Import(temp);
ensureLoaded(osu);
File.Delete(temp);
Assert.IsFalse(File.Exists(temp), "We likely held a read lock on the file when we shouldn't");
@@ -351,13 +366,13 @@ namespace osu.Game.Tests.Beatmaps.IO
}
}
- public static BeatmapSetInfo LoadOszIntoOsu(OsuGameBase osu, string path = null)
+ public static async Task LoadOszIntoOsu(OsuGameBase osu, string path = null)
{
var temp = path ?? TestResources.GetTestBeatmapForImport();
var manager = osu.Dependencies.Get();
- manager.Import(temp);
+ await manager.Import(temp);
var imported = manager.GetAllUsableBeatmapSets();
@@ -373,11 +388,32 @@ namespace osu.Game.Tests.Beatmaps.IO
var manager = osu.Dependencies.Get();
manager.Delete(imported);
- Assert.IsTrue(manager.GetAllUsableBeatmapSets().Count == 0);
- Assert.AreEqual(1, manager.QueryBeatmapSets(_ => true).ToList().Count);
+ checkBeatmapSetCount(osu, 0);
+ checkBeatmapSetCount(osu, 1, true);
+ checkSingleReferencedFileCount(osu, 0);
+
Assert.IsTrue(manager.QueryBeatmapSets(_ => true).First().DeletePending);
}
+ private void checkBeatmapSetCount(OsuGameBase osu, int expected, bool includeDeletePending = false)
+ {
+ var manager = osu.Dependencies.Get();
+
+ Assert.AreEqual(expected, includeDeletePending
+ ? manager.QueryBeatmapSets(_ => true).ToList().Count
+ : manager.GetAllUsableBeatmapSets().Count);
+ }
+
+ private void checkBeatmapCount(OsuGameBase osu, int expected)
+ {
+ Assert.AreEqual(expected, osu.Dependencies.Get().QueryBeatmaps(_ => true).ToList().Count);
+ }
+
+ private void checkSingleReferencedFileCount(OsuGameBase osu, int expected)
+ {
+ Assert.AreEqual(expected, osu.Dependencies.Get().QueryFiles(f => f.ReferenceCount == 1).Count());
+ }
+
private OsuGameBase loadOsu(GameHost host)
{
var osu = new OsuGameBase();
diff --git a/osu.Game.Tests/NonVisual/FramedReplayinputHandlerTest.cs b/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs
similarity index 94%
rename from osu.Game.Tests/NonVisual/FramedReplayinputHandlerTest.cs
rename to osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs
index 73387fa5ab..18cbd4e7c5 100644
--- a/osu.Game.Tests/NonVisual/FramedReplayinputHandlerTest.cs
+++ b/osu.Game.Tests/NonVisual/FramedReplayInputHandlerTest.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Game.Replays;
@@ -9,7 +10,7 @@ using osu.Game.Rulesets.Replays;
namespace osu.Game.Tests.NonVisual
{
[TestFixture]
- public class FramedReplayinputHandlerTest
+ public class FramedReplayInputHandlerTest
{
private Replay replay;
private TestInputHandler handler;
@@ -160,10 +161,7 @@ namespace osu.Game.Tests.NonVisual
[Test]
public void TestRewindInsideImportantSection()
{
- // fast forward to important section
- while (handler.SetFrameFromTime(3000) != null)
- {
- }
+ fastForwardToPoint(3000);
setTime(4000, 4000);
confirmCurrentFrame(4);
@@ -205,10 +203,7 @@ namespace osu.Game.Tests.NonVisual
[Test]
public void TestRewindOutOfImportantSection()
{
- // fast forward to important section
- while (handler.SetFrameFromTime(3500) != null)
- {
- }
+ fastForwardToPoint(3500);
confirmCurrentFrame(3);
confirmNextFrame(4);
@@ -227,6 +222,15 @@ namespace osu.Game.Tests.NonVisual
confirmNextFrame(2);
}
+ private void fastForwardToPoint(double destination)
+ {
+ for (int i = 0; i < 1000; i++)
+ if (handler.SetFrameFromTime(destination) == null)
+ return;
+
+ throw new TimeoutException("Seek was never fulfilled");
+ }
+
private void setTime(double set, double? expect)
{
Assert.AreEqual(expect, handler.SetFrameFromTime(set));
@@ -274,6 +278,7 @@ namespace osu.Game.Tests.NonVisual
public TestInputHandler(Replay replay)
: base(replay)
{
+ FrameAccuratePlayback = true;
}
protected override double AllowedImportantTimeSpan => 1000;
diff --git a/osu.Game.Tests/Scores/IO/ImportScoreTest.cs b/osu.Game.Tests/Scores/IO/ImportScoreTest.cs
index e39f18c3cd..4babb07213 100644
--- a/osu.Game.Tests/Scores/IO/ImportScoreTest.cs
+++ b/osu.Game.Tests/Scores/IO/ImportScoreTest.cs
@@ -23,13 +23,13 @@ namespace osu.Game.Tests.Scores.IO
public class ImportScoreTest
{
[Test]
- public void TestBasicImport()
+ public async Task TestBasicImport()
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestBasicImport"))
{
try
{
- var osu = loadOsu(host);
+ var osu = await loadOsu(host);
var toImport = new ScoreInfo
{
@@ -43,7 +43,7 @@ namespace osu.Game.Tests.Scores.IO
OnlineScoreID = 12345,
};
- var imported = loadIntoOsu(osu, toImport);
+ var imported = await loadIntoOsu(osu, toImport);
Assert.AreEqual(toImport.Rank, imported.Rank);
Assert.AreEqual(toImport.TotalScore, imported.TotalScore);
@@ -62,20 +62,20 @@ namespace osu.Game.Tests.Scores.IO
}
[Test]
- public void TestImportMods()
+ public async Task TestImportMods()
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportMods"))
{
try
{
- var osu = loadOsu(host);
+ var osu = await loadOsu(host);
var toImport = new ScoreInfo
{
Mods = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() },
};
- var imported = loadIntoOsu(osu, toImport);
+ var imported = await loadIntoOsu(osu, toImport);
Assert.IsTrue(imported.Mods.Any(m => m is OsuModHardRock));
Assert.IsTrue(imported.Mods.Any(m => m is OsuModDoubleTime));
@@ -88,13 +88,13 @@ namespace osu.Game.Tests.Scores.IO
}
[Test]
- public void TestImportStatistics()
+ public async Task TestImportStatistics()
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost("TestImportStatistics"))
{
try
{
- var osu = loadOsu(host);
+ var osu = await loadOsu(host);
var toImport = new ScoreInfo
{
@@ -105,7 +105,7 @@ namespace osu.Game.Tests.Scores.IO
}
};
- var imported = loadIntoOsu(osu, toImport);
+ var imported = await loadIntoOsu(osu, toImport);
Assert.AreEqual(toImport.Statistics[HitResult.Perfect], imported.Statistics[HitResult.Perfect]);
Assert.AreEqual(toImport.Statistics[HitResult.Miss], imported.Statistics[HitResult.Miss]);
@@ -117,7 +117,7 @@ namespace osu.Game.Tests.Scores.IO
}
}
- private ScoreInfo loadIntoOsu(OsuGameBase osu, ScoreInfo score)
+ private async Task loadIntoOsu(OsuGameBase osu, ScoreInfo score)
{
var beatmapManager = osu.Dependencies.Get();
@@ -125,20 +125,24 @@ namespace osu.Game.Tests.Scores.IO
score.Ruleset = new OsuRuleset().RulesetInfo;
var scoreManager = osu.Dependencies.Get();
- scoreManager.Import(score);
+ await scoreManager.Import(score);
return scoreManager.GetAllUsableScores().First();
}
- private OsuGameBase loadOsu(GameHost host)
+ private async Task loadOsu(GameHost host)
{
var osu = new OsuGameBase();
+
+#pragma warning disable 4014
Task.Run(() => host.Run(osu));
+#pragma warning restore 4014
+
waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
var beatmapFile = TestResources.GetTestBeatmapForImport();
var beatmapManager = osu.Dependencies.Get();
- beatmapManager.Import(beatmapFile);
+ await beatmapManager.Import(beatmapFile);
return osu;
}
diff --git a/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenBeatmap.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs
similarity index 90%
rename from osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenBeatmap.cs
rename to osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs
index c9bdcf928f..dc4ceed59e 100644
--- a/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenBeatmap.cs
+++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs
@@ -7,8 +7,10 @@ using System.Linq;
using System.Threading;
using NUnit.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Framework.Input.States;
using osu.Framework.Platform;
@@ -35,7 +37,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Background
{
[TestFixture]
- public class TestSceneBackgroundScreenBeatmap : ManualInputManagerTestScene
+ public class TestSceneUserDimContainer : ManualInputManagerTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
@@ -54,7 +56,7 @@ namespace osu.Game.Tests.Visual.Background
private RulesetStore rulesets;
[BackgroundDependencyLoader]
- private void load(GameHost host)
+ private void load(GameHost host, AudioManager audio)
{
factory = new DatabaseContextFactory(LocalStorage);
factory.ResetDatabase();
@@ -68,10 +70,10 @@ namespace osu.Game.Tests.Visual.Background
usage.Migrate();
Dependencies.Cache(rulesets = new RulesetStore(factory));
- Dependencies.Cache(manager = new BeatmapManager(LocalStorage, factory, rulesets, null, null, host, Beatmap.Default));
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, factory, rulesets, null, audio, host, Beatmap.Default));
Dependencies.Cache(new OsuConfigManager(LocalStorage));
- manager.Import(TestResources.GetTestBeatmapForImport());
+ manager.Import(TestResources.GetTestBeatmapForImport()).Wait();
Beatmap.SetDefault();
}
@@ -136,14 +138,14 @@ namespace osu.Game.Tests.Visual.Background
player.StoryboardEnabled.Value = true;
});
waitForDim();
- AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible());
+ AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible);
AddStep("Storyboard Disabled", () =>
{
player.ReplacesBackground.Value = false;
player.StoryboardEnabled.Value = false;
});
waitForDim();
- AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && player.IsStoryboardInvisible());
+ AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && !player.IsStoryboardVisible);
}
///
@@ -240,14 +242,15 @@ namespace osu.Game.Tests.Visual.Background
{
player.StoryboardEnabled.Value = false;
player.ReplacesBackground.Value = false;
- player.CurrentStoryboardContainer.Add(new OsuSpriteText
+ player.DimmableStoryboard.Add(new OsuSpriteText
{
- Size = new Vector2(250, 50),
+ Size = new Vector2(500, 50),
Alpha = 1,
- Colour = Color4.Tomato,
+ Colour = Color4.White,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = "THIS IS A STORYBOARD",
+ Font = new FontUsage(size: 50)
});
});
@@ -299,7 +302,7 @@ namespace osu.Game.Tests.Visual.Background
public bool IsBackgroundUndimmed() => ((FadeAccessibleBackground)Background).CurrentColour == Color4.White;
- public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * 25);
+ public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR);
public bool IsUserBlurDisabled() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(0);
@@ -332,17 +335,7 @@ namespace osu.Game.Tests.Visual.Background
{
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
- protected override UserDimContainer CreateStoryboardContainer()
- {
- return new TestUserDimContainer(true)
- {
- RelativeSizeAxes = Axes.Both,
- Alpha = 1,
- EnableUserDim = { Value = true }
- };
- }
-
- public UserDimContainer CurrentStoryboardContainer => StoryboardContainer;
+ public new DimmableStoryboard DimmableStoryboard => base.DimmableStoryboard;
// Whether or not the player should be allowed to load.
public bool BlockLoad;
@@ -356,9 +349,7 @@ namespace osu.Game.Tests.Visual.Background
{
}
- public bool IsStoryboardVisible() => ((TestUserDimContainer)CurrentStoryboardContainer).CurrentAlpha == 1;
-
- public bool IsStoryboardInvisible() => ((TestUserDimContainer)CurrentStoryboardContainer).CurrentAlpha <= 1;
+ public bool IsStoryboardVisible => DimmableStoryboard.ContentDisplayed;
[BackgroundDependencyLoader]
private void load(OsuConfigManager config, CancellationToken token)
@@ -391,15 +382,15 @@ namespace osu.Game.Tests.Visual.Background
private class FadeAccessibleBackground : BackgroundScreenBeatmap
{
- protected override UserDimContainer CreateFadeContainer() => fadeContainer = new TestUserDimContainer { RelativeSizeAxes = Axes.Both };
+ protected override DimmableBackground CreateFadeContainer() => dimmable = new TestDimmableBackground { RelativeSizeAxes = Axes.Both };
- public Color4 CurrentColour => fadeContainer.CurrentColour;
+ public Color4 CurrentColour => dimmable.CurrentColour;
- public float CurrentAlpha => fadeContainer.CurrentAlpha;
+ public float CurrentAlpha => dimmable.CurrentAlpha;
public Vector2 CurrentBlur => Background.BlurSigma;
- private TestUserDimContainer fadeContainer;
+ private TestDimmableBackground dimmable;
public FadeAccessibleBackground(WorkingBeatmap beatmap)
: base(beatmap)
@@ -407,15 +398,10 @@ namespace osu.Game.Tests.Visual.Background
}
}
- private class TestUserDimContainer : UserDimContainer
+ private class TestDimmableBackground : BackgroundScreenBeatmap.DimmableBackground
{
- public Color4 CurrentColour => DimContainer.Colour;
- public float CurrentAlpha => DimContainer.Alpha;
-
- public TestUserDimContainer(bool isStoryboard = false)
- : base(isStoryboard)
- {
- }
+ public Color4 CurrentColour => Content.Colour;
+ public float CurrentAlpha => Content.Alpha;
}
}
}
diff --git a/osu.Game.Tests/Visual/Components/TestSceneIdleTracker.cs b/osu.Game.Tests/Visual/Components/TestSceneIdleTracker.cs
index e97983dd8b..55aaeed8bf 100644
--- a/osu.Game.Tests/Visual/Components/TestSceneIdleTracker.cs
+++ b/osu.Game.Tests/Visual/Components/TestSceneIdleTracker.cs
@@ -14,94 +14,132 @@ namespace osu.Game.Tests.Visual.Components
[TestFixture]
public class TestSceneIdleTracker : ManualInputManagerTestScene
{
- private readonly IdleTrackingBox box1;
- private readonly IdleTrackingBox box2;
- private readonly IdleTrackingBox box3;
- private readonly IdleTrackingBox box4;
+ private IdleTrackingBox box1;
+ private IdleTrackingBox box2;
+ private IdleTrackingBox box3;
+ private IdleTrackingBox box4;
- public TestSceneIdleTracker()
+ private IdleTrackingBox[] boxes;
+
+ [SetUp]
+ public void SetUp() => Schedule(() =>
{
- Children = new Drawable[]
+ InputManager.MoveMouseTo(Vector2.Zero);
+
+ Children = boxes = new[]
{
- box1 = new IdleTrackingBox(1000)
+ box1 = new IdleTrackingBox(2000)
{
+ Name = "TopLeft",
RelativeSizeAxes = Axes.Both,
Colour = Color4.Red,
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
},
- box2 = new IdleTrackingBox(2000)
+ box2 = new IdleTrackingBox(4000)
{
+ Name = "TopRight",
RelativeSizeAxes = Axes.Both,
Colour = Color4.Green,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
},
- box3 = new IdleTrackingBox(3000)
+ box3 = new IdleTrackingBox(6000)
{
+ Name = "BottomLeft",
RelativeSizeAxes = Axes.Both,
Colour = Color4.Blue,
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
},
- box4 = new IdleTrackingBox(4000)
+ box4 = new IdleTrackingBox(8000)
{
+ Name = "BottomRight",
RelativeSizeAxes = Axes.Both,
Colour = Color4.Orange,
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
},
};
- }
+ });
[Test]
public void TestNudge()
{
- AddStep("move mouse to top left", () => InputManager.MoveMouseTo(box1.ScreenSpaceDrawQuad.Centre));
+ AddStep("move to top left", () => InputManager.MoveMouseTo(box1));
- AddUntilStep("Wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle);
+ waitForAllIdle();
AddStep("nudge mouse", () => InputManager.MoveMouseTo(box1.ScreenSpaceDrawQuad.Centre + new Vector2(1)));
- AddAssert("check not idle", () => !box1.IsIdle);
- AddAssert("check idle", () => box2.IsIdle);
- AddAssert("check idle", () => box3.IsIdle);
- AddAssert("check idle", () => box4.IsIdle);
+ checkIdleStatus(1, false);
+ checkIdleStatus(2, true);
+ checkIdleStatus(3, true);
+ checkIdleStatus(4, true);
}
[Test]
public void TestMovement()
{
- AddStep("move mouse", () => InputManager.MoveMouseTo(box2.ScreenSpaceDrawQuad.Centre));
+ AddStep("move to top right", () => InputManager.MoveMouseTo(box2));
- AddAssert("check not idle", () => box1.IsIdle);
- AddAssert("check not idle", () => !box2.IsIdle);
- AddAssert("check idle", () => box3.IsIdle);
- AddAssert("check idle", () => box4.IsIdle);
+ checkIdleStatus(1, true);
+ checkIdleStatus(2, false);
+ checkIdleStatus(3, true);
+ checkIdleStatus(4, true);
- AddStep("move mouse", () => InputManager.MoveMouseTo(box3.ScreenSpaceDrawQuad.Centre));
- AddStep("move mouse", () => InputManager.MoveMouseTo(box4.ScreenSpaceDrawQuad.Centre));
+ AddStep("move to bottom left", () => InputManager.MoveMouseTo(box3));
+ AddStep("move to bottom right", () => InputManager.MoveMouseTo(box4));
- AddAssert("check not idle", () => box1.IsIdle);
- AddAssert("check not idle", () => !box2.IsIdle);
- AddAssert("check idle", () => !box3.IsIdle);
- AddAssert("check idle", () => !box4.IsIdle);
+ checkIdleStatus(1, true);
+ checkIdleStatus(2, false);
+ checkIdleStatus(3, false);
+ checkIdleStatus(4, false);
- AddUntilStep("Wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle);
+ waitForAllIdle();
}
[Test]
public void TestTimings()
{
- AddStep("move mouse", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.Centre));
+ AddStep("move to centre", () => InputManager.MoveMouseTo(Content));
+
+ checkIdleStatus(1, false);
+ checkIdleStatus(2, false);
+ checkIdleStatus(3, false);
+ checkIdleStatus(4, false);
- AddAssert("check not idle", () => !box1.IsIdle && !box2.IsIdle && !box3.IsIdle && !box4.IsIdle);
AddUntilStep("Wait for idle", () => box1.IsIdle);
- AddAssert("check not idle", () => !box2.IsIdle && !box3.IsIdle && !box4.IsIdle);
+
+ checkIdleStatus(1, true);
+ checkIdleStatus(2, false);
+ checkIdleStatus(3, false);
+ checkIdleStatus(4, false);
+
AddUntilStep("Wait for idle", () => box2.IsIdle);
- AddAssert("check not idle", () => !box3.IsIdle && !box4.IsIdle);
+
+ checkIdleStatus(1, true);
+ checkIdleStatus(2, true);
+ checkIdleStatus(3, false);
+ checkIdleStatus(4, false);
+
AddUntilStep("Wait for idle", () => box3.IsIdle);
+ checkIdleStatus(1, true);
+ checkIdleStatus(2, true);
+ checkIdleStatus(3, true);
+ checkIdleStatus(4, false);
+
+ waitForAllIdle();
+ }
+
+ private void checkIdleStatus(int box, bool expectedIdle)
+ {
+ AddAssert($"box {box} is {(expectedIdle ? "idle" : "active")}", () => boxes[box - 1].IsIdle == expectedIdle);
+ }
+
+ private void waitForAllIdle()
+ {
AddUntilStep("Wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle);
}
diff --git a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs
index 94412455a0..df6740421b 100644
--- a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs
+++ b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs
@@ -111,16 +111,19 @@ namespace osu.Game.Tests.Visual.Components
private class TestPreviewTrackManager : PreviewTrackManager
{
- protected override TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, TrackManager trackManager) => new TestPreviewTrack(beatmapSetInfo, trackManager);
+ protected override TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TestPreviewTrack(beatmapSetInfo, trackStore);
protected class TestPreviewTrack : TrackManagerPreviewTrack
{
- public TestPreviewTrack(BeatmapSetInfo beatmapSetInfo, TrackManager trackManager)
+ private readonly ITrackStore trackManager;
+
+ public TestPreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackManager)
: base(beatmapSetInfo, trackManager)
{
+ this.trackManager = trackManager;
}
- protected override Track GetTrack() => new TrackVirtual { Length = 100000 };
+ protected override Track GetTrack() => trackManager.GetVirtual(100000);
}
}
}
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneEditorCompose.cs b/osu.Game.Tests/Visual/Editor/TestSceneEditorCompose.cs
index b537cb0beb..608df1965e 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneEditorCompose.cs
+++ b/osu.Game.Tests/Visual/Editor/TestSceneEditorCompose.cs
@@ -7,7 +7,6 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit.Compose;
-using osu.Game.Tests.Beatmaps;
namespace osu.Game.Tests.Visual.Editor
{
@@ -19,7 +18,7 @@ namespace osu.Game.Tests.Visual.Editor
[BackgroundDependencyLoader]
private void load()
{
- Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo, Clock);
+ Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
Child = new ComposeScreen();
}
}
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs b/osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs
index 154c58dd99..a8c2362910 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs
+++ b/osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -30,9 +31,9 @@ namespace osu.Game.Tests.Visual.Editor
};
[BackgroundDependencyLoader]
- private void load()
+ private void load(AudioManager audio)
{
- Beatmap.Value = new WaveformTestBeatmap();
+ Beatmap.Value = new WaveformTestBeatmap(audio);
Children = new Drawable[]
{
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneEditorSeekSnapping.cs b/osu.Game.Tests/Visual/Editor/TestSceneEditorSeekSnapping.cs
index 590fa59107..b997d6aaeb 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneEditorSeekSnapping.cs
+++ b/osu.Game.Tests/Visual/Editor/TestSceneEditorSeekSnapping.cs
@@ -1,4 +1,4 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
@@ -10,7 +10,6 @@ using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Osu.Objects;
-using osu.Game.Tests.Beatmaps;
using osuTK;
using osuTK.Graphics;
@@ -48,7 +47,7 @@ namespace osu.Game.Tests.Visual.Editor
}
};
- Beatmap.Value = new TestWorkingBeatmap(testBeatmap, Clock);
+ Beatmap.Value = CreateWorkingBeatmap(testBeatmap);
Child = new TimingPointVisualiser(testBeatmap, 5000) { Clock = Clock };
}
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneEditorSummaryTimeline.cs b/osu.Game.Tests/Visual/Editor/TestSceneEditorSummaryTimeline.cs
index f20c921ff2..2e04eb50ca 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneEditorSummaryTimeline.cs
+++ b/osu.Game.Tests/Visual/Editor/TestSceneEditorSummaryTimeline.cs
@@ -8,7 +8,6 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit.Components.Timelines.Summary;
-using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual.Editor
@@ -21,7 +20,7 @@ namespace osu.Game.Tests.Visual.Editor
[BackgroundDependencyLoader]
private void load()
{
- Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo, null);
+ Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
Add(new SummaryTimeline
{
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs b/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs
index 47aa059b62..7accbe2fa8 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs
+++ b/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs
@@ -18,7 +18,6 @@ using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit.Compose;
using osu.Game.Screens.Edit.Compose.Components;
-using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual.Editor
@@ -45,7 +44,7 @@ namespace osu.Game.Tests.Visual.Editor
[BackgroundDependencyLoader]
private void load()
{
- Beatmap.Value = new TestWorkingBeatmap(new Beatmap
+ Beatmap.Value = CreateWorkingBeatmap(new Beatmap
{
HitObjects = new List
{
diff --git a/osu.Game.Tests/Visual/Editor/TestScenePlaybackControl.cs b/osu.Game.Tests/Visual/Editor/TestScenePlaybackControl.cs
index 126ab98291..0d4fe4366d 100644
--- a/osu.Game.Tests/Visual/Editor/TestScenePlaybackControl.cs
+++ b/osu.Game.Tests/Visual/Editor/TestScenePlaybackControl.cs
@@ -1,4 +1,4 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
@@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Screens.Edit.Components;
-using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual.Editor
@@ -29,7 +28,7 @@ namespace osu.Game.Tests.Visual.Editor
Size = new Vector2(200, 100)
};
- Beatmap.Value = new TestWorkingBeatmap(new Beatmap(), Clock);
+ Beatmap.Value = CreateWorkingBeatmap(new Beatmap());
Child = playback;
}
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneWaveform.cs b/osu.Game.Tests/Visual/Editor/TestSceneWaveform.cs
index e93789b1d3..e2762f3d5f 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneWaveform.cs
+++ b/osu.Game.Tests/Visual/Editor/TestSceneWaveform.cs
@@ -3,6 +3,7 @@
using NUnit.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Audio;
@@ -10,6 +11,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites;
+using osu.Game.Rulesets.Osu;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Editor
@@ -20,9 +22,9 @@ namespace osu.Game.Tests.Visual.Editor
private WorkingBeatmap waveformBeatmap;
[BackgroundDependencyLoader]
- private void load()
+ private void load(AudioManager audio)
{
- waveformBeatmap = new WaveformTestBeatmap();
+ waveformBeatmap = new WaveformTestBeatmap(audio);
}
[TestCase(1f)]
@@ -91,7 +93,7 @@ namespace osu.Game.Tests.Visual.Editor
Child = graph = new TestWaveformGraph
{
RelativeSizeAxes = Axes.Both,
- Waveform = new DummyWorkingBeatmap().Waveform,
+ Waveform = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).Waveform,
},
};
});
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs
new file mode 100644
index 0000000000..f4e8a68819
--- /dev/null
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs
@@ -0,0 +1,50 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Rulesets;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Screens.Play;
+
+namespace osu.Game.Tests.Visual.Gameplay
+{
+ public class TestSceneFailAnimation : AllPlayersTestScene
+ {
+ protected override Player CreatePlayer(Ruleset ruleset)
+ {
+ Mods.Value = Array.Empty();
+ return new FailPlayer();
+ }
+
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(AllPlayersTestScene),
+ typeof(TestPlayer),
+ typeof(Player),
+ };
+
+ protected override void AddCheckSteps()
+ {
+ AddUntilStep("wait for fail", () => Player.HasFailed);
+ AddUntilStep("wait for fail overlay", () => ((FailPlayer)Player).FailOverlay.State.Value == Visibility.Visible);
+ }
+
+ private class FailPlayer : TestPlayer
+ {
+ public new FailOverlay FailOverlay => base.FailOverlay;
+
+ public FailPlayer()
+ : base(false, false)
+ {
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ ScoreProcessor.FailConditions += (_, __) => true;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayMenuOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayMenuOverlay.cs
index ba9c583b08..4727140d99 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayMenuOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayMenuOverlay.cs
@@ -97,7 +97,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("Show overlay", () => pauseOverlay.Show());
AddStep("Press select", () => press(GlobalAction.Select));
- AddAssert("Overlay still open", () => pauseOverlay.State == Visibility.Visible);
+ AddAssert("Overlay still open", () => pauseOverlay.State.Value == Visibility.Visible);
AddStep("Hide overlay", () => pauseOverlay.Hide());
}
@@ -237,7 +237,7 @@ namespace osu.Game.Tests.Visual.Gameplay
});
AddAssert("Action was triggered", () => triggered);
- AddAssert("Overlay is closed", () => pauseOverlay.State == Visibility.Hidden);
+ AddAssert("Overlay is closed", () => pauseOverlay.State.Value == Visibility.Hidden);
}
///
@@ -272,7 +272,7 @@ namespace osu.Game.Tests.Visual.Gameplay
return triggered;
});
- AddAssert("Overlay is closed", () => pauseOverlay.State == Visibility.Hidden);
+ AddAssert("Overlay is closed", () => pauseOverlay.State.Value == Visibility.Hidden);
}
private void press(Key key)
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
new file mode 100644
index 0000000000..237fee1594
--- /dev/null
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
@@ -0,0 +1,109 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Audio;
+using osu.Framework.Audio.Track;
+using osu.Framework.MathUtils;
+using osu.Framework.Timing;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets;
+using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Osu;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.UI;
+using osu.Game.Screens.Play;
+using osuTK;
+
+namespace osu.Game.Tests.Visual.Gameplay
+{
+ public class TestSceneGameplayRewinding : PlayerTestScene
+ {
+ private RulesetExposingPlayer player => (RulesetExposingPlayer)Player;
+
+ [Resolved]
+ private AudioManager audioManager { get; set; }
+
+ public TestSceneGameplayRewinding()
+ : base(new OsuRuleset())
+ {
+ }
+
+ private Track track;
+
+ protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap)
+ {
+ var working = new ClockBackedTestWorkingBeatmap(beatmap, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
+ track = working.Track;
+ return working;
+ }
+
+ [Test]
+ public void TestNoJudgementsOnRewind()
+ {
+ AddUntilStep("wait for track to start running", () => track.IsRunning);
+ addSeekStep(3000);
+ AddAssert("all judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged));
+ AddStep("clear results", () => player.AppliedResults.Clear());
+ addSeekStep(0);
+ AddAssert("none judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => !h.Judged));
+ AddAssert("no results triggered", () => player.AppliedResults.Count == 0);
+ }
+
+ private void addSeekStep(double time)
+ {
+ AddStep($"seek to {time}", () => track.Seek(time));
+
+ // Allow a few frames of lenience
+ AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
+ }
+
+ protected override Player CreatePlayer(Ruleset ruleset)
+ {
+ Mods.Value = Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
+ return new RulesetExposingPlayer();
+ }
+
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
+ {
+ var beatmap = new Beatmap
+ {
+ BeatmapInfo = { BaseDifficulty = { ApproachRate = 9 } },
+ };
+
+ for (int i = 0; i < 15; i++)
+ {
+ beatmap.HitObjects.Add(new HitCircle
+ {
+ Position = new Vector2(256, 192),
+ StartTime = 1000 + 30 * i
+ });
+ }
+
+ return beatmap;
+ }
+
+ private class RulesetExposingPlayer : Player
+ {
+ public readonly List AppliedResults = new List();
+
+ public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
+
+ public new DrawableRuleset DrawableRuleset => base.DrawableRuleset;
+
+ public RulesetExposingPlayer()
+ : base(false, false)
+ {
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ ScoreProcessor.NewJudgement += r => AppliedResults.Add(r);
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
index b6f8638f4a..5808a78056 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
@@ -113,7 +113,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public void TestPauseAfterFail()
{
AddUntilStep("wait for fail", () => Player.HasFailed);
- AddAssert("fail overlay shown", () => Player.FailOverlayVisible);
+ AddUntilStep("fail overlay shown", () => Player.FailOverlayVisible);
confirmClockRunning(false);
@@ -137,6 +137,22 @@ namespace osu.Game.Tests.Visual.Gameplay
exitAndConfirm();
}
+ [Test]
+ public void TestExitViaHoldToExit()
+ {
+ AddStep("exit", () =>
+ {
+ InputManager.MoveMouseTo(Player.HUDOverlay.HoldToQuit.First(c => c is HoldToConfirmContainer));
+ InputManager.PressButton(MouseButton.Left);
+ });
+
+ confirmPaused();
+
+ AddStep("release", () => InputManager.ReleaseButton(MouseButton.Left));
+
+ exitAndConfirm();
+ }
+
[Test]
public void TestExitFromPause()
{
@@ -189,7 +205,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddAssert("pause overlay " + (isShown ? "shown" : "hidden"), () => Player.PauseOverlayVisible == isShown);
private void confirmClockRunning(bool isRunning) =>
- AddAssert("clock " + (isRunning ? "running" : "stopped"), () => Player.GameplayClockContainer.GameplayClock.IsRunning == isRunning);
+ AddUntilStep("clock " + (isRunning ? "running" : "stopped"), () => Player.GameplayClockContainer.GameplayClock.IsRunning == isRunning);
protected override bool AllowFail => true;
@@ -203,9 +219,9 @@ namespace osu.Game.Tests.Visual.Gameplay
public new HUDOverlay HUDOverlay => base.HUDOverlay;
- public bool FailOverlayVisible => FailOverlay.State == Visibility.Visible;
+ public bool FailOverlayVisible => FailOverlay.State.Value == Visibility.Visible;
- public bool PauseOverlayVisible => PauseOverlay.State == Visibility.Visible;
+ public bool PauseOverlayVisible => PauseOverlay.State.Value == Visibility.Visible;
public override void OnEntering(IScreen last)
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
index 5c26f733ab..ab519360ac 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
@@ -1,4 +1,4 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
@@ -9,6 +9,7 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
+using osu.Framework.MathUtils;
using osu.Framework.Screens;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
@@ -16,35 +17,45 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens;
using osu.Game.Screens.Play;
-using osu.Game.Tests.Beatmaps;
+using osu.Game.Screens.Play.PlayerSettings;
namespace osu.Game.Tests.Visual.Gameplay
{
public class TestScenePlayerLoader : ManualInputManagerTestScene
{
- private PlayerLoader loader;
+ private TestPlayerLoader loader;
private OsuScreenStack stack;
[SetUp]
public void Setup() => Schedule(() =>
{
InputManager.Child = stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both };
- Beatmap.Value = new TestWorkingBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo), Clock);
+ Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
});
+ [Test]
+ public void TestBlockLoadViaMouseMovement()
+ {
+ AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => new TestPlayer(false, false))));
+ AddUntilStep("wait for current", () => loader.IsCurrentScreen());
+ AddRepeatStep("move mouse", () => InputManager.MoveMouseTo(loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft + (loader.VisualSettings.ScreenSpaceDrawQuad.BottomRight - loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft) * RNG.NextSingle()), 20);
+ AddAssert("loader still active", () => loader.IsCurrentScreen());
+ AddUntilStep("loads after idle", () => !loader.IsCurrentScreen());
+ }
+
[Test]
public void TestLoadContinuation()
{
Player player = null;
SlowLoadPlayer slowPlayer = null;
- AddStep("load dummy beatmap", () => stack.Push(loader = new PlayerLoader(() => player = new TestPlayer(false, false))));
+ AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => player = new TestPlayer(false, false))));
AddUntilStep("wait for current", () => loader.IsCurrentScreen());
AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre));
AddUntilStep("wait for player to be current", () => player.IsCurrentScreen());
AddStep("load slow dummy beatmap", () =>
{
- stack.Push(loader = new PlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false)));
+ stack.Push(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false)));
Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000);
});
@@ -62,7 +73,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("load player", () =>
{
Mods.Value = new[] { gameMod = new TestMod() };
- stack.Push(loader = new PlayerLoader(() => player = new TestPlayer()));
+ stack.Push(loader = new TestPlayerLoader(() => player = new TestPlayer()));
});
AddUntilStep("wait for loader to become current", () => loader.IsCurrentScreen());
@@ -86,6 +97,16 @@ namespace osu.Game.Tests.Visual.Gameplay
AddAssert("player mods applied", () => playerMod2.Applied);
}
+ private class TestPlayerLoader : PlayerLoader
+ {
+ public new VisualSettings VisualSettings => base.VisualSettings;
+
+ public TestPlayerLoader(Func createPlayer)
+ : base(createPlayer)
+ {
+ }
+ }
+
private class TestMod : Mod, IApplicableToScoreProcessor
{
public override string Name => string.Empty;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs
index c75fb2567b..65b56319e8 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs
@@ -3,7 +3,6 @@
using System;
using osu.Framework.Lists;
-using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Screens.Play;
@@ -43,9 +42,9 @@ namespace osu.Game.Tests.Visual.Gameplay
});
}
- protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock clock)
+ protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap)
{
- var working = base.CreateWorkingBeatmap(beatmap, clock);
+ var working = base.CreateWorkingBeatmap(beatmap);
workingWeakReferences.Add(working);
return working;
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
new file mode 100644
index 0000000000..0dfcda122f
--- /dev/null
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs
@@ -0,0 +1,76 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Game.Online;
+using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Rulesets.Osu;
+using osu.Game.Scoring;
+using osu.Game.Screens.Play;
+using osu.Game.Users;
+using osuTK;
+using System;
+using System.Collections.Generic;
+
+namespace osu.Game.Tests.Visual.Gameplay
+{
+ [TestFixture]
+ public class TestSceneReplayDownloadButton : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(ReplayDownloadButton)
+ };
+
+ private TestReplayDownloadButton downloadButton;
+
+ public TestSceneReplayDownloadButton()
+ {
+ createButton(true);
+ AddStep(@"downloading state", () => downloadButton.SetDownloadState(DownloadState.Downloading));
+ AddStep(@"locally available state", () => downloadButton.SetDownloadState(DownloadState.LocallyAvailable));
+ AddStep(@"not downloaded state", () => downloadButton.SetDownloadState(DownloadState.NotDownloaded));
+ createButton(false);
+ }
+
+ private void createButton(bool withReplay)
+ {
+ AddStep(withReplay ? @"create button with replay" : "create button without replay", () =>
+ {
+ Child = downloadButton = new TestReplayDownloadButton(getScoreInfo(withReplay))
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(80, 40),
+ };
+ });
+ }
+
+ private ScoreInfo getScoreInfo(bool replayAvailable)
+ {
+ return new APILegacyScoreInfo
+ {
+ ID = 1,
+ OnlineScoreID = 2553163309,
+ Ruleset = new OsuRuleset().RulesetInfo,
+ Replay = replayAvailable,
+ User = new User
+ {
+ Id = 39828,
+ Username = @"WubWoofWolf",
+ }
+ };
+ }
+
+ private class TestReplayDownloadButton : ReplayDownloadButton
+ {
+ public void SetDownloadState(DownloadState state) => State.Value = state;
+
+ public TestReplayDownloadButton(ScoreInfo score)
+ : base(score)
+ {
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs
index 0519660477..b152c21454 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs
@@ -1,19 +1,88 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.Linq;
using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Timing;
using osu.Game.Screens.Play;
+using osuTK;
+using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay
{
[TestFixture]
- public class TestSceneSkipOverlay : OsuTestScene
+ public class TestSceneSkipOverlay : ManualInputManagerTestScene
{
- protected override void LoadComplete()
- {
- base.LoadComplete();
+ private SkipOverlay skip;
+ private int requestCount;
- Add(new SkipOverlay(Clock.CurrentTime + 5000));
+ [SetUp]
+ public void SetUp() => Schedule(() =>
+ {
+ requestCount = 0;
+ Child = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Clock = new FramedOffsetClock(Clock)
+ {
+ Offset = -Clock.CurrentTime,
+ },
+ Children = new Drawable[]
+ {
+ skip = new SkipOverlay(6000)
+ {
+ RequestSeek = _ => requestCount++
+ }
+ },
+ };
+ });
+
+ [Test]
+ public void TestFadeOnIdle()
+ {
+ AddStep("move mouse", () => InputManager.MoveMouseTo(Vector2.Zero));
+ AddUntilStep("fully visible", () => skip.Children.First().Alpha == 1);
+ AddUntilStep("wait for fade", () => skip.Children.First().Alpha < 1);
+
+ AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
+ AddUntilStep("fully visible", () => skip.Children.First().Alpha == 1);
+ AddUntilStep("wait for fade", () => skip.Children.First().Alpha < 1);
}
+
+ [Test]
+ public void TestClickableAfterFade()
+ {
+ AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
+ AddUntilStep("wait for fade", () => skip.Children.First().Alpha == 0);
+ AddStep("click", () => InputManager.Click(MouseButton.Left));
+ checkRequestCount(1);
+ }
+
+ [Test]
+ public void TestClickOnlyActuatesOnce()
+ {
+ AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
+ AddStep("click", () => InputManager.Click(MouseButton.Left));
+ AddStep("click", () => InputManager.Click(MouseButton.Left));
+ AddStep("click", () => InputManager.Click(MouseButton.Left));
+ AddStep("click", () => InputManager.Click(MouseButton.Left));
+ checkRequestCount(1);
+ }
+
+ [Test]
+ public void TestDoesntFadeOnMouseDown()
+ {
+ AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
+ AddStep("button down", () => InputManager.PressButton(MouseButton.Left));
+ AddUntilStep("wait for overlay disapper", () => !skip.IsAlive);
+ AddAssert("ensure button didn't disappear", () => skip.Children.First().Alpha > 0);
+ AddStep("button up", () => InputManager.ReleaseButton(MouseButton.Left));
+ checkRequestCount(0);
+ }
+
+ private void checkRequestCount(int expected) =>
+ AddAssert($"request count is {expected}", () => requestCount == expected);
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs
index 213cdf5e48..ead7a4b7fc 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs
@@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
- State = Visibility.Visible,
+ State = { Value = Visibility.Visible },
});
AddStep("Restart", restart);
diff --git a/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs b/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs
index 0c789d8cb7..f24589ed35 100644
--- a/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs
+++ b/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs
@@ -17,13 +17,13 @@ namespace osu.Game.Tests.Visual.Menus
{
typeof(ToolbarButton),
typeof(ToolbarRulesetSelector),
- typeof(ToolbarRulesetButton),
+ typeof(ToolbarRulesetTabButton),
typeof(ToolbarNotificationButton),
};
public TestSceneToolbar()
{
- var toolbar = new Toolbar { State = Visibility.Visible };
+ var toolbar = new Toolbar { State = { Value = Visibility.Visible } };
ToolbarNotificationButton notificationButton = null;
AddStep("create toolbar", () =>
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs
index 21b97fe73b..8d842fc865 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs
@@ -8,7 +8,6 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
@@ -37,7 +36,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
settings = new TestRoomSettings
{
RelativeSizeAxes = Axes.Both,
- State = Visibility.Visible
+ State = { Value = Visibility.Visible }
};
Child = settings;
@@ -57,7 +56,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("set name", () => Room.Name.Value = "Room name");
AddAssert("button disabled", () => !settings.ApplyButton.Enabled.Value);
- AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = new DummyWorkingBeatmap().BeatmapInfo }));
+ AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = CreateBeatmap(Ruleset.Value).BeatmapInfo }));
AddAssert("button enabled", () => settings.ApplyButton.Enabled.Value);
AddStep("clear name", () => Room.Name.Value = "");
diff --git a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs
index a7e725ec3f..35449f5687 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs
@@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Online
api.Logout();
api.LocalUser.BindValueChanged(user => { userPanelArea.Child = new UserPanel(user.NewValue) { Width = 200 }; }, true);
- AddStep("show", () => accountCreation.State = Visibility.Visible);
+ AddStep("show", () => accountCreation.Show());
AddStep("logout", () => api.Logout());
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapAvailability.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapAvailability.cs
new file mode 100644
index 0000000000..fe94165777
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapAvailability.cs
@@ -0,0 +1,95 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Overlays.BeatmapSet;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ [TestFixture]
+ public class TestSceneBeatmapAvailability : OsuTestScene
+ {
+ private readonly BeatmapAvailability container;
+
+ public TestSceneBeatmapAvailability()
+ {
+ Add(container = new BeatmapAvailability());
+ }
+
+ [Test]
+ public void TestUndownloadableWithLink()
+ {
+ AddStep("set undownloadable beatmapset with link", () => container.BeatmapSet = new BeatmapSetInfo
+ {
+ OnlineInfo = new BeatmapSetOnlineInfo
+ {
+ Availability = new BeatmapSetOnlineAvailability
+ {
+ DownloadDisabled = true,
+ ExternalLink = @"https://osu.ppy.sh",
+ },
+ },
+ });
+
+ visiblityAssert(true);
+ }
+
+ [Test]
+ public void TestUndownloadableNoLink()
+ {
+ AddStep("set undownloadable beatmapset without link", () => container.BeatmapSet = new BeatmapSetInfo
+ {
+ OnlineInfo = new BeatmapSetOnlineInfo
+ {
+ Availability = new BeatmapSetOnlineAvailability
+ {
+ DownloadDisabled = true,
+ },
+ },
+ });
+
+ visiblityAssert(true);
+ }
+
+ [Test]
+ public void TestPartsRemovedWithLink()
+ {
+ AddStep("set parts-removed beatmapset with link", () => container.BeatmapSet = new BeatmapSetInfo
+ {
+ OnlineInfo = new BeatmapSetOnlineInfo
+ {
+ Availability = new BeatmapSetOnlineAvailability
+ {
+ DownloadDisabled = false,
+ ExternalLink = @"https://osu.ppy.sh",
+ },
+ },
+ });
+
+ visiblityAssert(true);
+ }
+
+ [Test]
+ public void TestNormal()
+ {
+ AddStep("set normal beatmapset", () => container.BeatmapSet = new BeatmapSetInfo
+ {
+ OnlineInfo = new BeatmapSetOnlineInfo
+ {
+ Availability = new BeatmapSetOnlineAvailability
+ {
+ DownloadDisabled = false,
+ },
+ },
+ });
+
+ visiblityAssert(false);
+ }
+
+ private void visiblityAssert(bool shown)
+ {
+ AddAssert($"is container {(shown ? "visible" : "hidden")}", () => container.Alpha == (shown ? 1 : 0));
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs
index 5910da7b88..daee419b52 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs
@@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Online
[TestFixture]
public class TestSceneBeatmapSetOverlay : OsuTestScene
{
- private readonly BeatmapSetOverlay overlay;
+ private readonly TestBeatmapSetOverlay overlay;
public override IReadOnlyList RequiredTypes => new[]
{
@@ -32,375 +32,204 @@ namespace osu.Game.Tests.Visual.Online
typeof(BasicStats),
typeof(BeatmapPicker),
typeof(Details),
- typeof(DownloadButton),
+ typeof(HeaderDownloadButton),
typeof(FavouriteButton),
typeof(Header),
typeof(HeaderButton),
typeof(Info),
typeof(PreviewButton),
typeof(SuccessRate),
+ typeof(BeatmapAvailability),
};
+ private RulesetInfo taikoRuleset;
+ private RulesetInfo maniaRuleset;
+
public TestSceneBeatmapSetOverlay()
{
- Add(overlay = new BeatmapSetOverlay());
+ Add(overlay = new TestBeatmapSetOverlay());
}
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
- var mania = rulesets.GetRuleset(3);
- var taiko = rulesets.GetRuleset(1);
+ taikoRuleset = rulesets.GetRuleset(1);
+ maniaRuleset = rulesets.GetRuleset(3);
+ }
+ [Test]
+ public void TestLoading()
+ {
AddStep(@"show loading", () => overlay.ShowBeatmapSet(null));
+ }
+ [Test]
+ public void TestOnline()
+ {
AddStep(@"show online", () => overlay.FetchAndShowBeatmapSet(55));
+ }
+ [Test]
+ public void TestLocalBeatmaps()
+ {
AddStep(@"show first", () =>
{
overlay.ShowBeatmapSet(new BeatmapSetInfo
{
+ OnlineBeatmapSetID = 1235,
Metadata = new BeatmapMetadata
{
- Title = @"Lachryma ",
- Artist = @"Kaneko Chiharu",
- Source = @"SOUND VOLTEX III GRAVITY WARS",
- Tags = @"sdvx grace the 5th kac original song contest konami bemani",
+ Title = @"an awesome beatmap",
+ Artist = @"naru narusegawa",
+ Source = @"hinata sou",
+ Tags = @"test tag tag more tag",
Author = new User
{
- Username = @"Fresh Chicken",
- Id = 3984370,
+ Username = @"BanchoBot",
+ Id = 3,
},
},
OnlineInfo = new BeatmapSetOnlineInfo
{
- Preview = @"https://b.ppy.sh/preview/415886.mp3",
- PlayCount = 681380,
- FavouriteCount = 356,
- Submitted = new DateTime(2016, 2, 10),
- Ranked = new DateTime(2016, 6, 19),
- Status = BeatmapSetOnlineStatus.Ranked,
- BPM = 236,
+ Preview = @"https://b.ppy.sh/preview/12345.mp3",
+ PlayCount = 123,
+ FavouriteCount = 456,
+ Submitted = DateTime.Now,
+ Ranked = DateTime.Now,
+ BPM = 111,
HasVideo = true,
- Covers = new BeatmapSetOnlineCovers
- {
- Cover = @"https://assets.ppy.sh/beatmaps/415886/covers/cover.jpg?1465651778",
- },
+ HasStoryboard = true,
+ Covers = new BeatmapSetOnlineCovers(),
},
+ Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() },
Beatmaps = new List
{
new BeatmapInfo
{
- StarDifficulty = 1.36,
- Version = @"BASIC",
- Ruleset = mania,
+ StarDifficulty = 9.99,
+ Version = @"TEST",
+ Length = 456000,
+ Ruleset = maniaRuleset,
BaseDifficulty = new BeatmapDifficulty
{
- CircleSize = 4,
- DrainRate = 6.5f,
- OverallDifficulty = 6.5f,
- ApproachRate = 5,
+ CircleSize = 1,
+ DrainRate = 2.3f,
+ OverallDifficulty = 4.5f,
+ ApproachRate = 6,
},
OnlineInfo = new BeatmapOnlineInfo
{
- Length = 115000,
- CircleCount = 265,
- SliderCount = 71,
- PlayCount = 47906,
- PassCount = 19899,
+ CircleCount = 111,
+ SliderCount = 12,
+ PlayCount = 222,
+ PassCount = 21,
},
Metrics = new BeatmapMetrics
{
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
- },
- },
- new BeatmapInfo
- {
- StarDifficulty = 2.22,
- Version = @"NOVICE",
- Ruleset = mania,
- BaseDifficulty = new BeatmapDifficulty
- {
- CircleSize = 4,
- DrainRate = 7,
- OverallDifficulty = 7,
- ApproachRate = 5,
- },
- OnlineInfo = new BeatmapOnlineInfo
- {
- Length = 118000,
- CircleCount = 592,
- SliderCount = 62,
- PlayCount = 162021,
- PassCount = 72116,
- },
- Metrics = new BeatmapMetrics
- {
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
- },
- },
- new BeatmapInfo
- {
- StarDifficulty = 3.49,
- Version = @"ADVANCED",
- Ruleset = mania,
- BaseDifficulty = new BeatmapDifficulty
- {
- CircleSize = 4,
- DrainRate = 7.5f,
- OverallDifficulty = 7.5f,
- ApproachRate = 5,
- },
- OnlineInfo = new BeatmapOnlineInfo
- {
- Length = 118000,
- CircleCount = 1042,
- SliderCount = 79,
- PlayCount = 225178,
- PassCount = 73001,
- },
- Metrics = new BeatmapMetrics
- {
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
- },
- },
- new BeatmapInfo
- {
- StarDifficulty = 4.24,
- Version = @"EXHAUST",
- Ruleset = mania,
- BaseDifficulty = new BeatmapDifficulty
- {
- CircleSize = 4,
- DrainRate = 8,
- OverallDifficulty = 8,
- ApproachRate = 5,
- },
- OnlineInfo = new BeatmapOnlineInfo
- {
- Length = 118000,
- CircleCount = 1352,
- SliderCount = 69,
- PlayCount = 131545,
- PassCount = 42703,
- },
- Metrics = new BeatmapMetrics
- {
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
- },
- },
- new BeatmapInfo
- {
- StarDifficulty = 5.26,
- Version = @"GRAVITY",
- Ruleset = mania,
- BaseDifficulty = new BeatmapDifficulty
- {
- CircleSize = 4,
- DrainRate = 8.5f,
- OverallDifficulty = 8.5f,
- ApproachRate = 5,
- },
- OnlineInfo = new BeatmapOnlineInfo
- {
- Length = 118000,
- CircleCount = 1730,
- SliderCount = 115,
- PlayCount = 117673,
- PassCount = 24241,
- },
- Metrics = new BeatmapMetrics
- {
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
},
},
});
});
- AddStep(@"show second", () =>
+ downloadAssert(true);
+ }
+
+ [Test]
+ public void TestAvailability()
+ {
+ AddStep(@"show undownloadable", () =>
{
overlay.ShowBeatmapSet(new BeatmapSetInfo
{
+ OnlineBeatmapSetID = 1234,
Metadata = new BeatmapMetadata
{
- Title = @"Soumatou Labyrinth",
- Artist = @"Yunomi with Momobako&miko",
- Tags = @"mmbk.com yuzu__rinrin charlotte",
+ Title = @"undownloadable beatmap",
+ Artist = @"no one",
+ Source = @"some source",
+ Tags = @"another test tag tag more test tags",
Author = new User
{
- Username = @"komasy",
- Id = 1980256,
+ Username = @"BanchoBot",
+ Id = 3,
},
},
OnlineInfo = new BeatmapSetOnlineInfo
{
- Preview = @"https://b.ppy.sh/preview/625493.mp3",
- PlayCount = 22996,
- FavouriteCount = 58,
- Submitted = new DateTime(2016, 6, 11),
- Ranked = new DateTime(2016, 7, 12),
- Status = BeatmapSetOnlineStatus.Pending,
- BPM = 160,
- HasVideo = false,
- Covers = new BeatmapSetOnlineCovers
+ Availability = new BeatmapSetOnlineAvailability
{
- Cover = @"https://assets.ppy.sh/beatmaps/625493/covers/cover.jpg?1499167472",
+ DownloadDisabled = true,
+ ExternalLink = "https://osu.ppy.sh",
},
+ Preview = @"https://b.ppy.sh/preview/1234.mp3",
+ PlayCount = 123,
+ FavouriteCount = 456,
+ Submitted = DateTime.Now,
+ Ranked = DateTime.Now,
+ BPM = 111,
+ HasVideo = true,
+ HasStoryboard = true,
+ Covers = new BeatmapSetOnlineCovers(),
},
+ Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() },
Beatmaps = new List
{
new BeatmapInfo
{
- StarDifficulty = 1.40,
- Version = @"yzrin's Kantan",
- Ruleset = taiko,
+ StarDifficulty = 5.67,
+ Version = @"ANOTHER TEST",
+ Length = 123000,
+ Ruleset = taikoRuleset,
BaseDifficulty = new BeatmapDifficulty
{
- CircleSize = 2,
- DrainRate = 7,
- OverallDifficulty = 3,
- ApproachRate = 10,
+ CircleSize = 9,
+ DrainRate = 8,
+ OverallDifficulty = 7,
+ ApproachRate = 6,
},
OnlineInfo = new BeatmapOnlineInfo
{
- Length = 193000,
- CircleCount = 262,
- SliderCount = 0,
- PlayCount = 3952,
- PassCount = 1373,
+ CircleCount = 123,
+ SliderCount = 45,
+ PlayCount = 567,
+ PassCount = 89,
},
Metrics = new BeatmapMetrics
{
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
- },
- },
- new BeatmapInfo
- {
- StarDifficulty = 2.23,
- Version = @"Futsuu",
- Ruleset = taiko,
- BaseDifficulty = new BeatmapDifficulty
- {
- CircleSize = 2,
- DrainRate = 6,
- OverallDifficulty = 4,
- ApproachRate = 10,
- },
- OnlineInfo = new BeatmapOnlineInfo
- {
- Length = 193000,
- CircleCount = 464,
- SliderCount = 0,
- PlayCount = 4833,
- PassCount = 920,
- },
- Metrics = new BeatmapMetrics
- {
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
- },
- },
- new BeatmapInfo
- {
- StarDifficulty = 3.19,
- Version = @"Muzukashii",
- Ruleset = taiko,
- BaseDifficulty = new BeatmapDifficulty
- {
- CircleSize = 2,
- DrainRate = 6,
- OverallDifficulty = 5,
- ApproachRate = 10,
- },
- OnlineInfo = new BeatmapOnlineInfo
- {
- Length = 193000,
- CircleCount = 712,
- SliderCount = 0,
- PlayCount = 4405,
- PassCount = 854,
- },
- Metrics = new BeatmapMetrics
- {
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
- },
- },
- new BeatmapInfo
- {
- StarDifficulty = 3.97,
- Version = @"Charlotte's Oni",
- Ruleset = taiko,
- BaseDifficulty = new BeatmapDifficulty
- {
- CircleSize = 5,
- DrainRate = 6,
- OverallDifficulty = 5.5f,
- ApproachRate = 10,
- },
- OnlineInfo = new BeatmapOnlineInfo
- {
- Length = 193000,
- CircleCount = 943,
- SliderCount = 0,
- PlayCount = 3950,
- PassCount = 693,
- },
- Metrics = new BeatmapMetrics
- {
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
- },
- },
- new BeatmapInfo
- {
- StarDifficulty = 5.08,
- Version = @"Labyrinth Oni",
- Ruleset = taiko,
- BaseDifficulty = new BeatmapDifficulty
- {
- CircleSize = 5,
- DrainRate = 5,
- OverallDifficulty = 6,
- ApproachRate = 10,
- },
- OnlineInfo = new BeatmapOnlineInfo
- {
- Length = 193000,
- CircleCount = 1068,
- SliderCount = 0,
- PlayCount = 5856,
- PassCount = 1207,
- },
- Metrics = new BeatmapMetrics
- {
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
},
},
});
});
+ downloadAssert(false);
+ }
+
+ [Test]
+ public void TestHide()
+ {
AddStep(@"hide", overlay.Hide);
+ }
+
+ [Test]
+ public void TestShowWithNoReload()
+ {
AddStep(@"show without reload", overlay.Show);
}
+
+ private void downloadAssert(bool shown)
+ {
+ AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.DownloadButtonsVisible == shown);
+ }
+
+ private class TestBeatmapSetOverlay : BeatmapSetOverlay
+ {
+ public bool DownloadButtonsVisible => Header.DownloadButtonsVisible;
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs
new file mode 100644
index 0000000000..2a45e68c0a
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs
@@ -0,0 +1,69 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Framework.MathUtils;
+using osu.Game.Beatmaps;
+using osu.Game.Overlays.BeatmapSet;
+using osu.Game.Screens.Select.Details;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ public class TestSceneBeatmapSetOverlayDetails : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(Details)
+ };
+
+ private RatingsExposingDetails details;
+
+ [SetUp]
+ public void Setup() => Schedule(() =>
+ {
+ Child = details = new RatingsExposingDetails
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre
+ };
+ });
+
+ [Test]
+ public void TestMetrics()
+ {
+ var firstSet = createSet();
+ var secondSet = createSet();
+
+ AddStep("set first set", () => details.BeatmapSet = firstSet);
+ AddAssert("ratings set", () => details.Ratings.Metrics == firstSet.Metrics);
+
+ AddStep("set second set", () => details.BeatmapSet = secondSet);
+ AddAssert("ratings set", () => details.Ratings.Metrics == secondSet.Metrics);
+
+ BeatmapSetInfo createSet() => new BeatmapSetInfo
+ {
+ Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).Select(_ => RNG.Next(10)).ToArray() },
+ Beatmaps = new List
+ {
+ new BeatmapInfo
+ {
+ Metrics = new BeatmapMetrics
+ {
+ Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
+ }
+ }
+ }
+ };
+ }
+
+ private class RatingsExposingDetails : Details
+ {
+ public new UserRatings Ratings => base.Ratings;
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs
new file mode 100644
index 0000000000..05f5c117e4
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs
@@ -0,0 +1,82 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.MathUtils;
+using osu.Game.Beatmaps;
+using osu.Game.Overlays.BeatmapSet;
+using osu.Game.Screens.Select.Details;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ public class TestSceneBeatmapSetOverlaySuccessRate : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(Details)
+ };
+
+ private GraphExposingSuccessRate successRate;
+
+ [SetUp]
+ public void Setup() => Schedule(() =>
+ {
+ Child = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(275, 220),
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Gray,
+ },
+ successRate = new GraphExposingSuccessRate
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(275, 220),
+ Padding = new MarginPadding(20)
+ }
+ }
+ };
+ });
+
+ [Test]
+ public void TestMetrics()
+ {
+ var firstBeatmap = createBeatmap();
+ var secondBeatmap = createBeatmap();
+
+ AddStep("set first set", () => successRate.Beatmap = firstBeatmap);
+ AddAssert("ratings set", () => successRate.Graph.Metrics == firstBeatmap.Metrics);
+
+ AddStep("set second set", () => successRate.Beatmap = secondBeatmap);
+ AddAssert("ratings set", () => successRate.Graph.Metrics == secondBeatmap.Metrics);
+
+ BeatmapInfo createBeatmap() => new BeatmapInfo
+ {
+ Metrics = new BeatmapMetrics
+ {
+ Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
+ }
+ };
+ }
+
+ private class GraphExposingSuccessRate : SuccessRate
+ {
+ public new FailRetryGraph Graph => base.Graph;
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
index d1a7730bee..cf8bac7642 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
@@ -24,6 +24,7 @@ namespace osu.Game.Tests.Visual.Online
typeof(ChangelogListing),
typeof(ChangelogSingleBuild),
typeof(ChangelogBuild),
+ typeof(Comments),
};
protected override void LoadComplete()
@@ -42,7 +43,7 @@ namespace osu.Game.Tests.Visual.Online
{
Version = "2018.712.0",
DisplayVersion = "2018.712.0",
- UpdateStream = new APIUpdateStream { Name = "lazer" },
+ UpdateStream = new APIUpdateStream { Name = OsuGameBase.CLIENT_STREAM_NAME },
ChangelogEntries = new List
{
new APIChangelogEntry
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs
index 364c986723..16e47c5df9 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs
@@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual.Online
});
channelTabControl.OnRequestLeave += channel => channelTabControl.RemoveChannel(channel);
- channelTabControl.Current.ValueChanged += channel => currentText.Text = "Currently selected channel: " + channel.NewValue.ToString();
+ channelTabControl.Current.ValueChanged += channel => currentText.Text = "Currently selected channel: " + channel.NewValue;
AddStep("Add random private channel", addRandomPrivateChannel);
AddAssert("There is only one channels", () => channelTabControl.Items.Count() == 2);
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatDisplay.cs
deleted file mode 100644
index 634176e65f..0000000000
--- a/osu.Game.Tests/Visual/Online/TestSceneChatDisplay.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using osu.Framework.Allocation;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Game.Online.Chat;
-using osu.Game.Overlays;
-using osu.Game.Overlays.Chat;
-using osu.Game.Overlays.Chat.Tabs;
-
-namespace osu.Game.Tests.Visual.Online
-{
- [Description("Testing chat api and overlay")]
- public class TestSceneChatDisplay : OsuTestScene
- {
- public override IReadOnlyList RequiredTypes => new[]
- {
- typeof(ChatOverlay),
- typeof(ChatLine),
- typeof(DrawableChannel),
- typeof(ChannelSelectorTabItem),
- typeof(ChannelTabControl),
- typeof(ChannelTabItem),
- typeof(PrivateChannelTabItem),
- typeof(TabCloseButton)
- };
-
- [Cached]
- private readonly ChannelManager channelManager = new ChannelManager();
-
- [BackgroundDependencyLoader]
- private void load()
- {
- Children = new Drawable[]
- {
- channelManager,
- new ChatOverlay { State = Visibility.Visible }
- };
- }
- }
-}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
new file mode 100644
index 0000000000..4d3992ce13
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
@@ -0,0 +1,157 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.UserInterface;
+using osu.Game.Online.Chat;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Chat;
+using osu.Game.Overlays.Chat.Selection;
+using osu.Game.Overlays.Chat.Tabs;
+using osu.Game.Users;
+using osuTK.Input;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ public class TestSceneChatOverlay : ManualInputManagerTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(ChatLine),
+ typeof(DrawableChannel),
+ typeof(ChannelSelectorTabItem),
+ typeof(ChannelTabControl),
+ typeof(ChannelTabItem),
+ typeof(PrivateChannelTabItem),
+ typeof(TabCloseButton)
+ };
+
+ private TestChatOverlay chatOverlay;
+ private ChannelManager channelManager;
+
+ private readonly Channel channel1 = new Channel(new User()) { Name = "test1" };
+ private readonly Channel channel2 = new Channel(new User()) { Name = "test2" };
+
+ [SetUp]
+ public void Setup()
+ {
+ Schedule(() =>
+ {
+ ChannelManagerContainer container;
+
+ Child = container = new ChannelManagerContainer(new List { channel1, channel2 })
+ {
+ RelativeSizeAxes = Axes.Both,
+ };
+
+ chatOverlay = container.ChatOverlay;
+ channelManager = container.ChannelManager;
+ });
+ }
+
+ [Test]
+ public void TestHideOverlay()
+ {
+ AddAssert("Chat overlay is visible", () => chatOverlay.State.Value == Visibility.Visible);
+ AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible);
+
+ AddStep("Close chat overlay", () => chatOverlay.Hide());
+
+ AddAssert("Chat overlay was hidden", () => chatOverlay.State.Value == Visibility.Hidden);
+ AddAssert("Channel selection overlay was hidden", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
+ }
+
+ [Test]
+ public void TestSelectingChannelClosesSelector()
+ {
+ AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible);
+
+ AddStep("Join channel 1", () => channelManager.JoinChannel(channel1));
+ AddStep("Switch to channel 1", () => clickDrawable(chatOverlay.TabMap[channel1]));
+
+ AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1);
+ AddAssert("Channel selector was closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
+ }
+
+ [Test]
+ public void TestCloseChannelWhileSelectorClosed()
+ {
+ AddStep("Join channel 1", () => channelManager.JoinChannel(channel1));
+ AddStep("Join channel 2", () => channelManager.JoinChannel(channel2));
+
+ AddStep("Switch to channel 2", () => clickDrawable(chatOverlay.TabMap[channel2]));
+ AddStep("Close channel 2", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel2]).CloseButton.Child));
+
+ AddAssert("Selector remained closed", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
+ AddAssert("Current channel is channel 1", () => channelManager.CurrentChannel.Value == channel1);
+
+ AddStep("Close channel 1", () => clickDrawable(((TestChannelTabItem)chatOverlay.TabMap[channel1]).CloseButton.Child));
+
+ AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible);
+ }
+
+ private void clickDrawable(Drawable d)
+ {
+ InputManager.MoveMouseTo(d);
+ InputManager.Click(MouseButton.Left);
+ }
+
+ private class ChannelManagerContainer : Container
+ {
+ public TestChatOverlay ChatOverlay { get; private set; }
+
+ [Cached]
+ public ChannelManager ChannelManager { get; } = new ChannelManager();
+
+ private readonly List channels;
+
+ public ChannelManagerContainer(List channels)
+ {
+ this.channels = channels;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ ((BindableList)ChannelManager.AvailableChannels).AddRange(channels);
+
+ Child = ChatOverlay = new TestChatOverlay { RelativeSizeAxes = Axes.Both, };
+ ChatOverlay.Show();
+ }
+ }
+
+ private class TestChatOverlay : ChatOverlay
+ {
+ public Visibility SelectionOverlayState => ChannelSelectionOverlay.State.Value;
+
+ public new ChannelSelectionOverlay ChannelSelectionOverlay => base.ChannelSelectionOverlay;
+
+ protected override ChannelTabControl CreateChannelTabControl() => new TestTabControl();
+
+ public IReadOnlyDictionary> TabMap => ((TestTabControl)ChannelTabControl).TabMap;
+ }
+
+ private class TestTabControl : ChannelTabControl
+ {
+ protected override TabItem CreateTabItem(Channel value) => new TestChannelTabItem(value);
+
+ public new IReadOnlyDictionary> TabMap => base.TabMap;
+ }
+
+ private class TestChannelTabItem : PrivateChannelTabItem
+ {
+ public TestChannelTabItem(Channel channel)
+ : base(channel)
+ {
+ }
+
+ public new ClickableContainer CloseButton => base.CloseButton;
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs
new file mode 100644
index 0000000000..5b0c2d3c67
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs
@@ -0,0 +1,158 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Game.Beatmaps;
+using osu.Game.Online;
+using osu.Game.Overlays.Direct;
+using osu.Game.Rulesets.Osu;
+using osu.Game.Tests.Resources;
+using osuTK;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ public class TestSceneDirectDownloadButton : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(PanelDownloadButton)
+ };
+
+ private TestDownloadButton downloadButton;
+
+ [Resolved]
+ private BeatmapManager beatmaps { get; set; }
+
+ [Test]
+ public void TestDownloadableBeatmap()
+ {
+ createButton(true);
+ assertEnabled(true);
+ }
+
+ [Test]
+ public void TestUndownloadableBeatmap()
+ {
+ createButton(false);
+ assertEnabled(false);
+ }
+
+ [Test]
+ public void TestDownloadState()
+ {
+ AddUntilStep("ensure manager loaded", () => beatmaps != null);
+ ensureSoleilyRemoved();
+ createButtonWithBeatmap(createSoleily());
+ AddAssert("button state not downloaded", () => downloadButton.DownloadState == DownloadState.NotDownloaded);
+ AddStep("import soleily", () => beatmaps.Import(new[] { TestResources.GetTestBeatmapForImport() }));
+ AddUntilStep("wait for beatmap import", () => beatmaps.GetAllUsableBeatmapSets().Any(b => b.OnlineBeatmapSetID == 241526));
+ createButtonWithBeatmap(createSoleily());
+ AddAssert("button state downloaded", () => downloadButton.DownloadState == DownloadState.LocallyAvailable);
+ ensureSoleilyRemoved();
+ AddAssert("button state not downloaded", () => downloadButton.DownloadState == DownloadState.NotDownloaded);
+ }
+
+ private void ensureSoleilyRemoved()
+ {
+ AddStep("remove soleily", () =>
+ {
+ var beatmap = beatmaps.QueryBeatmapSet(b => b.OnlineBeatmapSetID == 241526);
+
+ if (beatmap != null) beatmaps.Delete(beatmap);
+ });
+ }
+
+ private void assertEnabled(bool enabled)
+ {
+ AddAssert($"button {(enabled ? "enabled" : "disabled")}", () => downloadButton.DownloadEnabled == enabled);
+ }
+
+ private BeatmapSetInfo createSoleily()
+ {
+ return new BeatmapSetInfo
+ {
+ ID = 1,
+ OnlineBeatmapSetID = 241526,
+ OnlineInfo = new BeatmapSetOnlineInfo
+ {
+ Availability = new BeatmapSetOnlineAvailability
+ {
+ DownloadDisabled = false,
+ ExternalLink = string.Empty,
+ },
+ },
+ };
+ }
+
+ private void createButtonWithBeatmap(BeatmapSetInfo beatmap)
+ {
+ AddStep("create button", () =>
+ {
+ Child = downloadButton = new TestDownloadButton(beatmap)
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(75, 50),
+ };
+ });
+ }
+
+ private void createButton(bool downloadable)
+ {
+ AddStep("create button", () =>
+ {
+ Child = downloadButton = new TestDownloadButton(downloadable ? getDownloadableBeatmapSet() : getUndownloadableBeatmapSet())
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(75, 50),
+ };
+ });
+ }
+
+ private BeatmapSetInfo getDownloadableBeatmapSet()
+ {
+ var normal = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo;
+ normal.OnlineInfo.HasVideo = true;
+ normal.OnlineInfo.HasStoryboard = true;
+
+ return normal;
+ }
+
+ private BeatmapSetInfo getUndownloadableBeatmapSet()
+ {
+ var beatmap = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo;
+ beatmap.Metadata.Artist = "test";
+ beatmap.Metadata.Title = "undownloadable";
+ beatmap.Metadata.AuthorString = "test";
+
+ beatmap.OnlineInfo.HasVideo = true;
+ beatmap.OnlineInfo.HasStoryboard = true;
+
+ beatmap.OnlineInfo.Availability = new BeatmapSetOnlineAvailability
+ {
+ DownloadDisabled = true,
+ ExternalLink = "http://osu.ppy.sh",
+ };
+
+ return beatmap;
+ }
+
+ private class TestDownloadButton : PanelDownloadButton
+ {
+ public new bool DownloadEnabled => base.DownloadEnabled;
+
+ public DownloadState DownloadState => State.Value;
+
+ public TestDownloadButton(BeatmapSetInfo beatmapSet, bool noVideo = false)
+ : base(beatmapSet, noVideo)
+ {
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectOverlay.cs
index efc12c5fdd..75c2a2a6a1 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneDirectOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneDirectOverlay.cs
@@ -3,10 +3,8 @@
using System.Collections.Generic;
using NUnit.Framework;
-using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Overlays;
-using osu.Game.Rulesets;
namespace osu.Game.Tests.Visual.Online
{
@@ -14,7 +12,6 @@ namespace osu.Game.Tests.Visual.Online
public class TestSceneDirectOverlay : OsuTestScene
{
private DirectOverlay direct;
- private RulesetStore rulesets;
protected override void LoadComplete()
{
@@ -25,18 +22,11 @@ namespace osu.Game.Tests.Visual.Online
AddStep(@"toggle", direct.ToggleVisibility);
AddStep(@"result counts", () => direct.ResultAmounts = new DirectOverlay.ResultCounts(1, 4, 13));
- }
-
- [BackgroundDependencyLoader]
- private void load(RulesetStore rulesets)
- {
- this.rulesets = rulesets;
+ AddStep(@"trigger disabled", () => Ruleset.Disabled = !Ruleset.Disabled);
}
private void newBeatmaps()
{
- var ruleset = rulesets.GetRuleset(0);
-
direct.BeatmapSets = new[]
{
new BeatmapSetInfo
@@ -65,7 +55,7 @@ namespace osu.Game.Tests.Visual.Online
{
new BeatmapInfo
{
- Ruleset = ruleset,
+ Ruleset = Ruleset.Value,
StarDifficulty = 5.35f,
Metadata = new BeatmapMetadata(),
},
@@ -97,7 +87,7 @@ namespace osu.Game.Tests.Visual.Online
{
new BeatmapInfo
{
- Ruleset = ruleset,
+ Ruleset = Ruleset.Value,
StarDifficulty = 5.81f,
Metadata = new BeatmapMetadata(),
},
@@ -129,23 +119,23 @@ namespace osu.Game.Tests.Visual.Online
{
new BeatmapInfo
{
- Ruleset = ruleset,
+ Ruleset = Ruleset.Value,
StarDifficulty = 0.9f,
Metadata = new BeatmapMetadata(),
},
new BeatmapInfo
{
- Ruleset = ruleset,
+ Ruleset = Ruleset.Value,
StarDifficulty = 1.1f,
},
new BeatmapInfo
{
- Ruleset = ruleset,
+ Ruleset = Ruleset.Value,
StarDifficulty = 2.02f,
},
new BeatmapInfo
{
- Ruleset = ruleset,
+ Ruleset = Ruleset.Value,
StarDifficulty = 3.49f,
},
},
@@ -176,43 +166,43 @@ namespace osu.Game.Tests.Visual.Online
{
new BeatmapInfo
{
- Ruleset = ruleset,
+ Ruleset = Ruleset.Value,
StarDifficulty = 1.26f,
Metadata = new BeatmapMetadata(),
},
new BeatmapInfo
{
- Ruleset = ruleset,
+ Ruleset = Ruleset.Value,
StarDifficulty = 2.01f,
},
new BeatmapInfo
{
- Ruleset = ruleset,
+ Ruleset = Ruleset.Value,
StarDifficulty = 2.87f,
},
new BeatmapInfo
{
- Ruleset = ruleset,
+ Ruleset = Ruleset.Value,
StarDifficulty = 3.76f,
},
new BeatmapInfo
{
- Ruleset = ruleset,
+ Ruleset = Ruleset.Value,
StarDifficulty = 3.93f,
},
new BeatmapInfo
{
- Ruleset = ruleset,
+ Ruleset = Ruleset.Value,
StarDifficulty = 4.37f,
},
new BeatmapInfo
{
- Ruleset = ruleset,
+ Ruleset = Ruleset.Value,
StarDifficulty = 5.13f,
},
new BeatmapInfo
{
- Ruleset = ruleset,
+ Ruleset = Ruleset.Value,
StarDifficulty = 5.42f,
},
},
diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
index a3d932a383..53dbaeddda 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
@@ -6,9 +6,11 @@ using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Game.Beatmaps;
using osu.Game.Overlays.Direct;
+using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
-using osu.Game.Tests.Beatmaps;
+using osu.Game.Users;
using osuTK;
namespace osu.Game.Tests.Visual.Online
@@ -22,25 +24,74 @@ namespace osu.Game.Tests.Visual.Online
typeof(IconPill)
};
+ private BeatmapSetInfo getUndownloadableBeatmapSet(RulesetInfo ruleset) => new BeatmapSetInfo
+ {
+ OnlineBeatmapSetID = 123,
+ Metadata = new BeatmapMetadata
+ {
+ Title = "undownloadable beatmap",
+ Artist = "test",
+ Source = "more tests",
+ Author = new User
+ {
+ Username = "BanchoBot",
+ Id = 3,
+ },
+ },
+ OnlineInfo = new BeatmapSetOnlineInfo
+ {
+ Availability = new BeatmapSetOnlineAvailability
+ {
+ DownloadDisabled = true,
+ },
+ Preview = @"https://b.ppy.sh/preview/12345.mp3",
+ PlayCount = 123,
+ FavouriteCount = 456,
+ BPM = 111,
+ HasVideo = true,
+ HasStoryboard = true,
+ Covers = new BeatmapSetOnlineCovers(),
+ },
+ Beatmaps = new List
+ {
+ new BeatmapInfo
+ {
+ Ruleset = ruleset,
+ Version = "Test",
+ StarDifficulty = 6.42,
+ }
+ }
+ };
+
[BackgroundDependencyLoader]
private void load()
{
- var beatmap = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo, null);
- beatmap.BeatmapSetInfo.OnlineInfo.HasVideo = true;
- beatmap.BeatmapSetInfo.OnlineInfo.HasStoryboard = true;
+ var ruleset = new OsuRuleset().RulesetInfo;
- Child = new FillFlowContainer
+ var normal = CreateWorkingBeatmap(ruleset).BeatmapSetInfo;
+ normal.OnlineInfo.HasVideo = true;
+ normal.OnlineInfo.HasStoryboard = true;
+
+ var undownloadable = getUndownloadableBeatmapSet(ruleset);
+
+ Child = new BasicScrollContainer
{
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical,
- Padding = new MarginPadding(20),
- Spacing = new Vector2(0, 20),
- Children = new Drawable[]
+ RelativeSizeAxes = Axes.Both,
+ Child = new FillFlowContainer
{
- new DirectGridPanel(beatmap.BeatmapSetInfo),
- new DirectListPanel(beatmap.BeatmapSetInfo)
- }
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Padding = new MarginPadding(20),
+ Spacing = new Vector2(0, 20),
+ Children = new Drawable[]
+ {
+ new DirectGridPanel(normal),
+ new DirectListPanel(normal),
+ new DirectGridPanel(undownloadable),
+ new DirectListPanel(undownloadable),
+ },
+ },
};
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneFullscreenOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneFullscreenOverlay.cs
index 6dc3428bff..fe8437be17 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneFullscreenOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneFullscreenOverlay.cs
@@ -18,8 +18,24 @@ namespace osu.Game.Tests.Visual.Online
{
base.LoadComplete();
+ int fireCount = 0;
+
Add(overlay = new TestFullscreenOverlay());
- AddStep(@"toggle", overlay.ToggleVisibility);
+
+ overlay.State.ValueChanged += _ => fireCount++;
+
+ AddStep(@"show", overlay.Show);
+
+ AddAssert("fire count 1", () => fireCount == 1);
+
+ AddStep(@"show again", overlay.Show);
+
+ // this logic is specific to FullscreenOverlay
+ AddAssert("fire count 2", () => fireCount == 2);
+
+ AddStep(@"hide", overlay.Hide);
+
+ AddAssert("fire count 3", () => fireCount == 3);
}
private class TestFullscreenOverlay : FullscreenOverlay
diff --git a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs
index f309112f0d..838347800f 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs
@@ -5,9 +5,9 @@ using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
using osu.Game.Overlays.Profile.Sections;
using osu.Game.Overlays.Profile.Sections.Historical;
using osu.Game.Users;
@@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual.Online
Colour = OsuColour.Gray(0.2f)
});
- Add(new ScrollContainer
+ Add(new OsuScrollContainer
{
RelativeSizeAxes = Axes.Both,
Child = section = new HistoricalSection(),
diff --git a/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs
new file mode 100644
index 0000000000..c344cb9598
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs
@@ -0,0 +1,40 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using osu.Game.Overlays.Profile.Header.Components;
+using System;
+using System.Collections.Generic;
+using osu.Game.Rulesets.Catch;
+using osu.Game.Rulesets.Mania;
+using osu.Game.Rulesets.Osu;
+using osu.Game.Rulesets.Taiko;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ public class TestSceneProfileRulesetSelector : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(ProfileRulesetSelector),
+ typeof(ProfileRulesetTabItem),
+ };
+
+ public TestSceneProfileRulesetSelector()
+ {
+ ProfileRulesetSelector selector;
+
+ Child = selector = new ProfileRulesetSelector
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ };
+
+ AddStep("set osu! as default", () => selector.SetDefaultRuleset(new OsuRuleset().RulesetInfo));
+ AddStep("set mania as default", () => selector.SetDefaultRuleset(new ManiaRuleset().RulesetInfo));
+ AddStep("set taiko as default", () => selector.SetDefaultRuleset(new TaikoRuleset().RulesetInfo));
+ AddStep("set catch as default", () => selector.SetDefaultRuleset(new CatchRuleset().RulesetInfo));
+ AddStep("select default ruleset", selector.SelectDefaultRuleset);
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
index 6815018be6..b26de1984a 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
@@ -3,18 +3,18 @@
using System;
using System.Collections.Generic;
-using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils;
-using osu.Game.Graphics;
+using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapSet.Scores;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Users;
+using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Online
{
@@ -29,123 +29,149 @@ namespace osu.Game.Tests.Visual.Online
typeof(ScoreTableRowBackground),
};
- private readonly Box background;
-
public TestSceneScoresContainer()
{
- ScoresContainer scoresContainer;
+ TestScoresContainer scoresContainer;
Child = new Container
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
- AutoSizeAxes = Axes.Y,
- RelativeSizeAxes = Axes.X,
+ RelativeSizeAxes = Axes.Both,
Width = 0.8f,
Children = new Drawable[]
{
- background = new Box { RelativeSizeAxes = Axes.Both },
- scoresContainer = new ScoresContainer(),
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Black,
+ },
+ scoresContainer = new TestScoresContainer(),
}
};
- var scores = new List
+ var allScores = new APILegacyScores
{
- new ScoreInfo
+ Scores = new List
{
- User = new User
+ new APILegacyScoreInfo
{
- Id = 6602580,
- Username = @"waaiiru",
- Country = new Country
+ User = new User
{
- FullName = @"Spain",
- FlagName = @"ES",
+ Id = 6602580,
+ Username = @"waaiiru",
+ Country = new Country
+ {
+ FullName = @"Spain",
+ FlagName = @"ES",
+ },
},
- },
- Mods = new Mod[]
- {
- new OsuModDoubleTime(),
- new OsuModHidden(),
- new OsuModFlashlight(),
- new OsuModHardRock(),
- },
- Rank = ScoreRank.XH,
- PP = 200,
- MaxCombo = 1234,
- TotalScore = 1234567890,
- Accuracy = 1,
- },
- new ScoreInfo
- {
- User = new User
- {
- Id = 4608074,
- Username = @"Skycries",
- Country = new Country
+ Mods = new Mod[]
{
- FullName = @"Brazil",
- FlagName = @"BR",
+ new OsuModDoubleTime(),
+ new OsuModHidden(),
+ new OsuModFlashlight(),
+ new OsuModHardRock(),
},
+ Rank = ScoreRank.XH,
+ PP = 200,
+ MaxCombo = 1234,
+ TotalScore = 1234567890,
+ Accuracy = 1,
},
- Mods = new Mod[]
+ new APILegacyScoreInfo
{
- new OsuModDoubleTime(),
- new OsuModHidden(),
- new OsuModFlashlight(),
- },
- Rank = ScoreRank.S,
- PP = 190,
- MaxCombo = 1234,
- TotalScore = 1234789,
- Accuracy = 0.9997,
- },
- new ScoreInfo
- {
- User = new User
- {
- Id = 1014222,
- Username = @"eLy",
- Country = new Country
+ User = new User
{
- FullName = @"Japan",
- FlagName = @"JP",
+ Id = 4608074,
+ Username = @"Skycries",
+ Country = new Country
+ {
+ FullName = @"Brazil",
+ FlagName = @"BR",
+ },
},
- },
- Mods = new Mod[]
- {
- new OsuModDoubleTime(),
- new OsuModHidden(),
- },
- Rank = ScoreRank.B,
- PP = 180,
- MaxCombo = 1234,
- TotalScore = 12345678,
- Accuracy = 0.9854,
- },
- new ScoreInfo
- {
- User = new User
- {
- Id = 1541390,
- Username = @"Toukai",
- Country = new Country
+ Mods = new Mod[]
{
- FullName = @"Canada",
- FlagName = @"CA",
+ new OsuModDoubleTime(),
+ new OsuModHidden(),
+ new OsuModFlashlight(),
},
+ Rank = ScoreRank.S,
+ PP = 190,
+ MaxCombo = 1234,
+ TotalScore = 1234789,
+ Accuracy = 0.9997,
},
- Mods = new Mod[]
+ new APILegacyScoreInfo
{
- new OsuModDoubleTime(),
+ User = new User
+ {
+ Id = 1014222,
+ Username = @"eLy",
+ Country = new Country
+ {
+ FullName = @"Japan",
+ FlagName = @"JP",
+ },
+ },
+ Mods = new Mod[]
+ {
+ new OsuModDoubleTime(),
+ new OsuModHidden(),
+ },
+ Rank = ScoreRank.B,
+ PP = 180,
+ MaxCombo = 1234,
+ TotalScore = 12345678,
+ Accuracy = 0.9854,
},
- Rank = ScoreRank.C,
- PP = 170,
- MaxCombo = 1234,
- TotalScore = 1234567,
- Accuracy = 0.8765,
- },
- new ScoreInfo
+ new APILegacyScoreInfo
+ {
+ User = new User
+ {
+ Id = 1541390,
+ Username = @"Toukai",
+ Country = new Country
+ {
+ FullName = @"Canada",
+ FlagName = @"CA",
+ },
+ },
+ Mods = new Mod[]
+ {
+ new OsuModDoubleTime(),
+ },
+ Rank = ScoreRank.C,
+ PP = 170,
+ MaxCombo = 1234,
+ TotalScore = 1234567,
+ Accuracy = 0.8765,
+ },
+ new APILegacyScoreInfo
+ {
+ User = new User
+ {
+ Id = 7151382,
+ Username = @"Mayuri Hana",
+ Country = new Country
+ {
+ FullName = @"Thailand",
+ FlagName = @"TH",
+ },
+ },
+ Rank = ScoreRank.D,
+ PP = 160,
+ MaxCombo = 1234,
+ TotalScore = 123456,
+ Accuracy = 0.6543,
+ },
+ }
+ };
+
+ var myBestScore = new APILegacyUserTopScoreInfo
+ {
+ Score = new APILegacyScoreInfo
{
User = new User
{
@@ -157,15 +183,48 @@ namespace osu.Game.Tests.Visual.Online
FlagName = @"TH",
},
},
- Rank = ScoreRank.F,
+ Rank = ScoreRank.D,
PP = 160,
MaxCombo = 1234,
TotalScore = 123456,
Accuracy = 0.6543,
},
+ Position = 1337,
};
- foreach (var s in scores)
+ var oneScore = new APILegacyScores
+ {
+ Scores = new List
+ {
+ new APILegacyScoreInfo
+ {
+ User = new User
+ {
+ Id = 6602580,
+ Username = @"waaiiru",
+ Country = new Country
+ {
+ FullName = @"Spain",
+ FlagName = @"ES",
+ },
+ },
+ Mods = new Mod[]
+ {
+ new OsuModDoubleTime(),
+ new OsuModHidden(),
+ new OsuModFlashlight(),
+ new OsuModHardRock(),
+ },
+ Rank = ScoreRank.XH,
+ PP = 200,
+ MaxCombo = 1234,
+ TotalScore = 1234567890,
+ Accuracy = 1,
+ }
+ }
+ };
+
+ foreach (var s in allScores.Scores)
{
s.Statistics.Add(HitResult.Great, RNG.Next(2000));
s.Statistics.Add(HitResult.Good, RNG.Next(2000));
@@ -173,13 +232,26 @@ namespace osu.Game.Tests.Visual.Online
s.Statistics.Add(HitResult.Miss, RNG.Next(2000));
}
- scoresContainer.Scores = scores;
+ AddStep("Load all scores", () =>
+ {
+ allScores.UserScore = null;
+ scoresContainer.Scores = allScores;
+ });
+ AddStep("Load null scores", () => scoresContainer.Scores = null);
+ AddStep("Load only one score", () => scoresContainer.Scores = oneScore);
+ AddStep("Load scores with my best", () =>
+ {
+ allScores.UserScore = myBestScore;
+ scoresContainer.Scores = allScores;
+ });
}
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
+ private class TestScoresContainer : ScoresContainer
{
- background.Colour = colours.Gray2;
+ public new APILegacyScores Scores
+ {
+ set => base.Scores = value;
+ }
}
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs b/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs
new file mode 100644
index 0000000000..bccb263600
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs
@@ -0,0 +1,55 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Overlays.Profile.Sections;
+using System;
+using System.Collections.Generic;
+using osu.Framework.Graphics;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ public class TestSceneShowMoreButton : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(ShowMoreButton),
+ };
+
+ public TestSceneShowMoreButton()
+ {
+ ShowMoreButton button = null;
+
+ int fireCount = 0;
+
+ Add(button = new ShowMoreButton
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Action = () =>
+ {
+ fireCount++;
+ // ReSharper disable once AccessToModifiedClosure
+ // ReSharper disable once PossibleNullReferenceException
+ Scheduler.AddDelayed(() => button.IsLoading = false, 2000);
+ }
+ });
+
+ AddStep("click button", () => button.Click());
+
+ AddAssert("action fired once", () => fireCount == 1);
+ AddAssert("is in loading state", () => button.IsLoading);
+
+ AddStep("click button", () => button.Click());
+
+ AddAssert("action not fired", () => fireCount == 1);
+ AddAssert("is in loading state", () => button.IsLoading);
+
+ AddUntilStep("wait for loaded", () => !button.IsLoading);
+
+ AddStep("click button", () => button.Click());
+
+ AddAssert("action fired twice", () => fireCount == 2);
+ AddAssert("is in loading state", () => button.IsLoading);
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs
index fca18a9263..54f06d6ad2 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
+using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Users;
@@ -12,10 +13,12 @@ namespace osu.Game.Tests.Visual.Online
[TestFixture]
public class TestSceneUserPanel : OsuTestScene
{
+ private readonly UserPanel peppy;
+
public TestSceneUserPanel()
{
UserPanel flyte;
- UserPanel peppy;
+
Add(new FillFlowContainer
{
Anchor = Anchor.Centre,
@@ -44,13 +47,31 @@ namespace osu.Game.Tests.Visual.Online
});
flyte.Status.Value = new UserStatusOnline();
- peppy.Status.Value = new UserStatusSoloGame();
+ peppy.Status.Value = null;
+ }
- AddStep(@"spectating", () => { flyte.Status.Value = new UserStatusSpectating(); });
- AddStep(@"multiplaying", () => { flyte.Status.Value = new UserStatusMultiplayerGame(); });
- AddStep(@"modding", () => { flyte.Status.Value = new UserStatusModding(); });
- AddStep(@"offline", () => { flyte.Status.Value = new UserStatusOffline(); });
- AddStep(@"null status", () => { flyte.Status.Value = null; });
+ [Test]
+ public void UserStatusesTests()
+ {
+ AddStep("online", () => { peppy.Status.Value = new UserStatusOnline(); });
+ AddStep(@"do not disturb", () => { peppy.Status.Value = new UserStatusDoNotDisturb(); });
+ AddStep(@"offline", () => { peppy.Status.Value = new UserStatusOffline(); });
+ AddStep(@"null status", () => { peppy.Status.Value = null; });
+ }
+
+ [Test]
+ public void UserActivitiesTests()
+ {
+ Bindable activity = new Bindable();
+
+ peppy.Activity.BindTo(activity);
+
+ AddStep("idle", () => { activity.Value = null; });
+ AddStep("spectating", () => { activity.Value = new UserActivity.Spectating(); });
+ AddStep("solo", () => { activity.Value = new UserActivity.SoloGame(null, null); });
+ AddStep("choosing", () => { activity.Value = new UserActivity.ChoosingBeatmap(); });
+ AddStep("editing", () => { activity.Value = new UserActivity.Editing(null); });
+ AddStep("modding", () => { activity.Value = new UserActivity.Modding(); });
}
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs
index d9230090fc..2285c9b799 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs
@@ -39,13 +39,27 @@ namespace osu.Game.Tests.Visual.Online
header = new ProfileHeader();
Add(header);
- AddStep("Show offline dummy", () => header.User.Value = TestSceneUserProfileOverlay.TEST_USER);
+ AddStep("Show test dummy", () => header.User.Value = TestSceneUserProfileOverlay.TEST_USER);
AddStep("Show null dummy", () => header.User.Value = new User
{
Username = "Null"
});
+ AddStep("Show online dummy", () => header.User.Value = new User
+ {
+ Username = "IAmOnline",
+ LastVisit = DateTimeOffset.Now,
+ IsOnline = true,
+ });
+
+ AddStep("Show offline dummy", () => header.User.Value = new User
+ {
+ Username = "IAmOffline",
+ LastVisit = DateTimeOffset.Now,
+ IsOnline = false,
+ });
+
addOnlineStep("Show ppy", new User
{
Username = @"peppy",
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs
index d60e723102..f022425bf6 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs
@@ -9,6 +9,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Profile.Sections;
@@ -36,7 +37,7 @@ namespace osu.Game.Tests.Visual.Online
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(0.2f)
},
- new ScrollContainer
+ new OsuScrollContainer
{
RelativeSizeAxes = Axes.Both,
Child = new FillFlowContainer
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs b/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs
index 70118b5ebd..9f0a8c769a 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs
@@ -8,6 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
using osu.Game.Overlays.Profile.Sections;
using osu.Game.Overlays.Profile.Sections.Ranks;
using osu.Game.Users;
@@ -33,7 +34,7 @@ namespace osu.Game.Tests.Visual.Online
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(0.2f)
},
- new ScrollContainer
+ new OsuScrollContainer
{
RelativeSizeAxes = Axes.Both,
Child = ranks = new RanksSection(),
diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyConfiguration.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs
similarity index 50%
rename from osu.Game.Tests/Visual/Settings/TestSceneKeyConfiguration.cs
rename to osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs
index d06d82ddb5..426ff988c4 100644
--- a/osu.Game.Tests/Visual/Settings/TestSceneKeyConfiguration.cs
+++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs
@@ -1,17 +1,30 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
+using System.Collections.Generic;
using NUnit.Framework;
using osu.Game.Overlays;
+using osu.Game.Overlays.KeyBinding;
namespace osu.Game.Tests.Visual.Settings
{
[TestFixture]
- public class TestSceneKeyConfiguration : OsuTestScene
+ public class TestSceneKeyBindingPanel : OsuTestScene
{
private readonly KeyBindingPanel panel;
- public TestSceneKeyConfiguration()
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(KeyBindingRow),
+ typeof(GlobalKeyBindingsSection),
+ typeof(KeyBindingRow),
+ typeof(KeyBindingsSubsection),
+ typeof(RulesetBindingsSection),
+ typeof(VariantBindingsSubsection),
+ };
+
+ public TestSceneKeyBindingPanel()
{
Child = panel = new KeyBindingPanel();
}
diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs
similarity index 67%
rename from osu.Game.Tests/Visual/Settings/TestSceneSettings.cs
rename to osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs
index 964754f8d0..668fdf2c20 100644
--- a/osu.Game.Tests/Visual/Settings/TestSceneSettings.cs
+++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs
@@ -1,24 +1,33 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
+using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Game.Overlays;
+using osu.Game.Overlays.Settings;
namespace osu.Game.Tests.Visual.Settings
{
[TestFixture]
- public class TestSceneSettings : OsuTestScene
+ public class TestSceneSettingsPanel : OsuTestScene
{
private readonly SettingsPanel settings;
private readonly DialogOverlay dialogOverlay;
- public TestSceneSettings()
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(SettingsFooter),
+ typeof(SettingsOverlay),
+ };
+
+ public TestSceneSettingsPanel()
{
settings = new SettingsOverlay
{
- State = Visibility.Visible
+ State = { Value = Visibility.Visible }
};
Add(dialogOverlay = new DialogOverlay
{
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs
index cf4362ba28..7b97a27732 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetailArea.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
+using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Screens.Select;
@@ -18,7 +19,8 @@ namespace osu.Game.Tests.Visual.SongSelect
{
public override IReadOnlyList RequiredTypes => new[] { typeof(BeatmapDetails) };
- public TestSceneBeatmapDetailArea()
+ [BackgroundDependencyLoader]
+ private void load(OsuGameBase game)
{
BeatmapDetailArea detailsArea;
Add(detailsArea = new BeatmapDetailArea
@@ -28,8 +30,12 @@ namespace osu.Game.Tests.Visual.SongSelect
Size = new Vector2(550f, 450f),
});
- AddStep("all metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap
+ AddStep("all metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
{
+ BeatmapSetInfo =
+ {
+ Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
+ },
BeatmapInfo =
{
Version = "All Metrics",
@@ -48,16 +54,19 @@ namespace osu.Game.Tests.Visual.SongSelect
StarDifficulty = 5.3f,
Metrics = new BeatmapMetrics
{
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
}
}
);
- AddStep("all except source", () => detailsArea.Beatmap = new DummyWorkingBeatmap
+ AddStep("all except source", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
{
+ BeatmapSetInfo =
+ {
+ Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
+ },
BeatmapInfo =
{
Version = "All Metrics",
@@ -75,15 +84,18 @@ namespace osu.Game.Tests.Visual.SongSelect
StarDifficulty = 5.3f,
Metrics = new BeatmapMetrics
{
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
}
});
- AddStep("ratings", () => detailsArea.Beatmap = new DummyWorkingBeatmap
+ AddStep("ratings", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
{
+ BeatmapSetInfo =
+ {
+ Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
+ },
BeatmapInfo =
{
Version = "Only Ratings",
@@ -99,15 +111,11 @@ namespace osu.Game.Tests.Visual.SongSelect
OverallDifficulty = 6,
ApproachRate = 6,
},
- StarDifficulty = 4.8f,
- Metrics = new BeatmapMetrics
- {
- Ratings = Enumerable.Range(0, 11),
- },
+ StarDifficulty = 4.8f
}
});
- AddStep("fails+retries", () => detailsArea.Beatmap = new DummyWorkingBeatmap
+ AddStep("fails+retries", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
{
BeatmapInfo =
{
@@ -127,13 +135,13 @@ namespace osu.Game.Tests.Visual.SongSelect
StarDifficulty = 2.91f,
Metrics = new BeatmapMetrics
{
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
}
});
- AddStep("null metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap
+ AddStep("null metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
{
BeatmapInfo =
{
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs
index acbbd4e18b..acf037198f 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs
@@ -1,28 +1,38 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System.ComponentModel;
using System.Linq;
+using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.SongSelect
{
- [Description("PlaySongSelect beatmap details")]
+ [System.ComponentModel.Description("PlaySongSelect beatmap details")]
public class TestSceneBeatmapDetails : OsuTestScene
{
- public TestSceneBeatmapDetails()
+ private BeatmapDetails details;
+
+ [SetUp]
+ public void Setup() => Schedule(() =>
{
- BeatmapDetails details;
- Add(details = new BeatmapDetails
+ Child = details = new BeatmapDetails
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(150),
- });
+ };
+ });
+ [Test]
+ public void TestAllMetrics()
+ {
AddStep("all metrics", () => details.Beatmap = new BeatmapInfo
{
+ BeatmapSet = new BeatmapSetInfo
+ {
+ Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
+ },
Version = "All Metrics",
Metadata = new BeatmapMetadata
{
@@ -39,14 +49,21 @@ namespace osu.Game.Tests.Visual.SongSelect
StarDifficulty = 5.3f,
Metrics = new BeatmapMetrics
{
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
});
+ }
+ [Test]
+ public void TestAllMetricsExceptSource()
+ {
AddStep("all except source", () => details.Beatmap = new BeatmapInfo
{
+ BeatmapSet = new BeatmapSetInfo
+ {
+ Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
+ },
Version = "All Metrics",
Metadata = new BeatmapMetadata
{
@@ -62,14 +79,21 @@ namespace osu.Game.Tests.Visual.SongSelect
StarDifficulty = 5.3f,
Metrics = new BeatmapMetrics
{
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
});
+ }
+ [Test]
+ public void TestOnlyRatings()
+ {
AddStep("ratings", () => details.Beatmap = new BeatmapInfo
{
+ BeatmapSet = new BeatmapSetInfo
+ {
+ Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
+ },
Version = "Only Ratings",
Metadata = new BeatmapMetadata
{
@@ -84,12 +108,12 @@ namespace osu.Game.Tests.Visual.SongSelect
ApproachRate = 6,
},
StarDifficulty = 4.8f,
- Metrics = new BeatmapMetrics
- {
- Ratings = Enumerable.Range(0, 11),
- },
});
+ }
+ [Test]
+ public void TestOnlyFailsAndRetries()
+ {
AddStep("fails retries", () => details.Beatmap = new BeatmapInfo
{
Version = "Only Retries and Fails",
@@ -108,11 +132,15 @@ namespace osu.Game.Tests.Visual.SongSelect
StarDifficulty = 2.91f,
Metrics = new BeatmapMetrics
{
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
+ Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
+ Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
},
});
+ }
+ [Test]
+ public void TestNoMetrics()
+ {
AddStep("no metrics", () => details.Beatmap = new BeatmapInfo
{
Version = "No Metrics",
@@ -129,10 +157,22 @@ namespace osu.Game.Tests.Visual.SongSelect
ApproachRate = 6.5f,
},
StarDifficulty = 1.97f,
- Metrics = new BeatmapMetrics(),
});
+ }
+ [Test]
+ public void TestNullBeatmap()
+ {
AddStep("null beatmap", () => details.Beatmap = null);
}
+
+ [Test]
+ public void TestOnlineMetrics()
+ {
+ AddStep("online ratings/retries/fails", () => details.Beatmap = new BeatmapInfo
+ {
+ OnlineBeatmapID = 162,
+ });
+ }
}
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs
index b1ed5c46c2..932e114580 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs
@@ -7,7 +7,6 @@ using JetBrains.Annotations;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets;
@@ -18,7 +17,6 @@ using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Taiko;
using osu.Game.Screens.Select;
-using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual.SongSelect
@@ -49,7 +47,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("show", () =>
{
- infoWedge.State = Visibility.Visible;
+ infoWedge.Show();
infoWedge.Beatmap = Beatmap.Value;
});
@@ -58,11 +56,11 @@ namespace osu.Game.Tests.Visual.SongSelect
AddWaitStep("wait for select", 3);
- AddStep("hide", () => { infoWedge.State = Visibility.Hidden; });
+ AddStep("hide", () => { infoWedge.Hide(); });
AddWaitStep("wait for hide", 3);
- AddStep("show", () => { infoWedge.State = Visibility.Visible; });
+ AddStep("show", () => { infoWedge.Show(); });
foreach (var rulesetInfo in rulesets.AvailableRulesets)
{
@@ -136,7 +134,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep($"select {b?.Metadata.Title ?? "null"} beatmap", () =>
{
infoBefore = infoWedge.Info;
- infoWedge.Beatmap = Beatmap.Value = b == null ? Beatmap.Default : new TestWorkingBeatmap(b);
+ infoWedge.Beatmap = Beatmap.Value = b == null ? Beatmap.Default : CreateWorkingBeatmap(b);
});
AddUntilStep("wait for async load", () => infoWedge.Info != infoBefore);
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs
index 3d75470328..8e358a77db 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneLeaderboard.cs
@@ -4,12 +4,9 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
-using System.Linq;
-using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Online.Leaderboards;
-using osu.Game.Rulesets;
using osu.Game.Scoring;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users;
@@ -27,8 +24,6 @@ namespace osu.Game.Tests.Visual.SongSelect
typeof(RetrievalFailurePlaceholder),
};
- private RulesetStore rulesets;
-
private readonly FailableLeaderboard leaderboard;
public TestSceneLeaderboard()
@@ -47,13 +42,8 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep(@"No supporter", () => leaderboard.SetRetrievalState(PlaceholderState.NotSupporter));
AddStep(@"Not logged in", () => leaderboard.SetRetrievalState(PlaceholderState.NotLoggedIn));
AddStep(@"Unavailable", () => leaderboard.SetRetrievalState(PlaceholderState.Unavailable));
- AddStep(@"Real beatmap", realBeatmap);
- }
-
- [BackgroundDependencyLoader]
- private void load(RulesetStore rulesets)
- {
- this.rulesets = rulesets;
+ foreach (BeatmapSetOnlineStatus status in Enum.GetValues(typeof(BeatmapSetOnlineStatus)))
+ AddStep($"{status} beatmap", () => showBeatmapWithStatus(status));
}
private void newScores()
@@ -188,7 +178,7 @@ namespace osu.Game.Tests.Visual.SongSelect
},
new ScoreInfo
{
- Rank = ScoreRank.F,
+ Rank = ScoreRank.D,
Accuracy = 0.6025,
MaxCombo = 244,
TotalScore = 1707827,
@@ -206,7 +196,7 @@ namespace osu.Game.Tests.Visual.SongSelect
},
new ScoreInfo
{
- Rank = ScoreRank.F,
+ Rank = ScoreRank.D,
Accuracy = 0.5140,
MaxCombo = 244,
TotalScore = 1707827,
@@ -224,7 +214,7 @@ namespace osu.Game.Tests.Visual.SongSelect
},
new ScoreInfo
{
- Rank = ScoreRank.F,
+ Rank = ScoreRank.D,
Accuracy = 0.4222,
MaxCombo = 244,
TotalScore = 1707827,
@@ -245,35 +235,12 @@ namespace osu.Game.Tests.Visual.SongSelect
leaderboard.Scores = scores;
}
- private void realBeatmap()
+ private void showBeatmapWithStatus(BeatmapSetOnlineStatus status)
{
leaderboard.Beatmap = new BeatmapInfo
{
- StarDifficulty = 1.36,
- Version = @"BASIC",
OnlineBeatmapID = 1113057,
- Ruleset = rulesets.GetRuleset(0),
- BaseDifficulty = new BeatmapDifficulty
- {
- CircleSize = 4,
- DrainRate = 6.5f,
- OverallDifficulty = 6.5f,
- ApproachRate = 5,
- },
- OnlineInfo = new BeatmapOnlineInfo
- {
- Length = 115000,
- CircleCount = 265,
- SliderCount = 71,
- PlayCount = 47906,
- PassCount = 19899,
- },
- Metrics = new BeatmapMetrics
- {
- Ratings = Enumerable.Range(0, 11),
- Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6),
- Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
- },
+ Status = status,
};
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
index 7e962dbc06..f3255814f2 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Text;
using NUnit.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.MathUtils;
@@ -17,6 +18,7 @@ using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Taiko;
using osu.Game.Screens.Select;
@@ -79,7 +81,7 @@ namespace osu.Game.Tests.Visual.SongSelect
}
[BackgroundDependencyLoader]
- private void load(GameHost host)
+ private void load(GameHost host, AudioManager audio)
{
factory = new DatabaseContextFactory(LocalStorage);
factory.ResetDatabase();
@@ -93,14 +95,17 @@ namespace osu.Game.Tests.Visual.SongSelect
usage.Migrate();
Dependencies.Cache(rulesets = new RulesetStore(factory));
- Dependencies.Cache(manager = new BeatmapManager(LocalStorage, factory, rulesets, null, null, host, defaultBeatmap = Beatmap.Default));
+ Dependencies.Cache(manager = new BeatmapManager(LocalStorage, factory, rulesets, null, audio, host, defaultBeatmap = Beatmap.Default));
Beatmap.SetDefault();
}
[SetUp]
- public virtual void SetUp() =>
- Schedule(() => { manager?.Delete(manager.GetAllUsableBeatmapSets()); });
+ public virtual void SetUp() => Schedule(() =>
+ {
+ Ruleset.Value = new OsuRuleset().RulesetInfo;
+ manager?.Delete(manager.GetAllUsableBeatmapSets());
+ });
[Test]
public void TestDummy()
@@ -128,6 +133,9 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; });
AddStep(@"Sort by Title", delegate { songSelect.FilterControl.Sort = SortMode.Title; });
AddStep(@"Sort by Author", delegate { songSelect.FilterControl.Sort = SortMode.Author; });
+ AddStep(@"Sort by DateAdded", delegate { songSelect.FilterControl.Sort = SortMode.DateAdded; });
+ AddStep(@"Sort by BPM", delegate { songSelect.FilterControl.Sort = SortMode.BPM; });
+ AddStep(@"Sort by Length", delegate { songSelect.FilterControl.Sort = SortMode.Length; });
AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
}
@@ -137,7 +145,7 @@ namespace osu.Game.Tests.Visual.SongSelect
{
createSongSelect();
changeRuleset(2);
- importForRuleset(0);
+ addRulesetImportStep(0);
AddUntilStep("no selection", () => songSelect.Carousel.SelectedBeatmap == null);
}
@@ -146,8 +154,8 @@ namespace osu.Game.Tests.Visual.SongSelect
{
createSongSelect();
changeRuleset(2);
- importForRuleset(2);
- importForRuleset(1);
+ addRulesetImportStep(2);
+ addRulesetImportStep(1);
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap.RulesetID == 2);
changeRuleset(1);
@@ -184,7 +192,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("empty mods", () => !Mods.Value.Any());
void onModChange(ValueChangedEvent> e) => modChangeIndex = actionIndex++;
- void onRulesetChange(ValueChangedEvent e) => rulesetChangeIndex = actionIndex--;
+ void onRulesetChange(ValueChangedEvent e) => rulesetChangeIndex = actionIndex++;
}
[Test]
@@ -209,7 +217,21 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("start not requested", () => !startRequested);
}
- private void importForRuleset(int id) => AddStep($"import test map for ruleset {id}", () => manager.Import(createTestBeatmapSet(getImportId(), rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())));
+ [Test]
+ public void TestHideSetSelectsCorrectBeatmap()
+ {
+ int? previousID = null;
+ createSongSelect();
+ addRulesetImportStep(0);
+ AddStep("Move to last difficulty", () => songSelect.Carousel.SelectBeatmap(songSelect.Carousel.BeatmapSets.First().Beatmaps.Last()));
+ AddStep("Store current ID", () => previousID = songSelect.Carousel.SelectedBeatmap.ID);
+ AddStep("Hide first beatmap", () => manager.Hide(songSelect.Carousel.SelectedBeatmapSet.Beatmaps.First()));
+ AddAssert("Selected beatmap has not changed", () => songSelect.Carousel.SelectedBeatmap.ID == previousID);
+ }
+
+ private void addRulesetImportStep(int id) => AddStep($"import test map for ruleset {id}", () => importForRuleset(id));
+
+ private void importForRuleset(int id) => manager.Import(createTestBeatmapSet(getImportId(), rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())).Wait();
private static int importId;
private int getImportId() => ++importId;
@@ -231,7 +253,7 @@ namespace osu.Game.Tests.Visual.SongSelect
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray();
for (int i = 0; i < 100; i += 10)
- manager.Import(createTestBeatmapSet(i, usableRulesets));
+ manager.Import(createTestBeatmapSet(i, usableRulesets)).Wait();
});
}
@@ -246,16 +268,21 @@ namespace osu.Game.Tests.Visual.SongSelect
{
int beatmapId = setId * 10 + i;
+ int length = RNG.Next(30000, 200000);
+ double bpm = RNG.NextSingle(80, 200);
+
beatmaps.Add(new BeatmapInfo
{
Ruleset = getRuleset(),
OnlineBeatmapID = beatmapId,
Path = "normal.osu",
- Version = $"{beatmapId}",
+ Version = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
+ Length = length,
+ BPM = bpm,
BaseDifficulty = new BeatmapDifficulty
{
OverallDifficulty = 3.5f,
- }
+ },
});
}
@@ -267,10 +294,11 @@ namespace osu.Game.Tests.Visual.SongSelect
{
// Create random metadata, then we can check if sorting works based on these
Artist = "Some Artist " + RNG.Next(0, 9),
- Title = $"Some Song (set id {setId})",
+ Title = $"Some Song (set id {setId}, max bpm {beatmaps.Max(b => b.BPM):0.#})",
AuthorString = "Some Guy " + RNG.Next(0, 9),
},
- Beatmaps = beatmaps
+ Beatmaps = beatmaps,
+ DateAdded = DateTimeOffset.UtcNow,
};
}
}
diff --git a/osu.Game.Tests/Visual/Tournament/TestSceneDrawings.cs b/osu.Game.Tests/Visual/Tournament/TestSceneDrawings.cs
deleted file mode 100644
index 995819f7ae..0000000000
--- a/osu.Game.Tests/Visual/Tournament/TestSceneDrawings.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System.Collections.Generic;
-using System.ComponentModel;
-using osu.Framework.Allocation;
-using osu.Game.Screens.Tournament;
-using osu.Game.Screens.Tournament.Teams;
-
-namespace osu.Game.Tests.Visual.Tournament
-{
- [Description("for tournament use")]
- public class TestSceneDrawings : ScreenTestScene
- {
- [BackgroundDependencyLoader]
- private void load()
- {
- LoadScreen(new Drawings
- {
- TeamList = new TestTeamList(),
- });
- }
-
- private class TestTeamList : ITeamList
- {
- public IEnumerable Teams { get; } = new[]
- {
- new DrawingsTeam
- {
- FlagName = "GB",
- FullName = "United Kingdom",
- Acronym = "UK"
- },
- new DrawingsTeam
- {
- FlagName = "FR",
- FullName = "France",
- Acronym = "FRA"
- },
- new DrawingsTeam
- {
- FlagName = "CN",
- FullName = "China",
- Acronym = "CHN"
- },
- new DrawingsTeam
- {
- FlagName = "AU",
- FullName = "Australia",
- Acronym = "AUS"
- },
- new DrawingsTeam
- {
- FlagName = "JP",
- FullName = "Japan",
- Acronym = "JPN"
- },
- new DrawingsTeam
- {
- FlagName = "RO",
- FullName = "Romania",
- Acronym = "ROM"
- },
- new DrawingsTeam
- {
- FlagName = "IT",
- FullName = "Italy",
- Acronym = "PIZZA"
- },
- new DrawingsTeam
- {
- FlagName = "VE",
- FullName = "Venezuela",
- Acronym = "VNZ"
- },
- new DrawingsTeam
- {
- FlagName = "US",
- FullName = "United States of America",
- Acronym = "USA"
- },
- };
- }
- }
-}
diff --git a/osu.Game.Tests/Visual/UserInterface/OsuGridTestScene.cs b/osu.Game.Tests/Visual/UserInterface/OsuGridTestScene.cs
new file mode 100644
index 0000000000..096ac951de
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/OsuGridTestScene.cs
@@ -0,0 +1,50 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ ///
+ /// An abstract test case which exposes small cells arranged in a grid.
+ /// Useful for displaying multiple configurations of a tested component at a glance.
+ ///
+ public abstract class OsuGridTestScene : OsuTestScene
+ {
+ private readonly Drawable[,] cells;
+
+ ///
+ /// The amount of rows in the grid.
+ ///
+ protected readonly int Rows;
+
+ ///
+ /// The amount of columns in the grid.
+ ///
+ protected readonly int Cols;
+
+ ///
+ /// Constructs a grid test case with the given dimensions.
+ ///
+ protected OsuGridTestScene(int rows, int cols)
+ {
+ Rows = rows;
+ Cols = cols;
+
+ GridContainer testContainer;
+ Add(testContainer = new GridContainer { RelativeSizeAxes = Axes.Both });
+
+ cells = new Drawable[rows, cols];
+ for (int r = 0; r < rows; r++)
+ for (int c = 0; c < cols; c++)
+ cells[r, c] = new Container { RelativeSizeAxes = Axes.Both };
+
+ testContainer.Content = cells.ToJagged();
+ }
+
+ protected Container Cell(int index) => (Container)cells[index / Cols, index % Cols];
+ protected Container Cell(int row, int col) => (Container)cells[row, col];
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs
new file mode 100644
index 0000000000..38a9af05d8
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs
@@ -0,0 +1,53 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics.UserInterface;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneBackButton : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(TwoLayerButton)
+ };
+
+ public TestSceneBackButton()
+ {
+ BackButton button;
+
+ Child = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(300),
+ Masking = true,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.SlateGray
+ },
+ button = new BackButton
+ {
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ }
+ }
+ };
+
+ button.Action = () => button.Hide();
+
+ AddStep("show button", () => button.Show());
+ AddStep("hide button", () => button.Hide());
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs
index c8cc864089..f0e1c38525 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs
@@ -9,6 +9,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Shapes;
using osu.Game.Screens.Menu;
+using osuTK;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
@@ -23,11 +24,12 @@ namespace osu.Game.Tests.Visual.UserInterface
typeof(Button)
};
- public TestSceneButtonSystem()
- {
- OsuLogo logo;
- ButtonSystem buttons;
+ private OsuLogo logo;
+ private ButtonSystem buttons;
+ [SetUp]
+ public void SetUp() => Schedule(() =>
+ {
Children = new Drawable[]
{
new Box
@@ -36,13 +38,47 @@ namespace osu.Game.Tests.Visual.UserInterface
RelativeSizeAxes = Axes.Both,
},
buttons = new ButtonSystem(),
- logo = new OsuLogo { RelativePositionAxes = Axes.Both }
+ logo = new OsuLogo
+ {
+ RelativePositionAxes = Axes.Both,
+ Position = new Vector2(0.5f)
+ }
};
buttons.SetOsuLogo(logo);
+ });
+ [Test]
+ public void TestAllStates()
+ {
foreach (var s in Enum.GetValues(typeof(ButtonSystemState)).OfType().Skip(1))
AddStep($"State to {s}", () => buttons.State = s);
+
+ AddStep("Enter mode", performEnterMode);
+
+ AddStep("Return to menu", () =>
+ {
+ buttons.State = ButtonSystemState.Play;
+ buttons.FadeIn(MainMenu.FADE_IN_DURATION, Easing.OutQuint);
+ buttons.MoveTo(new Vector2(0), MainMenu.FADE_IN_DURATION, Easing.OutQuint);
+ logo.FadeColour(Color4.White, 100, Easing.OutQuint);
+ logo.FadeIn(100, Easing.OutQuint);
+ });
+ }
+
+ [Test]
+ public void TestSmoothExit()
+ {
+ AddStep("Enter mode", performEnterMode);
+ }
+
+ private void performEnterMode()
+ {
+ buttons.State = ButtonSystemState.EnteringMode;
+ buttons.FadeOut(MainMenu.FADE_OUT_DURATION, Easing.InSine);
+ buttons.MoveTo(new Vector2(-800, 0), MainMenu.FADE_OUT_DURATION, Easing.InSine);
+ logo.FadeOut(300, Easing.InSine)
+ .ScaleTo(0.2f, 300, Easing.InSine);
}
}
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs
index 590ee4e720..23d9112b25 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs
@@ -84,7 +84,6 @@ namespace osu.Game.Tests.Visual.UserInterface
testLocalCursor();
testUserCursorOverride();
testMultipleLocalCursors();
- ReturnUserInput();
}
///
@@ -177,7 +176,7 @@ namespace osu.Game.Tests.Visual.UserInterface
/// Checks if a cursor is visible.
///
/// The cursor to check.
- private bool checkVisible(CursorContainer cursorContainer) => cursorContainer.State == Visibility.Visible;
+ private bool checkVisible(CursorContainer cursorContainer) => cursorContainer.State.Value == Visibility.Visible;
///
/// Checks if a cursor is at the current inputmanager screen position.
@@ -193,7 +192,7 @@ namespace osu.Game.Tests.Visual.UserInterface
public CursorContainer Cursor { get; }
public bool ProvidingUserCursor { get; }
- public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) || SmoothTransition && !ProvidingUserCursor;
+ public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) || (SmoothTransition && !ProvidingUserCursor);
private readonly Box background;
@@ -219,7 +218,7 @@ namespace osu.Game.Tests.Visual.UserInterface
},
Cursor = new TestCursorContainer
{
- State = providesUserCursor ? Visibility.Hidden : Visibility.Visible,
+ State = { Value = providesUserCursor ? Visibility.Hidden : Visibility.Visible },
}
};
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneIconButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneIconButton.cs
index 0c9ce50288..c80b3e6297 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneIconButton.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneIconButton.cs
@@ -26,8 +26,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{
new NamedIconButton("No change", new IconButton()),
new NamedIconButton("Background colours", new ColouredIconButton()),
- new NamedIconButton("Full-width", new IconButton { ButtonSize = new Vector2(200, 30) }),
- new NamedIconButton("Unchanging size", new IconButton(), false),
+ new NamedIconButton("Full-width", new IconButton { Size = new Vector2(200, 30) }),
new NamedIconButton("Icon colours", new IconButton
{
IconColour = Color4.Green,
@@ -48,7 +47,7 @@ namespace osu.Game.Tests.Visual.UserInterface
private class NamedIconButton : Container
{
- public NamedIconButton(string name, IconButton button, bool allowSizeChange = true)
+ public NamedIconButton(string name, IconButton button)
{
AutoSizeAxes = Axes.Y;
Width = 200;
@@ -101,13 +100,7 @@ namespace osu.Game.Tests.Visual.UserInterface
}
};
- if (allowSizeChange)
- iconContainer.AutoSizeAxes = Axes.Both;
- else
- {
- iconContainer.RelativeSizeAxes = Axes.X;
- iconContainer.Height = 30;
- }
+ iconContainer.AutoSizeAxes = Axes.Both;
button.Anchor = Anchor.Centre;
button.Origin = Anchor.Centre;
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingAnimation.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingAnimation.cs
index b9a6d74f19..b0233d35f9 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingAnimation.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingAnimation.cs
@@ -3,13 +3,12 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
-using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
{
- public class TestSceneLoadingAnimation : GridTestScene //todo: this should be an OsuTestScene
+ public class TestSceneLoadingAnimation : OsuGridTestScene
{
public TestSceneLoadingAnimation()
: base(2, 2)
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneMods.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
similarity index 90%
rename from osu.Game.Tests/Visual/UserInterface/TestSceneMods.cs
rename to osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
index 2e36ba39ed..80408ab43b 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneMods.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
@@ -24,11 +24,10 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
{
[Description("mod select and icon display")]
- public class TestSceneMods : OsuTestScene
+ public class TestSceneModSelectOverlay : OsuTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
- typeof(ModSelectOverlay),
typeof(ModDisplay),
typeof(ModSection),
typeof(ModIcon),
@@ -77,7 +76,7 @@ namespace osu.Game.Tests.Visual.UserInterface
public void TestOsuMods()
{
var ruleset = rulesets.AvailableRulesets.First(r => r.ID == 0);
- AddStep("change ruleset", () => { Ruleset.Value = ruleset; });
+ changeRuleset(ruleset);
var instance = ruleset.CreateInstance();
@@ -109,7 +108,7 @@ namespace osu.Game.Tests.Visual.UserInterface
public void TestManiaMods()
{
var ruleset = rulesets.AvailableRulesets.First(r => r.ID == 3);
- AddStep("change ruleset", () => { Ruleset.Value = ruleset; });
+ changeRuleset(ruleset);
testRankedText(ruleset.CreateInstance().GetModsFor(ModType.Conversion).First(m => m is ManiaModRandom));
}
@@ -120,7 +119,7 @@ namespace osu.Game.Tests.Visual.UserInterface
var rulesetOsu = rulesets.AvailableRulesets.First(r => r.ID == 0);
var rulesetMania = rulesets.AvailableRulesets.First(r => r.ID == 3);
- AddStep("change ruleset to null", () => { Ruleset.Value = null; });
+ changeRuleset(null);
var instance = rulesetOsu.CreateInstance();
var easierMods = instance.GetModsFor(ModType.DifficultyReduction);
@@ -128,15 +127,15 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("set mods externally", () => { modDisplay.Current.Value = new[] { noFailMod }; });
- AddStep("change ruleset to osu", () => { Ruleset.Value = rulesetOsu; });
+ changeRuleset(rulesetOsu);
AddAssert("ensure mods still selected", () => modDisplay.Current.Value.Single(m => m is OsuModNoFail) != null);
- AddStep("change ruleset to mania", () => { Ruleset.Value = rulesetMania; });
+ changeRuleset(rulesetMania);
AddAssert("ensure mods not selected", () => !modDisplay.Current.Value.Any(m => m is OsuModNoFail));
- AddStep("change ruleset to osu", () => { Ruleset.Value = rulesetOsu; });
+ changeRuleset(rulesetOsu);
AddAssert("ensure mods not selected", () => !modDisplay.Current.Value.Any());
}
@@ -217,14 +216,11 @@ namespace osu.Game.Tests.Visual.UserInterface
private void testRankedText(Mod mod)
{
- AddWaitStep("wait for fade", 1);
- AddAssert("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0);
+ AddUntilStep("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0);
selectNext(mod);
- AddWaitStep("wait for fade", 1);
- AddAssert("check for unranked", () => modSelect.UnrankedLabel.Alpha != 0);
+ AddUntilStep("check for unranked", () => modSelect.UnrankedLabel.Alpha != 0);
selectPrevious(mod);
- AddWaitStep("wait for fade", 1);
- AddAssert("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0);
+ AddUntilStep("check for ranked", () => modSelect.UnrankedLabel.Alpha == 0);
}
private void selectNext(Mod mod) => AddStep($"left click {mod.Name}", () => modSelect.GetModButton(mod)?.SelectNext(1));
@@ -240,6 +236,15 @@ namespace osu.Game.Tests.Visual.UserInterface
});
}
+ private void changeRuleset(RulesetInfo ruleset)
+ {
+ AddStep($"change ruleset to {ruleset}", () => { Ruleset.Value = ruleset; });
+ waitForLoad();
+ }
+
+ private void waitForLoad() =>
+ AddUntilStep("wait for icons to load", () => modSelect.AllLoaded);
+
private void checkNotSelected(Mod mod)
{
AddAssert($"check {mod.Name} is not selected", () =>
@@ -255,6 +260,8 @@ namespace osu.Game.Tests.Visual.UserInterface
{
public new Bindable> SelectedMods => base.SelectedMods;
+ public bool AllLoaded => ModSectionsContainer.Children.All(c => c.ModIconsLoaded);
+
public ModButton GetModButton(Mod mod)
{
var section = ModSectionsContainer.Children.Single(s => s.ModType == mod.Type);
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneMusicController.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneMusicController.cs
index a62fd6467b..ab2ca47100 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneMusicController.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneMusicController.cs
@@ -3,7 +3,6 @@
using NUnit.Framework;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
using osu.Framework.Timing;
using osu.Game.Overlays;
@@ -23,9 +22,9 @@ namespace osu.Game.Tests.Visual.UserInterface
};
Add(mc);
- AddToggleStep(@"toggle visibility", state => mc.State = state ? Visibility.Visible : Visibility.Hidden);
- AddStep(@"show", () => mc.State = Visibility.Visible);
+ AddStep(@"show", () => mc.Show());
AddToggleStep(@"toggle beatmap lock", state => Beatmap.Disabled = state);
+ AddStep(@"show", () => mc.Hide());
}
}
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs
index 71033fcd2f..d8a4514df1 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs
@@ -18,9 +18,6 @@ namespace osu.Game.Tests.Visual.UserInterface
[TestFixture]
public class TestSceneNotificationOverlay : OsuTestScene
{
- private readonly NotificationOverlay manager;
- private readonly List progressingNotifications = new List();
-
public override IReadOnlyList RequiredTypes => new[]
{
typeof(NotificationSection),
@@ -31,25 +28,33 @@ namespace osu.Game.Tests.Visual.UserInterface
typeof(Notification)
};
- public TestSceneNotificationOverlay()
+ private NotificationOverlay notificationOverlay;
+
+ private readonly List progressingNotifications = new List();
+
+ private SpriteText displayedCount;
+
+ [SetUp]
+ public void SetUp() => Schedule(() =>
{
progressingNotifications.Clear();
- Content.Add(manager = new NotificationOverlay
+ Content.Children = new Drawable[]
{
- Anchor = Anchor.TopRight,
- Origin = Anchor.TopRight
- });
+ notificationOverlay = new NotificationOverlay
+ {
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight
+ },
+ displayedCount = new OsuSpriteText()
+ };
- SpriteText displayedCount = new OsuSpriteText();
-
- Content.Add(displayedCount);
-
- void setState(Visibility state) => AddStep(state.ToString(), () => manager.State = state);
- void checkProgressingCount(int expected) => AddAssert($"progressing count is {expected}", () => progressingNotifications.Count == expected);
-
- manager.UnreadCount.ValueChanged += count => { displayedCount.Text = $"displayed count: {count.NewValue}"; };
+ notificationOverlay.UnreadCount.ValueChanged += count => { displayedCount.Text = $"displayed count: {count.NewValue}"; };
+ });
+ [Test]
+ public void TestBasicFlow()
+ {
setState(Visibility.Visible);
AddStep(@"simple #1", sendHelloNotification);
AddStep(@"simple #2", sendAmazingNotification);
@@ -61,6 +66,7 @@ namespace osu.Game.Tests.Visual.UserInterface
setState(Visibility.Hidden);
AddRepeatStep(@"add many simple", sendManyNotifications, 3);
+
AddWaitStep("wait some", 5);
checkProgressingCount(0);
@@ -69,18 +75,122 @@ namespace osu.Game.Tests.Visual.UserInterface
checkProgressingCount(1);
- AddAssert("Displayed count is 33", () => manager.UnreadCount.Value == 33);
+ checkDisplayedCount(33);
AddWaitStep("wait some", 10);
checkProgressingCount(0);
-
- setState(Visibility.Visible);
-
- //AddStep(@"barrage", () => sendBarrage());
}
- private void sendBarrage(int remaining = 10)
+ [Test]
+ public void TestImportantWhileClosed()
+ {
+ AddStep(@"simple #1", sendHelloNotification);
+
+ AddAssert("Is visible", () => notificationOverlay.State.Value == Visibility.Visible);
+
+ checkDisplayedCount(1);
+
+ AddStep(@"progress #1", sendUploadProgress);
+ AddStep(@"progress #2", sendDownloadProgress);
+
+ checkProgressingCount(2);
+ checkDisplayedCount(3);
+ }
+
+ [Test]
+ public void TestUnimportantWhileClosed()
+ {
+ AddStep(@"background #1", sendBackgroundNotification);
+
+ AddAssert("Is not visible", () => notificationOverlay.State.Value == Visibility.Hidden);
+
+ checkDisplayedCount(1);
+
+ AddStep(@"background progress #1", sendBackgroundUploadProgress);
+
+ AddWaitStep("wait some", 5);
+
+ checkProgressingCount(0);
+
+ checkDisplayedCount(2);
+
+ AddStep(@"simple #1", sendHelloNotification);
+
+ checkDisplayedCount(3);
+ }
+
+ [Test]
+ public void TestSpam()
+ {
+ setState(Visibility.Visible);
+ AddRepeatStep("send barrage", sendBarrage, 10);
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ progressingNotifications.RemoveAll(n => n.State == ProgressNotificationState.Completed);
+
+ if (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3)
+ {
+ var p = progressingNotifications.Find(n => n.State == ProgressNotificationState.Queued);
+
+ if (p != null)
+ p.State = ProgressNotificationState.Active;
+ }
+
+ foreach (var n in progressingNotifications.FindAll(n => n.State == ProgressNotificationState.Active))
+ {
+ if (n.Progress < 1)
+ n.Progress += (float)(Time.Elapsed / 400) * RNG.NextSingle();
+ else
+ n.State = ProgressNotificationState.Completed;
+ }
+ }
+
+ private void checkDisplayedCount(int expected) =>
+ AddAssert($"Displayed count is {expected}", () => notificationOverlay.UnreadCount.Value == expected);
+
+ private void sendDownloadProgress()
+ {
+ var n = new ProgressNotification
+ {
+ Text = @"Downloading Haitai...",
+ CompletionText = "Downloaded Haitai!",
+ };
+ notificationOverlay.Post(n);
+ progressingNotifications.Add(n);
+ }
+
+ private void sendUploadProgress()
+ {
+ var n = new ProgressNotification
+ {
+ Text = @"Uploading to BSS...",
+ CompletionText = "Uploaded to BSS!",
+ };
+ notificationOverlay.Post(n);
+ progressingNotifications.Add(n);
+ }
+
+ private void sendBackgroundUploadProgress()
+ {
+ var n = new BackgroundProgressNotification
+ {
+ Text = @"Uploading to BSS...",
+ CompletionText = "Uploaded to BSS!",
+ };
+ notificationOverlay.Post(n);
+ progressingNotifications.Add(n);
+ }
+
+ private void setState(Visibility state) => AddStep(state.ToString(), () => notificationOverlay.State.Value = state);
+
+ private void checkProgressingCount(int expected) => AddAssert($"progressing count is {expected}", () => progressingNotifications.Count == expected);
+
+ private void sendBarrage()
{
switch (RNG.Next(0, 4))
{
@@ -100,69 +210,37 @@ namespace osu.Game.Tests.Visual.UserInterface
sendDownloadProgress();
break;
}
-
- if (remaining > 0)
- Scheduler.AddDelayed(() => sendBarrage(remaining - 1), 80);
- }
-
- protected override void Update()
- {
- base.Update();
-
- progressingNotifications.RemoveAll(n => n.State == ProgressNotificationState.Completed);
-
- if (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3)
- {
- var p = progressingNotifications.Find(n => n.State == ProgressNotificationState.Queued);
- if (p != null)
- p.State = ProgressNotificationState.Active;
- }
-
- foreach (var n in progressingNotifications.FindAll(n => n.State == ProgressNotificationState.Active))
- {
- if (n.Progress < 1)
- n.Progress += (float)(Time.Elapsed / 400) * RNG.NextSingle();
- else
- n.State = ProgressNotificationState.Completed;
- }
- }
-
- private void sendDownloadProgress()
- {
- var n = new ProgressNotification
- {
- Text = @"Downloading Haitai...",
- CompletionText = "Downloaded Haitai!",
- };
- manager.Post(n);
- progressingNotifications.Add(n);
- }
-
- private void sendUploadProgress()
- {
- var n = new ProgressNotification
- {
- Text = @"Uploading to BSS...",
- CompletionText = "Uploaded to BSS!",
- };
- manager.Post(n);
- progressingNotifications.Add(n);
}
private void sendAmazingNotification()
{
- manager.Post(new SimpleNotification { Text = @"You are amazing" });
+ notificationOverlay.Post(new SimpleNotification { Text = @"You are amazing" });
}
private void sendHelloNotification()
{
- manager.Post(new SimpleNotification { Text = @"Welcome to osu!. Enjoy your stay!" });
+ notificationOverlay.Post(new SimpleNotification { Text = @"Welcome to osu!. Enjoy your stay!" });
+ }
+
+ private void sendBackgroundNotification()
+ {
+ notificationOverlay.Post(new BackgroundNotification { Text = @"Welcome to osu!. Enjoy your stay!" });
}
private void sendManyNotifications()
{
for (int i = 0; i < 10; i++)
- manager.Post(new SimpleNotification { Text = @"Spam incoming!!" });
+ notificationOverlay.Post(new SimpleNotification { Text = @"Spam incoming!!" });
+ }
+
+ private class BackgroundNotification : SimpleNotification
+ {
+ public override bool IsImportant => false;
+ }
+
+ private class BackgroundProgressNotification : ProgressNotification
+ {
+ public override bool IsImportant => false;
}
}
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNumberBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNumberBox.cs
new file mode 100644
index 0000000000..f73450db60
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNumberBox.cs
@@ -0,0 +1,55 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics.UserInterface;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ [TestFixture]
+ public class TestSceneNumberBox : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(OsuNumberBox),
+ };
+
+ private OsuNumberBox numberBox;
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Child = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.X,
+ Padding = new MarginPadding { Horizontal = 250 },
+ Child = numberBox = new OsuNumberBox
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.X,
+ PlaceholderText = "Insert numbers here"
+ }
+ };
+
+ clearInput();
+ AddStep("enter numbers", () => numberBox.Text = "987654321");
+ expectedValue("987654321");
+ clearInput();
+ AddStep("enter text + single number", () => numberBox.Text = "1 hello 2 world 3");
+ expectedValue("123");
+ clearInput();
+ }
+
+ private void clearInput() => AddStep("clear input", () => numberBox.Text = null);
+
+ private void expectedValue(string value) => AddAssert("expect number", () => numberBox.Text == value);
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuAnimatedButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuAnimatedButton.cs
new file mode 100644
index 0000000000..6a41d08f01
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuAnimatedButton.cs
@@ -0,0 +1,72 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osu.Framework.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+using osuTK;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneOsuAnimatedButton : OsuGridTestScene
+ {
+ public TestSceneOsuAnimatedButton()
+ : base(3, 2)
+ {
+ Cell(0).Add(new BaseContainer("relative sized")
+ {
+ RelativeSizeAxes = Axes.Both,
+ });
+
+ Cell(1).Add(new BaseContainer("auto sized")
+ {
+ AutoSizeAxes = Axes.Both
+ });
+
+ Cell(2).Add(new BaseContainer("relative Y auto X")
+ {
+ RelativeSizeAxes = Axes.Y,
+ AutoSizeAxes = Axes.X
+ });
+
+ Cell(3).Add(new BaseContainer("relative X auto Y")
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y
+ });
+
+ Cell(4).Add(new BaseContainer("fixed")
+ {
+ Size = new Vector2(100),
+ });
+
+ Cell(5).Add(new BaseContainer("fixed")
+ {
+ Size = new Vector2(100, 50),
+ });
+
+ AddToggleStep("toggle enabled", toggle =>
+ {
+ for (int i = 0; i < 6; i++)
+ ((BaseContainer)Cell(i).Child).Action = toggle ? () => { } : (Action)null;
+ });
+ }
+
+ public class BaseContainer : OsuAnimatedButton
+ {
+ public BaseContainer(string text)
+ {
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
+
+ Add(new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Text = text
+ });
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuHoverContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuHoverContainer.cs
new file mode 100644
index 0000000000..dbef7d1686
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuHoverContainer.cs
@@ -0,0 +1,194 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Colour;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics.Containers;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ [TestFixture]
+ public class TestSceneOsuHoverContainer : ManualInputManagerTestScene
+ {
+ private OsuHoverTestContainer hoverContainer;
+ private Box colourContainer;
+
+ [SetUp]
+ public void SetUp() => Schedule(() =>
+ {
+ Child = hoverContainer = new OsuHoverTestContainer
+ {
+ Enabled = { Value = true },
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(100),
+ Child = colourContainer = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ };
+
+ doMoveOut();
+ });
+
+ [Description("Checks IsHovered property value on a container when it is hovered/unhovered.")]
+ [TestCase(true, TestName = "Enabled_Check_IsHovered")]
+ [TestCase(false, TestName = "Disabled_Check_IsHovered")]
+ public void TestIsHoveredHasProperValue(bool isEnabled)
+ {
+ setContainerEnabledTo(isEnabled);
+
+ checkNotHovered();
+
+ moveToText();
+ checkHovered();
+
+ moveOut();
+ checkNotHovered();
+
+ moveToText();
+ checkHovered();
+
+ moveOut();
+ checkNotHovered();
+ }
+
+ [Test]
+ [Description("Checks colour fading on an enabled container when it is hovered/unhovered.")]
+ public void TestTransitionWhileEnabled()
+ {
+ enableContainer();
+
+ checkColour(OsuHoverTestContainer.IDLE_COLOUR);
+
+ moveToText();
+ waitUntilColourIs(OsuHoverTestContainer.HOVER_COLOUR);
+
+ moveOut();
+ waitUntilColourIs(OsuHoverTestContainer.IDLE_COLOUR);
+
+ moveToText();
+ waitUntilColourIs(OsuHoverTestContainer.HOVER_COLOUR);
+
+ moveOut();
+ waitUntilColourIs(OsuHoverTestContainer.IDLE_COLOUR);
+ }
+
+ [Test]
+ [Description("Checks colour fading on a disabled container when it is hovered/unhovered.")]
+ public void TestNoTransitionWhileDisabled()
+ {
+ disableContainer();
+
+ checkColour(OsuHoverTestContainer.IDLE_COLOUR);
+
+ moveToText();
+ checkColour(OsuHoverTestContainer.IDLE_COLOUR);
+
+ moveOut();
+ checkColour(OsuHoverTestContainer.IDLE_COLOUR);
+
+ moveToText();
+ checkColour(OsuHoverTestContainer.IDLE_COLOUR);
+
+ moveOut();
+ checkColour(OsuHoverTestContainer.IDLE_COLOUR);
+ }
+
+ [Test]
+ [Description("Checks that when a disabled & hovered container gets enabled, colour fading happens")]
+ public void TestBecomesEnabledTransition()
+ {
+ disableContainer();
+ checkColour(OsuHoverTestContainer.IDLE_COLOUR);
+
+ moveToText();
+ checkColour(OsuHoverTestContainer.IDLE_COLOUR);
+
+ enableContainer();
+ waitUntilColourIs(OsuHoverTestContainer.HOVER_COLOUR);
+ }
+
+ [Test]
+ [Description("Checks that when an enabled & hovered container gets disabled, colour fading happens")]
+ public void TestBecomesDisabledTransition()
+ {
+ enableContainer();
+ checkColour(OsuHoverTestContainer.IDLE_COLOUR);
+
+ moveToText();
+ waitUntilColourIs(OsuHoverTestContainer.HOVER_COLOUR);
+
+ disableContainer();
+ waitUntilColourIs(OsuHoverTestContainer.IDLE_COLOUR);
+ }
+
+ [Test]
+ [Description("Checks that when a hovered container gets enabled and disabled multiple times, colour fading happens")]
+ public void TestDisabledChangesMultipleTimes()
+ {
+ enableContainer();
+ checkColour(OsuHoverTestContainer.IDLE_COLOUR);
+
+ moveToText();
+ waitUntilColourIs(OsuHoverTestContainer.HOVER_COLOUR);
+
+ disableContainer();
+ waitUntilColourIs(OsuHoverTestContainer.IDLE_COLOUR);
+
+ enableContainer();
+ waitUntilColourIs(OsuHoverTestContainer.HOVER_COLOUR);
+
+ disableContainer();
+ waitUntilColourIs(OsuHoverTestContainer.IDLE_COLOUR);
+ }
+
+ private void enableContainer() => setContainerEnabledTo(true);
+
+ private void disableContainer() => setContainerEnabledTo(false);
+
+ private void setContainerEnabledTo(bool newValue)
+ {
+ string word = newValue ? "Enable" : "Disable";
+ AddStep($"{word} container", () => hoverContainer.Enabled.Value = newValue);
+ }
+
+ private void moveToText() => AddStep("Move mouse to text", () => InputManager.MoveMouseTo(hoverContainer));
+
+ private void moveOut() => AddStep("Move out", doMoveOut);
+
+ private void checkHovered() => AddAssert("Check hovered", () => hoverContainer.IsHovered);
+
+ private void checkNotHovered() => AddAssert("Check not hovered", () => !hoverContainer.IsHovered);
+
+ private void checkColour(ColourInfo expectedColour)
+ => AddAssert($"Check colour to be '{expectedColour}'", () => currentColour.Equals(expectedColour));
+
+ private void waitUntilColourIs(ColourInfo expectedColour)
+ => AddUntilStep($"Wait until hover colour is {expectedColour}", () => currentColour.Equals(expectedColour));
+
+ private ColourInfo currentColour => colourContainer.DrawColourInfo.Colour;
+
+ ///
+ /// Moves the cursor to top left corner of the screen
+ ///
+ private void doMoveOut()
+ => InputManager.MoveMouseTo(new Vector2(InputManager.ScreenSpaceDrawQuad.TopLeft.X, InputManager.ScreenSpaceDrawQuad.TopLeft.Y));
+
+ private sealed class OsuHoverTestContainer : OsuHoverContainer
+ {
+ public static readonly Color4 HOVER_COLOUR = Color4.Red;
+ public static readonly Color4 IDLE_COLOUR = Color4.Green;
+
+ public OsuHoverTestContainer()
+ {
+ HoverColour = HOVER_COLOUR;
+ IdleColour = IDLE_COLOUR;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuIcon.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuIcon.cs
index 2c2a28394c..061039b297 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuIcon.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuIcon.cs
@@ -10,6 +10,7 @@ using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
using osuTK;
using osuTK.Graphics;
@@ -29,7 +30,7 @@ namespace osu.Game.Tests.Visual.UserInterface
Colour = Color4.Teal,
RelativeSizeAxes = Axes.Both,
},
- new ScrollContainer
+ new OsuScrollContainer
{
RelativeSizeAxes = Axes.Both,
Child = flow = new FillFlowContainer
diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs
index 24140125e0..9ddd8f4038 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual.UserInterface
var popup = new PopupDialog
{
RelativeSizeAxes = Axes.Both,
- State = Framework.Graphics.Containers.Visibility.Visible,
+ State = { Value = Framework.Graphics.Containers.Visibility.Visible },
Icon = FontAwesome.Solid.AssistiveListeningSystems,
HeaderText = @"This is a test popup",
BodyText = "I can say lots of stuff and even wrap my words!",
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs
index 9c83fdf96c..0cb8683d72 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs
@@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.UserInterface
},
};
- breadcrumbs.Current.ValueChanged += screen => titleText.Text = $"Changed to {screen.NewValue.ToString()}";
+ breadcrumbs.Current.ValueChanged += screen => titleText.Text = $"Changed to {screen.NewValue}";
breadcrumbs.Current.TriggerChange();
waitForCurrent();
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneToolbarRulesetSelector.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneToolbarRulesetSelector.cs
new file mode 100644
index 0000000000..0da256855a
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneToolbarRulesetSelector.cs
@@ -0,0 +1,79 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics.Containers;
+using osu.Game.Overlays.Toolbar;
+using System;
+using System.Collections.Generic;
+using osu.Framework.Graphics;
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.MathUtils;
+using osu.Game.Rulesets;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneToolbarRulesetSelector : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(ToolbarRulesetSelector),
+ typeof(ToolbarRulesetTabButton),
+ };
+
+ [Resolved]
+ private RulesetStore rulesets { get; set; }
+
+ [Test]
+ public void TestDisplay()
+ {
+ ToolbarRulesetSelector selector = null;
+
+ AddStep("create selector", () =>
+ {
+ Child = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ AutoSizeAxes = Axes.X,
+ Height = Toolbar.HEIGHT,
+ Child = selector = new ToolbarRulesetSelector()
+ };
+ });
+
+ AddStep("Select random", () =>
+ {
+ selector.Current.Value = selector.Items.ElementAt(RNG.Next(selector.Items.Count()));
+ });
+ AddStep("Toggle disabled state", () => selector.Current.Disabled = !selector.Current.Disabled);
+ }
+
+ [Test]
+ public void TestNonFirstRulesetInitialState()
+ {
+ TestSelector selector = null;
+
+ AddStep("create selector", () =>
+ {
+ Child = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ AutoSizeAxes = Axes.X,
+ Height = Toolbar.HEIGHT,
+ Child = selector = new TestSelector()
+ };
+
+ selector.Current.Value = rulesets.GetRuleset(2);
+ });
+
+ AddAssert("mode line has moved", () => selector.ModeButtonLine.DrawPosition.X > 0);
+ }
+
+ private class TestSelector : ToolbarRulesetSelector
+ {
+ public new Drawable ModeButtonLine => base.ModeButtonLine;
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneTwoLayerButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneTwoLayerButton.cs
index b9ed1a71cc..849577186d 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneTwoLayerButton.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneTwoLayerButton.cs
@@ -1,17 +1,26 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System.ComponentModel;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
+using osuTK;
+using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
{
- [Description("mostly back button")]
public class TestSceneTwoLayerButton : OsuTestScene
{
public TestSceneTwoLayerButton()
{
- Add(new BackButton());
+ Add(new TwoLayerButton
+ {
+ Position = new Vector2(100),
+ Text = "button",
+ Icon = FontAwesome.Solid.Check,
+ BackgroundColour = Color4.SlateGray,
+ HoverColour = Color4.SlateGray.Darken(0.2f)
+ });
}
}
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs
index 23065629a6..9cdfcb6cc4 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs
@@ -9,6 +9,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
+using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Rulesets;
@@ -32,7 +33,7 @@ namespace osu.Game.Tests.Visual.UserInterface
this.api = api;
this.rulesets = rulesets;
- testBeatmap = ImportBeatmapTest.LoadOszIntoOsu(osu);
+ testBeatmap = ImportBeatmapTest.LoadOszIntoOsu(osu).Result;
}
[Test]
@@ -41,7 +42,7 @@ namespace osu.Game.Tests.Visual.UserInterface
TestUpdateableBeatmapBackgroundSprite background = null;
AddStep("load null beatmap", () => Child = background = new TestUpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both });
- AddUntilStep("wait for load", () => background.ContentLoaded);
+ AddUntilStep("content loaded", () => background.ContentLoaded);
}
[Test]
@@ -92,13 +93,13 @@ namespace osu.Game.Tests.Visual.UserInterface
public void TestUnloadAndReload()
{
var backgrounds = new List();
- ScrollContainer scrollContainer = null;
+ OsuScrollContainer scrollContainer = null;
AddStep("create backgrounds hierarchy", () =>
{
FillFlowContainer backgroundFlow;
- Child = scrollContainer = new ScrollContainer
+ Child = scrollContainer = new OsuScrollContainer
{
Size = new Vector2(500),
Child = backgroundFlow = new FillFlowContainer
diff --git a/osu.Game.Tests/WaveformTestBeatmap.cs b/osu.Game.Tests/WaveformTestBeatmap.cs
index f66b374cd7..3e0df8d45e 100644
--- a/osu.Game.Tests/WaveformTestBeatmap.cs
+++ b/osu.Game.Tests/WaveformTestBeatmap.cs
@@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
+using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
@@ -19,30 +20,34 @@ namespace osu.Game.Tests
{
private readonly ZipArchiveReader reader;
private readonly Stream stream;
+ private readonly ITrackStore trackStore;
- public WaveformTestBeatmap()
- : base(new BeatmapInfo())
+ public WaveformTestBeatmap(AudioManager audioManager)
+ : base(new BeatmapInfo(), audioManager)
{
stream = TestResources.GetTestBeatmapStream();
reader = new ZipArchiveReader(stream);
+ trackStore = audioManager.GetTrackStore(reader);
}
- public override void Dispose()
+ protected override void Dispose(bool isDisposing)
{
- base.Dispose();
+ base.Dispose(isDisposing);
stream?.Dispose();
reader?.Dispose();
+ trackStore?.Dispose();
}
protected override IBeatmap GetBeatmap() => createTestBeatmap();
protected override Texture GetBackground() => null;
- protected override Waveform GetWaveform() => new Waveform(getAudioStream());
+ protected override Waveform GetWaveform() => new Waveform(trackStore.GetStream(firstAudioFile));
- protected override Track GetTrack() => new TrackBass(getAudioStream());
+ protected override Track GetTrack() => trackStore.Get(firstAudioFile);
+
+ private string firstAudioFile => reader.Filenames.First(f => f.EndsWith(".mp3"));
- private Stream getAudioStream() => reader.GetStream(reader.Filenames.First(f => f.EndsWith(".mp3")));
private Stream getBeatmapStream() => reader.GetStream(reader.Filenames.First(f => f.EndsWith(".osu")));
private Beatmap createTestBeatmap()
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index 11d70ee7be..659f5415c3 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -3,7 +3,7 @@
-
+
diff --git a/osu.Game.Tournament.Tests/.vscode/launch.json b/osu.Game.Tournament.Tests/.vscode/launch.json
new file mode 100644
index 0000000000..0204158347
--- /dev/null
+++ b/osu.Game.Tournament.Tests/.vscode/launch.json
@@ -0,0 +1,31 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "VisualTests (Debug)",
+ "type": "coreclr",
+ "request": "launch",
+ "program": "dotnet",
+ "args": [
+ "${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Tournament.Tests.dll"
+ ],
+ "cwd": "${workspaceRoot}",
+ "preLaunchTask": "Build (Debug)",
+ "env": {},
+ "console": "internalConsole"
+ },
+ {
+ "name": "VisualTests (Release)",
+ "type": "coreclr",
+ "request": "launch",
+ "program": "dotnet",
+ "args": [
+ "${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Tournament.Tests.dll"
+ ],
+ "cwd": "${workspaceRoot}",
+ "preLaunchTask": "Build (Release)",
+ "env": {},
+ "console": "internalConsole"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/osu.Game.Tournament.Tests/.vscode/tasks.json b/osu.Game.Tournament.Tests/.vscode/tasks.json
new file mode 100644
index 0000000000..37f2f32874
--- /dev/null
+++ b/osu.Game.Tournament.Tests/.vscode/tasks.json
@@ -0,0 +1,47 @@
+{
+ // See https://go.microsoft.com/fwlink/?LinkId=733558
+ // for the documentation about the tasks.json format
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "Build (Debug)",
+ "type": "shell",
+ "command": "dotnet",
+ "args": [
+ "build",
+ "--no-restore",
+ "osu.Game.Tournament.Tests.csproj",
+ "/p:GenerateFullPaths=true",
+ "/m",
+ "/verbosity:m"
+ ],
+ "group": "build",
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "Build (Release)",
+ "type": "shell",
+ "command": "dotnet",
+ "args": [
+ "build",
+ "--no-restore",
+ "osu.Game.Tournament.Tests.csproj",
+ "/p:Configuration=Release",
+ "/p:GenerateFullPaths=true",
+ "/m",
+ "/verbosity:m"
+ ],
+ "group": "build",
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "Restore",
+ "type": "shell",
+ "command": "dotnet",
+ "args": [
+ "restore"
+ ],
+ "problemMatcher": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentMatch.cs b/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentMatch.cs
new file mode 100644
index 0000000000..f329623703
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentMatch.cs
@@ -0,0 +1,93 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Tests.Visual;
+using osu.Game.Tournament.Components;
+using osu.Game.Tournament.Models;
+using osu.Game.Tournament.Screens.Ladder.Components;
+
+namespace osu.Game.Tournament.Tests.Components
+{
+ public class TestSceneDrawableTournamentMatch : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(TournamentMatch),
+ typeof(DrawableTournamentTeam),
+ };
+
+ public TestSceneDrawableTournamentMatch()
+ {
+ Container level1;
+ Container level2;
+
+ var match1 = new TournamentMatch(
+ new TournamentTeam { FlagName = { Value = "AU" }, FullName = { Value = "Australia" }, },
+ new TournamentTeam { FlagName = { Value = "JP" }, FullName = { Value = "Japan" }, Acronym = { Value = "JPN" } })
+ {
+ Team1Score = { Value = 4 },
+ Team2Score = { Value = 1 },
+ };
+
+ var match2 = new TournamentMatch(
+ new TournamentTeam
+ {
+ FlagName = { Value = "RO" },
+ FullName = { Value = "Romania" },
+ }
+ );
+
+ Child = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Children = new Drawable[]
+ {
+ level1 = new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.X,
+ Direction = FillDirection.Vertical,
+ Children = new[]
+ {
+ new DrawableTournamentMatch(match1),
+ new DrawableTournamentMatch(match2),
+ new DrawableTournamentMatch(new TournamentMatch()),
+ }
+ },
+ level2 = new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.X,
+ Direction = FillDirection.Vertical,
+ Margin = new MarginPadding(20),
+ Children = new[]
+ {
+ new DrawableTournamentMatch(new TournamentMatch()),
+ new DrawableTournamentMatch(new TournamentMatch())
+ }
+ }
+ }
+ };
+
+ level1.Children[0].Match.Progression.Value = level2.Children[0].Match;
+ level1.Children[1].Match.Progression.Value = level2.Children[0].Match;
+
+ AddRepeatStep("change scores", () => match1.Team2Score.Value++, 4);
+ AddStep("add new team", () => match2.Team2.Value = new TournamentTeam { FlagName = { Value = "PT" }, FullName = { Value = "Portugal" } });
+ AddStep("Add progression", () => level1.Children[2].Match.Progression.Value = level2.Children[1].Match);
+
+ AddStep("start match", () => match2.StartMatch());
+
+ AddRepeatStep("change scores", () => match2.Team1Score.Value++, 10);
+
+ AddStep("start submatch", () => level2.Children[0].Match.StartMatch());
+
+ AddRepeatStep("change scores", () => level2.Children[0].Match.Team1Score.Value++, 5);
+
+ AddRepeatStep("change scores", () => level2.Children[0].Match.Team2Score.Value++, 4);
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs
new file mode 100644
index 0000000000..72d9eb0e07
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs
@@ -0,0 +1,40 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.MathUtils;
+using osu.Game.Tournament.IPC;
+using osu.Game.Tournament.Screens.Gameplay.Components;
+
+namespace osu.Game.Tournament.Tests.Components
+{
+ public class TestSceneMatchScoreDisplay : LadderTestScene
+ {
+ [Cached(Type = typeof(MatchIPCInfo))]
+ private MatchIPCInfo matchInfo = new MatchIPCInfo();
+
+ public TestSceneMatchScoreDisplay()
+ {
+ Add(new MatchScoreDisplay
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ });
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ Scheduler.AddDelayed(() =>
+ {
+ int amount = (int)((RNG.NextDouble() - 0.5) * 10000);
+ if (amount < 0)
+ matchInfo.Score1.Value -= amount;
+ else
+ matchInfo.Score2.Value += amount;
+ }, 100, true);
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentBeatmapPanel.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentBeatmapPanel.cs
new file mode 100644
index 0000000000..77fa411058
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentBeatmapPanel.cs
@@ -0,0 +1,42 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Game.Beatmaps;
+using osu.Game.Online.API;
+using osu.Game.Online.API.Requests;
+using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Rulesets;
+using osu.Game.Tests.Visual;
+using osu.Game.Tournament.Components;
+
+namespace osu.Game.Tournament.Tests.Components
+{
+ public class TestSceneTournamentBeatmapPanel : OsuTestScene
+ {
+ [Resolved]
+ private IAPIProvider api { get; set; }
+
+ [Resolved]
+ private RulesetStore rulesets { get; set; }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = 1091460 });
+ req.Success += success;
+ api.Queue(req);
+ }
+
+ private void success(APIBeatmap apiBeatmap)
+ {
+ var beatmap = apiBeatmap.ToBeatmap(rulesets);
+ Add(new TournamentBeatmapPanel(beatmap)
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs
new file mode 100644
index 0000000000..41d32d9448
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs
@@ -0,0 +1,130 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Game.Online.Chat;
+using osu.Game.Tests.Visual;
+using osu.Game.Tournament.Components;
+using osu.Game.Tournament.IPC;
+using osu.Game.Tournament.Models;
+using osu.Game.Users;
+
+namespace osu.Game.Tournament.Tests.Components
+{
+ public class TestSceneTournamentMatchChatDisplay : OsuTestScene
+ {
+ private readonly Channel testChannel = new Channel();
+ private readonly Channel testChannel2 = new Channel();
+
+ private readonly User admin = new User
+ {
+ Username = "HappyStick",
+ Id = 2,
+ Colour = "f2ca34"
+ };
+
+ private readonly User redUser = new User
+ {
+ Username = "BanchoBot",
+ Id = 3,
+ };
+
+ private readonly User blueUser = new User
+ {
+ Username = "Zallius",
+ Id = 4,
+ };
+
+ [Cached]
+ private LadderInfo ladderInfo = new LadderInfo();
+
+ [Cached]
+ private MatchIPCInfo matchInfo = new MatchIPCInfo(); // hide parent
+
+ private readonly TournamentMatchChatDisplay chatDisplay;
+
+ public TestSceneTournamentMatchChatDisplay()
+ {
+ Add(chatDisplay = new TournamentMatchChatDisplay
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ });
+
+ ladderInfo.CurrentMatch.Value = new TournamentMatch
+ {
+ Team1 =
+ {
+ Value = new TournamentTeam { Players = new BindableList { redUser } }
+ },
+ Team2 =
+ {
+ Value = new TournamentTeam { Players = new BindableList { blueUser } }
+ }
+ };
+
+ chatDisplay.Channel.Value = testChannel;
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ AddStep("message from admin", () => testChannel.AddNewMessages(new Message(nextMessageId())
+ {
+ Sender = admin,
+ Content = "I am a wang!"
+ }));
+
+ AddStep("message from team red", () => testChannel.AddNewMessages(new Message(nextMessageId())
+ {
+ Sender = redUser,
+ Content = "I am team red."
+ }));
+
+ AddStep("message from team red", () => testChannel.AddNewMessages(new Message(nextMessageId())
+ {
+ Sender = redUser,
+ Content = "I plan to win!"
+ }));
+
+ AddStep("message from team blue", () => testChannel.AddNewMessages(new Message(nextMessageId())
+ {
+ Sender = blueUser,
+ Content = "Not on my watch. Prepare to eat saaaaaaaaaand. Lots and lots of saaaaaaand."
+ }));
+
+ AddStep("message from admin", () => testChannel.AddNewMessages(new Message(nextMessageId())
+ {
+ Sender = admin,
+ Content = "Okay okay, calm down guys. Let's do this!"
+ }));
+
+ AddStep("multiple messages", () => testChannel.AddNewMessages(new Message(nextMessageId())
+ {
+ Sender = admin,
+ Content = "I spam you!"
+ },
+ new Message(nextMessageId())
+ {
+ Sender = admin,
+ Content = "I spam you!!!1"
+ },
+ new Message(nextMessageId())
+ {
+ Sender = admin,
+ Content = "I spam you!1!1"
+ }));
+
+ AddStep("change channel to 2", () => chatDisplay.Channel.Value = testChannel2);
+
+ AddStep("change channel to 1", () => chatDisplay.Channel.Value = testChannel);
+ }
+
+ private int messageId;
+
+ private long? nextMessageId() => messageId++;
+ }
+}
diff --git a/osu.Game.Tournament.Tests/LadderTestScene.cs b/osu.Game.Tournament.Tests/LadderTestScene.cs
new file mode 100644
index 0000000000..b49341d0d1
--- /dev/null
+++ b/osu.Game.Tournament.Tests/LadderTestScene.cs
@@ -0,0 +1,15 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Game.Tests.Visual;
+using osu.Game.Tournament.Models;
+
+namespace osu.Game.Tournament.Tests
+{
+ public abstract class LadderTestScene : OsuTestScene
+ {
+ [Resolved]
+ protected LadderInfo Ladder { get; private set; }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs
new file mode 100644
index 0000000000..201736f38a
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs
@@ -0,0 +1,23 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Game.Tests.Visual;
+using osu.Game.Tournament.Components;
+using osu.Game.Tournament.Screens.Gameplay;
+
+namespace osu.Game.Tournament.Tests.Screens
+{
+ public class TestSceneGameplayScreen : OsuTestScene
+ {
+ [Cached]
+ private TournamentMatchChatDisplay chat = new TournamentMatchChatDisplay();
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Add(new GameplayScreen());
+ Add(chat);
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneLadderEditorScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneLadderEditorScreen.cs
new file mode 100644
index 0000000000..a45c5de2bd
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneLadderEditorScreen.cs
@@ -0,0 +1,23 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Game.Graphics.Cursor;
+using osu.Game.Tournament.Screens.Editors;
+
+namespace osu.Game.Tournament.Tests.Screens
+{
+ public class TestSceneLadderEditorScreen : LadderTestScene
+ {
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Add(new OsuContextMenuContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = new LadderEditorScreen()
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneLadderScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneLadderScreen.cs
new file mode 100644
index 0000000000..2be0564c82
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneLadderScreen.cs
@@ -0,0 +1,23 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Game.Graphics.Cursor;
+using osu.Game.Tournament.Screens.Ladder;
+
+namespace osu.Game.Tournament.Tests.Screens
+{
+ public class TestSceneLadderScreen : LadderTestScene
+ {
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Add(new OsuContextMenuContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = new LadderScreen()
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneMapPoolScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneMapPoolScreen.cs
new file mode 100644
index 0000000000..a7011c6d3c
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneMapPoolScreen.cs
@@ -0,0 +1,24 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Allocation;
+using osu.Game.Tournament.Screens.MapPool;
+
+namespace osu.Game.Tournament.Tests.Screens
+{
+ public class TestSceneMapPoolScreen : LadderTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(MapPoolScreen)
+ };
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Add(new MapPoolScreen { Width = 0.7f });
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneRoundEditorScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneRoundEditorScreen.cs
new file mode 100644
index 0000000000..e15ac416b0
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneRoundEditorScreen.cs
@@ -0,0 +1,18 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Tournament.Screens.Editors;
+
+namespace osu.Game.Tournament.Tests.Screens
+{
+ public class TestSceneRoundEditorScreen : LadderTestScene
+ {
+ public TestSceneRoundEditorScreen()
+ {
+ Add(new RoundEditorScreen
+ {
+ Width = 0.85f // create room for control panel
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneScheduleScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneScheduleScreen.cs
new file mode 100644
index 0000000000..f3e65919eb
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneScheduleScreen.cs
@@ -0,0 +1,18 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Game.Tests.Visual;
+using osu.Game.Tournament.Screens.Schedule;
+
+namespace osu.Game.Tournament.Tests.Screens
+{
+ public class TestSceneScheduleScreen : OsuTestScene
+ {
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Add(new ScheduleScreen());
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneShowcaseScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneShowcaseScreen.cs
new file mode 100644
index 0000000000..edf1477b06
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneShowcaseScreen.cs
@@ -0,0 +1,18 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Game.Tests.Visual;
+using osu.Game.Tournament.Screens.Showcase;
+
+namespace osu.Game.Tournament.Tests.Screens
+{
+ public class TestSceneShowcaseScreen : OsuTestScene
+ {
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Add(new ShowcaseScreen());
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneTeamEditorScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneTeamEditorScreen.cs
new file mode 100644
index 0000000000..097bad4a02
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneTeamEditorScreen.cs
@@ -0,0 +1,18 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Tournament.Screens.Editors;
+
+namespace osu.Game.Tournament.Tests.Screens
+{
+ public class TestSceneTeamEditorScreen : LadderTestScene
+ {
+ public TestSceneTeamEditorScreen()
+ {
+ Add(new TeamEditorScreen
+ {
+ Width = 0.85f // create room for control panel
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs
new file mode 100644
index 0000000000..3d340e393c
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs
@@ -0,0 +1,34 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Game.Tournament.Models;
+using osu.Game.Tournament.Screens.TeamIntro;
+
+namespace osu.Game.Tournament.Tests.Screens
+{
+ public class TestSceneTeamIntroScreen : LadderTestScene
+ {
+ [Cached]
+ private readonly Bindable currentMatch = new Bindable();
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ var match = new TournamentMatch();
+ match.Team1.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "USA");
+ match.Team2.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "JPN");
+ match.Round.Value = Ladder.Rounds.FirstOrDefault(g => g.Name.Value == "Finals");
+ currentMatch.Value = match;
+
+ Add(new TeamIntroScreen
+ {
+ FillMode = FillMode.Fit,
+ FillAspectRatio = 16 / 9f
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs
new file mode 100644
index 0000000000..6f5e17a36e
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs
@@ -0,0 +1,34 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Game.Tournament.Models;
+using osu.Game.Tournament.Screens.TeamWin;
+
+namespace osu.Game.Tournament.Tests.Screens
+{
+ public class TestSceneTeamWinScreen : LadderTestScene
+ {
+ [Cached]
+ private readonly Bindable currentMatch = new Bindable();
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ var match = new TournamentMatch();
+ match.Team1.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "USA");
+ match.Team2.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "JPN");
+ match.Round.Value = Ladder.Rounds.FirstOrDefault(g => g.Name.Value == "Finals");
+ currentMatch.Value = match;
+
+ Add(new TeamWinScreen
+ {
+ FillMode = FillMode.Fit,
+ FillAspectRatio = 16 / 9f
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/TestSceneTournamentSceneManager.cs b/osu.Game.Tournament.Tests/TestSceneTournamentSceneManager.cs
new file mode 100644
index 0000000000..378614343a
--- /dev/null
+++ b/osu.Game.Tournament.Tests/TestSceneTournamentSceneManager.cs
@@ -0,0 +1,18 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Platform;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Tournament.Tests
+{
+ public class TestSceneTournamentSceneManager : OsuTestScene
+ {
+ [BackgroundDependencyLoader]
+ private void load(Storage storage)
+ {
+ Add(new TournamentSceneManager());
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/TournamentTestBrowser.cs b/osu.Game.Tournament.Tests/TournamentTestBrowser.cs
new file mode 100644
index 0000000000..f7ad757926
--- /dev/null
+++ b/osu.Game.Tournament.Tests/TournamentTestBrowser.cs
@@ -0,0 +1,27 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Testing;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Backgrounds;
+
+namespace osu.Game.Tournament.Tests
+{
+ public class TournamentTestBrowser : TournamentGameBase
+ {
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ LoadComponentAsync(new Background("Menu/menu-background-0")
+ {
+ Colour = OsuColour.Gray(0.5f),
+ Depth = 10
+ }, AddInternal);
+
+ // Have to construct this here, rather than in the constructor, because
+ // we depend on some dependencies to be loaded within OsuGameBase.load().
+ Add(new TestBrowser());
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/TournamentTestRunner.cs b/osu.Game.Tournament.Tests/TournamentTestRunner.cs
new file mode 100644
index 0000000000..1f63f7c545
--- /dev/null
+++ b/osu.Game.Tournament.Tests/TournamentTestRunner.cs
@@ -0,0 +1,22 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osu.Framework;
+using osu.Framework.Platform;
+
+namespace osu.Game.Tournament.Tests
+{
+ public static class TournamentTestRunner
+ {
+ [STAThread]
+ public static int Main(string[] args)
+ {
+ using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
+ {
+ host.Run(new TournamentTestBrowser());
+ return 0;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
new file mode 100644
index 0000000000..dad2fe0877
--- /dev/null
+++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
@@ -0,0 +1,23 @@
+
+
+
+ osu.Game.Tournament.Tests.TournamentTestRunner
+
+
+
+
+
+
+
+
+ WinExe
+ netcoreapp2.2
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/osu.Game.Tournament/Components/ControlPanel.cs b/osu.Game.Tournament/Components/ControlPanel.cs
new file mode 100644
index 0000000000..a9bb1bf42f
--- /dev/null
+++ b/osu.Game.Tournament/Components/ControlPanel.cs
@@ -0,0 +1,69 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Tournament.Components
+{
+ ///
+ /// An element anchored to the right-hand area of a screen that provides streamer level controls.
+ /// Should be off-screen.
+ ///
+ public class ControlPanel : Container
+ {
+ private readonly FillFlowContainer buttons;
+
+ protected override Container Content => buttons;
+
+ public ControlPanel()
+ {
+ RelativeSizeAxes = Axes.Both;
+ AlwaysPresent = true;
+ Width = 0.15f;
+ Anchor = Anchor.TopRight;
+
+ InternalChildren = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = new Color4(54, 54, 54, 255)
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Text = "Control Panel",
+ Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 22)
+ },
+ buttons = new FillFlowContainer
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Width = 0.75f,
+ Position = new Vector2(0, 35f),
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 5f),
+ },
+ };
+ }
+
+ public class Spacer : CompositeDrawable
+ {
+ public Spacer(float height = 20)
+ {
+ RelativeSizeAxes = Axes.X;
+ Height = height;
+ AlwaysPresent = true;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Components/DateTextBox.cs b/osu.Game.Tournament/Components/DateTextBox.cs
new file mode 100644
index 0000000000..ee7e350970
--- /dev/null
+++ b/osu.Game.Tournament/Components/DateTextBox.cs
@@ -0,0 +1,44 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osu.Framework.Bindables;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Overlays.Settings;
+
+namespace osu.Game.Tournament.Components
+{
+ public class DateTextBox : SettingsTextBox
+ {
+ public new Bindable Bindable
+ {
+ get => bindable;
+ set
+ {
+ bindable = value.GetBoundCopy();
+ bindable.BindValueChanged(dto =>
+ base.Bindable.Value = dto.NewValue.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"), true);
+ }
+ }
+
+ // hold a reference to the provided bindable so we don't have to in every settings section.
+ private Bindable bindable;
+
+ public DateTextBox()
+ {
+ base.Bindable = new Bindable();
+ ((OsuTextBox)Control).OnCommit = (sender, newText) =>
+ {
+ try
+ {
+ bindable.Value = DateTimeOffset.Parse(sender.Text);
+ }
+ catch
+ {
+ // reset textbox content to its last valid state on a parse failure.
+ bindable.TriggerChange();
+ }
+ };
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Components/DrawableTournamentTeam.cs b/osu.Game.Tournament/Components/DrawableTournamentTeam.cs
new file mode 100644
index 0000000000..361bd92770
--- /dev/null
+++ b/osu.Game.Tournament/Components/DrawableTournamentTeam.cs
@@ -0,0 +1,55 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using JetBrains.Annotations;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Textures;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Tournament.Models;
+
+namespace osu.Game.Tournament.Components
+{
+ public abstract class DrawableTournamentTeam : CompositeDrawable
+ {
+ public readonly TournamentTeam Team;
+
+ protected readonly Sprite Flag;
+ protected readonly OsuSpriteText AcronymText;
+
+ [UsedImplicitly]
+ private Bindable acronym;
+
+ [UsedImplicitly]
+ private Bindable flag;
+
+ protected DrawableTournamentTeam(TournamentTeam team)
+ {
+ Team = team;
+
+ Flag = new Sprite
+ {
+ RelativeSizeAxes = Axes.Both,
+ FillMode = FillMode.Fit
+ };
+
+ AcronymText = new OsuSpriteText
+ {
+ Font = OsuFont.GetFont(weight: FontWeight.Regular),
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(TextureStore textures)
+ {
+ if (Team == null) return;
+
+ (acronym = Team.Acronym.GetBoundCopy()).BindValueChanged(acronym => AcronymText.Text = Team?.Acronym.Value?.ToUpperInvariant() ?? string.Empty, true);
+ (flag = Team.FlagName.GetBoundCopy()).BindValueChanged(acronym => Flag.Texture = textures.Get($@"Flags/{Team.FlagName}"), true);
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Components/SongBar.cs b/osu.Game.Tournament/Components/SongBar.cs
new file mode 100644
index 0000000000..7005c068ae
--- /dev/null
+++ b/osu.Game.Tournament/Components/SongBar.cs
@@ -0,0 +1,251 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Effects;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.Legacy;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Screens.Menu;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Tournament.Components
+{
+ public class SongBar : CompositeDrawable
+ {
+ private BeatmapInfo beatmap;
+
+ public BeatmapInfo Beatmap
+ {
+ get => beatmap;
+ set
+ {
+ if (beatmap == value)
+ return;
+
+ beatmap = value;
+ update();
+ }
+ }
+
+ private LegacyMods mods;
+
+ public LegacyMods Mods
+ {
+ get => mods;
+ set
+ {
+ mods = value;
+ update();
+ }
+ }
+
+ private Container panelContents;
+ private Container innerPanel;
+ private Container outerPanel;
+ private TournamentBeatmapPanel panel;
+
+ private float panelWidth => expanded ? 0.6f : 1;
+
+ private const float main_width = 0.97f;
+ private const float inner_panel_width = 0.7f;
+
+ private bool expanded;
+
+ public bool Expanded
+ {
+ get => expanded;
+ set
+ {
+ expanded = value;
+ panel?.ResizeWidthTo(panelWidth, 800, Easing.OutQuint);
+
+ if (expanded)
+ {
+ innerPanel.ResizeWidthTo(inner_panel_width, 800, Easing.OutQuint);
+ outerPanel.ResizeWidthTo(main_width, 800, Easing.OutQuint);
+ }
+ else
+ {
+ innerPanel.ResizeWidthTo(1, 800, Easing.OutQuint);
+ outerPanel.ResizeWidthTo(0.25f, 800, Easing.OutQuint);
+ }
+ }
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ RelativeSizeAxes = Axes.Both;
+
+ InternalChildren = new Drawable[]
+ {
+ outerPanel = new Container
+ {
+ Masking = true,
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Colour = Color4.Black.Opacity(0.2f),
+ Type = EdgeEffectType.Shadow,
+ Radius = 5,
+ },
+ RelativeSizeAxes = Axes.X,
+ Anchor = Anchor.BottomRight,
+ Origin = Anchor.BottomRight,
+ RelativePositionAxes = Axes.X,
+ X = -(1 - main_width) / 2,
+ Y = -10,
+ Width = main_width,
+ Height = TournamentBeatmapPanel.HEIGHT,
+ CornerRadius = TournamentBeatmapPanel.HEIGHT / 2,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = OsuColour.Gray(0.93f),
+ },
+ new OsuLogo
+ {
+ Triangles = false,
+ Colour = OsuColour.Gray(0.33f),
+ Scale = new Vector2(0.08f),
+ Margin = new MarginPadding(50),
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ },
+ innerPanel = new Container
+ {
+ Masking = true,
+ CornerRadius = TournamentBeatmapPanel.HEIGHT / 2,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Width = inner_panel_width,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = OsuColour.Gray(0.86f),
+ },
+ panelContents = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ }
+ }
+ }
+ }
+ }
+ };
+
+ Expanded = true;
+ }
+
+ private void update()
+ {
+ if (beatmap == null)
+ {
+ panelContents.Clear();
+ return;
+ }
+
+ var bpm = beatmap.BeatmapSet.OnlineInfo.BPM;
+ var length = beatmap.Length;
+ string hardRockExtra = "";
+ string srExtra = "";
+
+ //var ar = beatmap.BaseDifficulty.ApproachRate;
+ if ((mods & LegacyMods.HardRock) > 0)
+ {
+ hardRockExtra = "*";
+ srExtra = "*";
+ }
+
+ if ((mods & LegacyMods.DoubleTime) > 0)
+ {
+ //ar *= 1.5f;
+ bpm *= 1.5f;
+ length /= 1.5f;
+ srExtra = "*";
+ }
+
+ panelContents.Children = new Drawable[]
+ {
+ new DiffPiece(("Length", TimeSpan.FromMilliseconds(length).ToString(@"mm\:ss")))
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.BottomLeft,
+ },
+ new DiffPiece(("BPM", $"{bpm:0.#}"))
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.TopLeft
+ },
+ new DiffPiece(
+ //("CS", $"{beatmap.BaseDifficulty.CircleSize:0.#}{hardRockExtra}"),
+ //("AR", $"{ar:0.#}{srExtra}"),
+ ("OD", $"{beatmap.BaseDifficulty.OverallDifficulty:0.#}{hardRockExtra}"),
+ ("HP", $"{beatmap.BaseDifficulty.DrainRate:0.#}{hardRockExtra}")
+ )
+ {
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.BottomRight
+ },
+ new DiffPiece(("Star Rating", $"{beatmap.StarDifficulty:0.#}{srExtra}"))
+ {
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.TopRight
+ },
+ panel = new TournamentBeatmapPanel(beatmap)
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Size = new Vector2(panelWidth, 1)
+ }
+ };
+ }
+
+ public class DiffPiece : TextFlowContainer
+ {
+ public DiffPiece(params (string heading, string content)[] tuples)
+ {
+ Margin = new MarginPadding { Horizontal = 15, Vertical = 1 };
+ AutoSizeAxes = Axes.Both;
+
+ void cp(SpriteText s, Color4 colour)
+ {
+ s.Colour = colour;
+ s.Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 15);
+ }
+
+ for (var i = 0; i < tuples.Length; i++)
+ {
+ var tuple = tuples[i];
+
+ if (i > 0)
+ {
+ AddText(" / ", s =>
+ {
+ cp(s, OsuColour.Gray(0.33f));
+ s.Spacing = new Vector2(-2, 0);
+ });
+ }
+
+ AddText(new OsuSpriteText { Text = tuple.heading }, s => cp(s, OsuColour.Gray(0.33f)));
+ AddText(" ", s => cp(s, OsuColour.Gray(0.33f)));
+ AddText(new OsuSpriteText { Text = tuple.content }, s => cp(s, OsuColour.Gray(0.5f)));
+ }
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs
new file mode 100644
index 0000000000..d5e28c1e3e
--- /dev/null
+++ b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs
@@ -0,0 +1,203 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Specialized;
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Textures;
+using osu.Framework.Localisation;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.Drawables;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Tournament.Models;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Tournament.Components
+{
+ public class TournamentBeatmapPanel : CompositeDrawable
+ {
+ public readonly BeatmapInfo Beatmap;
+ private readonly string mods;
+
+ private const float horizontal_padding = 10;
+ private const float vertical_padding = 5;
+
+ public const float HEIGHT = 50;
+
+ private readonly Bindable currentMatch = new Bindable();
+ private Box flash;
+
+ public TournamentBeatmapPanel(BeatmapInfo beatmap, string mods = null)
+ {
+ if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
+
+ Beatmap = beatmap;
+ this.mods = mods;
+ Width = 400;
+ Height = HEIGHT;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(LadderInfo ladder, TextureStore textures)
+ {
+ currentMatch.BindValueChanged(matchChanged);
+ currentMatch.BindTo(ladder.CurrentMatch);
+
+ CornerRadius = HEIGHT / 2;
+ Masking = true;
+
+ AddRangeInternal(new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Black,
+ },
+ new UpdateableBeatmapSetCover
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = OsuColour.Gray(0.5f),
+ BeatmapSet = Beatmap.BeatmapSet,
+ },
+ new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Padding = new MarginPadding(vertical_padding),
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Text = new LocalisedString((
+ $"{Beatmap.Metadata.ArtistUnicode ?? Beatmap.Metadata.Artist} - {Beatmap.Metadata.TitleUnicode ?? Beatmap.Metadata.Title}",
+ $"{Beatmap.Metadata.Artist} - {Beatmap.Metadata.Title}")),
+ Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true),
+ },
+ new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Padding = new MarginPadding(vertical_padding),
+ Direction = FillDirection.Horizontal,
+ Children = new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Text = "mapper",
+ Padding = new MarginPadding { Right = 5 },
+ Font = OsuFont.GetFont(italics: true, weight: FontWeight.Regular, size: 14)
+ },
+ new OsuSpriteText
+ {
+ Text = Beatmap.Metadata.AuthorString,
+ Padding = new MarginPadding { Right = 20 },
+ Font = OsuFont.GetFont(italics: true, weight: FontWeight.Bold, size: 14)
+ },
+ new OsuSpriteText
+ {
+ Text = "difficulty",
+ Padding = new MarginPadding { Right = 5 },
+ Font = OsuFont.GetFont(italics: true, weight: FontWeight.Regular, size: 14)
+ },
+ new OsuSpriteText
+ {
+ Text = Beatmap.Version,
+ Font = OsuFont.GetFont(italics: true, weight: FontWeight.Bold, size: 14)
+ },
+ }
+ }
+ },
+ },
+ flash = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Gray,
+ Blending = BlendingMode.Additive,
+ Alpha = 0,
+ },
+ });
+
+ if (!string.IsNullOrEmpty(mods))
+ AddInternal(new Sprite
+ {
+ Texture = textures.Get($"mods/{mods}"),
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ Margin = new MarginPadding(20),
+ Scale = new Vector2(0.5f)
+ });
+ }
+
+ private void matchChanged(ValueChangedEvent match)
+ {
+ if (match.OldValue != null)
+ match.OldValue.PicksBans.CollectionChanged -= picksBansOnCollectionChanged;
+ match.NewValue.PicksBans.CollectionChanged += picksBansOnCollectionChanged;
+ updateState();
+ }
+
+ private void picksBansOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ => updateState();
+
+ private BeatmapChoice choice;
+
+ private void updateState()
+ {
+ var found = currentMatch.Value.PicksBans.FirstOrDefault(p => p.BeatmapID == Beatmap.OnlineBeatmapID);
+
+ bool doFlash = found != choice;
+ choice = found;
+
+ if (found != null)
+ {
+ if (doFlash)
+ flash?.FadeOutFromOne(500).Loop(0, 10);
+
+ BorderThickness = 6;
+
+ switch (found.Team)
+ {
+ case TeamColour.Red:
+ BorderColour = Color4.Red;
+ break;
+
+ case TeamColour.Blue:
+ BorderColour = Color4.Blue;
+ break;
+ }
+
+ switch (found.Type)
+ {
+ case ChoiceType.Pick:
+ Colour = Color4.White;
+ Alpha = 1;
+ break;
+
+ case ChoiceType.Ban:
+ Colour = Color4.Gray;
+ Alpha = 0.5f;
+ break;
+ }
+ }
+ else
+ {
+ Colour = Color4.White;
+ BorderThickness = 0;
+ Alpha = 1;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs
new file mode 100644
index 0000000000..48c5b9bd35
--- /dev/null
+++ b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs
@@ -0,0 +1,93 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Game.Online.Chat;
+using osu.Game.Overlays.Chat;
+using osu.Game.Tournament.IPC;
+using osu.Game.Tournament.Models;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Tournament.Components
+{
+ public class TournamentMatchChatDisplay : StandAloneChatDisplay
+ {
+ private readonly Bindable chatChannel = new Bindable();
+
+ private ChannelManager manager;
+
+ public TournamentMatchChatDisplay()
+ {
+ RelativeSizeAxes = Axes.X;
+ Y = 100;
+ Size = new Vector2(0.45f, 112);
+ Margin = new MarginPadding(10);
+ Anchor = Anchor.BottomCentre;
+ Origin = Anchor.BottomCentre;
+ }
+
+ [BackgroundDependencyLoader(true)]
+ private void load(MatchIPCInfo ipc)
+ {
+ if (ipc != null)
+ {
+ chatChannel.BindTo(ipc.ChatChannel);
+ chatChannel.BindValueChanged(c =>
+ {
+ if (string.IsNullOrWhiteSpace(c.NewValue))
+ return;
+
+ int id = int.Parse(c.NewValue);
+
+ if (id <= 0) return;
+
+ if (manager == null)
+ {
+ AddInternal(manager = new ChannelManager());
+ Channel.BindTo(manager.CurrentChannel);
+ }
+
+ foreach (var ch in manager.JoinedChannels.ToList())
+ manager.LeaveChannel(ch);
+
+ var channel = new Channel
+ {
+ Id = id,
+ Type = ChannelType.Public
+ };
+
+ manager.JoinChannel(channel);
+ manager.CurrentChannel.Value = channel;
+ }, true);
+ }
+ }
+
+ protected override ChatLine CreateMessage(Message message) => new MatchMessage(message);
+
+ protected class MatchMessage : StandAloneMessage
+ {
+ public MatchMessage(Message message)
+ : base(message)
+ {
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(LadderInfo info)
+ {
+ //if (info.CurrentMatch.Value.Team1.Value.Players.Any(u => u.Id == Message.Sender.Id))
+ // ColourBox.Colour = red;
+ //else if (info.CurrentMatch.Value.Team2.Value.Players.Any(u => u.Id == Message.Sender.Id))
+ // ColourBox.Colour = blue;
+ //else if (Message.Sender.Colour != null)
+ // SenderText.Colour = ColourBox.Colour = OsuColour.FromHex(Message.Sender.Colour);
+ }
+
+ private readonly Color4 red = new Color4(186, 0, 18, 255);
+ private readonly Color4 blue = new Color4(17, 136, 170, 255);
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Components/TourneyVideo.cs b/osu.Game.Tournament/Components/TourneyVideo.cs
new file mode 100644
index 0000000000..4f4660f645
--- /dev/null
+++ b/osu.Game.Tournament/Components/TourneyVideo.cs
@@ -0,0 +1,45 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.IO;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Colour;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.Video;
+using osu.Game.Graphics;
+
+namespace osu.Game.Tournament.Components
+{
+ public class TourneyVideo : CompositeDrawable
+ {
+ private readonly VideoSprite video;
+
+ public TourneyVideo(Stream stream)
+ {
+ if (stream == null)
+ {
+ InternalChild = new Box
+ {
+ Colour = ColourInfo.GradientVertical(OsuColour.Gray(0.3f), OsuColour.Gray(0.6f)),
+ RelativeSizeAxes = Axes.Both,
+ };
+ }
+ else
+ InternalChild = video = new VideoSprite(stream)
+ {
+ RelativeSizeAxes = Axes.Both,
+ FillMode = FillMode.Fit,
+ };
+ }
+
+ public bool Loop
+ {
+ set
+ {
+ if (video != null)
+ video.Loop = value;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tournament/IPC/FileBasedIPC.cs b/osu.Game.Tournament/IPC/FileBasedIPC.cs
new file mode 100644
index 0000000000..4fd858bd12
--- /dev/null
+++ b/osu.Game.Tournament/IPC/FileBasedIPC.cs
@@ -0,0 +1,194 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.IO;
+using System.Linq;
+using Microsoft.Win32;
+using osu.Framework.Allocation;
+using osu.Framework.Logging;
+using osu.Framework.Platform;
+using osu.Framework.Platform.Windows;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.Legacy;
+using osu.Game.Online.API;
+using osu.Game.Online.API.Requests;
+using osu.Game.Rulesets;
+using osu.Game.Tournament.Models;
+
+namespace osu.Game.Tournament.IPC
+{
+ public class FileBasedIPC : MatchIPCInfo
+ {
+ [Resolved]
+ protected IAPIProvider API { get; private set; }
+
+ [Resolved]
+ protected RulesetStore Rulesets { get; private set; }
+
+ private int lastBeatmapId;
+
+ [BackgroundDependencyLoader]
+ private void load(LadderInfo ladder, GameHost host)
+ {
+ StableStorage stable;
+
+ try
+ {
+ stable = new StableStorage(host as DesktopGameHost);
+ }
+ catch (Exception e)
+ {
+ Logger.Error(e, "Stable installation could not be found; disabling file based IPC");
+ return;
+ }
+
+ const string file_ipc_filename = "ipc.txt";
+ const string file_ipc_state_filename = "ipc-state.txt";
+ const string file_ipc_scores_filename = "ipc-scores.txt";
+ const string file_ipc_channel_filename = "ipc-channel.txt";
+
+ if (stable.Exists(file_ipc_filename))
+ Scheduler.AddDelayed(delegate
+ {
+ try
+ {
+ using (var stream = stable.GetStream(file_ipc_filename))
+ using (var sr = new StreamReader(stream))
+ {
+ var beatmapId = int.Parse(sr.ReadLine());
+ var mods = int.Parse(sr.ReadLine());
+
+ if (lastBeatmapId != beatmapId)
+ {
+ lastBeatmapId = beatmapId;
+
+ var existing = ladder.CurrentMatch.Value?.Round.Value?.Beatmaps.FirstOrDefault(b => b.ID == beatmapId && b.BeatmapInfo != null);
+
+ if (existing != null)
+ Beatmap.Value = existing.BeatmapInfo;
+ else
+ {
+ var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = beatmapId });
+ req.Success += b => Beatmap.Value = b.ToBeatmap(Rulesets);
+ API.Queue(req);
+ }
+ }
+
+ Mods.Value = (LegacyMods)mods;
+ }
+ }
+ catch
+ {
+ // file might be in use.
+ }
+
+ try
+ {
+ using (var stream = stable.GetStream(file_ipc_channel_filename))
+ using (var sr = new StreamReader(stream))
+ {
+ ChatChannel.Value = sr.ReadLine();
+ }
+ }
+ catch (Exception)
+ {
+ // file might be in use.
+ }
+
+ try
+ {
+ using (var stream = stable.GetStream(file_ipc_state_filename))
+ using (var sr = new StreamReader(stream))
+ {
+ State.Value = (TourneyState)Enum.Parse(typeof(TourneyState), sr.ReadLine());
+ }
+ }
+ catch (Exception)
+ {
+ // file might be in use.
+ }
+
+ try
+ {
+ using (var stream = stable.GetStream(file_ipc_scores_filename))
+ using (var sr = new StreamReader(stream))
+ {
+ Score1.Value = int.Parse(sr.ReadLine());
+ Score2.Value = int.Parse(sr.ReadLine());
+ }
+ }
+ catch (Exception)
+ {
+ // file might be in use.
+ }
+ }, 250, true);
+ }
+
+ ///
+ /// A method of accessing an osu-stable install in a controlled fashion.
+ ///
+ private class StableStorage : WindowsStorage
+ {
+ protected override string LocateBasePath()
+ {
+ bool checkExists(string p)
+ {
+ return File.Exists(Path.Combine(p, "ipc.txt"));
+ }
+
+ string stableInstallPath = string.Empty;
+
+ try
+ {
+ try
+ {
+ stableInstallPath = "G:\\My Drive\\Main\\osu!tourney";
+
+ if (checkExists(stableInstallPath))
+ return stableInstallPath;
+
+ stableInstallPath = "G:\\My Drive\\Main\\osu!mappool";
+
+ if (checkExists(stableInstallPath))
+ return stableInstallPath;
+ }
+ catch
+ {
+ }
+
+ try
+ {
+ using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu"))
+ stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(String.Empty).ToString().Split('"')[1].Replace("osu!.exe", "");
+
+ if (checkExists(stableInstallPath))
+ return stableInstallPath;
+ }
+ catch
+ {
+ }
+
+ stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!");
+ if (checkExists(stableInstallPath))
+ return stableInstallPath;
+
+ stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".osu");
+ if (checkExists(stableInstallPath))
+ return stableInstallPath;
+
+ return null;
+ }
+ finally
+ {
+ Logger.Log($"Stable path for tourney usage: {stableInstallPath}");
+ }
+ }
+
+ public StableStorage(DesktopGameHost host)
+ : base(string.Empty, host)
+ {
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tournament/IPC/MatchIPCInfo.cs b/osu.Game.Tournament/IPC/MatchIPCInfo.cs
new file mode 100644
index 0000000000..701258c6c7
--- /dev/null
+++ b/osu.Game.Tournament/IPC/MatchIPCInfo.cs
@@ -0,0 +1,20 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.Legacy;
+
+namespace osu.Game.Tournament.IPC
+{
+ public class MatchIPCInfo : Component
+ {
+ public Bindable Beatmap { get; } = new Bindable();
+ public Bindable Mods { get; } = new Bindable();
+ public Bindable State { get; } = new Bindable();
+ public Bindable ChatChannel { get; } = new Bindable();
+ public BindableInt Score1 { get; } = new BindableInt();
+ public BindableInt Score2 { get; } = new BindableInt();
+ }
+}
diff --git a/osu.Game.Tournament/IPC/TourneyState.cs b/osu.Game.Tournament/IPC/TourneyState.cs
new file mode 100644
index 0000000000..ef1c612a53
--- /dev/null
+++ b/osu.Game.Tournament/IPC/TourneyState.cs
@@ -0,0 +1,14 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+namespace osu.Game.Tournament.IPC
+{
+ public enum TourneyState
+ {
+ Initialising,
+ Idle,
+ WaitingForClients,
+ Playing,
+ Ranking
+ }
+}
diff --git a/osu.Game.Tournament/Models/BeatmapChoice.cs b/osu.Game.Tournament/Models/BeatmapChoice.cs
new file mode 100644
index 0000000000..384b349b24
--- /dev/null
+++ b/osu.Game.Tournament/Models/BeatmapChoice.cs
@@ -0,0 +1,38 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+
+namespace osu.Game.Tournament.Models
+{
+ ///
+ /// A beatmap choice by a team from a tournament's map pool.
+ ///
+ [Serializable]
+ public class BeatmapChoice
+ {
+ [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
+ public TeamColour Team;
+
+ [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
+ public ChoiceType Type;
+
+ public int BeatmapID;
+ }
+
+ [JsonConverter(typeof(StringEnumConverter))]
+ public enum TeamColour
+ {
+ Red,
+ Blue
+ }
+
+ [JsonConverter(typeof(StringEnumConverter))]
+ public enum ChoiceType
+ {
+ Pick,
+ Ban,
+ }
+}
diff --git a/osu.Game.Tournament/Models/LadderEditorInfo.cs b/osu.Game.Tournament/Models/LadderEditorInfo.cs
new file mode 100644
index 0000000000..70fd115e25
--- /dev/null
+++ b/osu.Game.Tournament/Models/LadderEditorInfo.cs
@@ -0,0 +1,12 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Bindables;
+
+namespace osu.Game.Tournament.Models
+{
+ public class LadderEditorInfo
+ {
+ public readonly Bindable Selected = new Bindable();
+ }
+}
diff --git a/osu.Game.Tournament/Models/LadderInfo.cs b/osu.Game.Tournament/Models/LadderInfo.cs
new file mode 100644
index 0000000000..547c4eab08
--- /dev/null
+++ b/osu.Game.Tournament/Models/LadderInfo.cs
@@ -0,0 +1,27 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using osu.Framework.Bindables;
+
+namespace osu.Game.Tournament.Models
+{
+ ///
+ /// Holds the complete data required to operate the tournament system.
+ ///
+ [Serializable]
+ public class LadderInfo
+ {
+ public BindableList Matches = new BindableList();
+ public BindableList Rounds = new BindableList();
+ public BindableList Teams = new BindableList();
+
+ // only used for serialisation
+ public List Progressions = new List();
+
+ [JsonIgnore]
+ public Bindable CurrentMatch = new Bindable();
+ }
+}
diff --git a/osu.Game.Tournament/Models/RoundBeatmap.cs b/osu.Game.Tournament/Models/RoundBeatmap.cs
new file mode 100644
index 0000000000..5d43d0ca66
--- /dev/null
+++ b/osu.Game.Tournament/Models/RoundBeatmap.cs
@@ -0,0 +1,15 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Beatmaps;
+
+namespace osu.Game.Tournament.Models
+{
+ public class RoundBeatmap
+ {
+ public int ID;
+ public string Mods;
+
+ public BeatmapInfo BeatmapInfo;
+ }
+}
diff --git a/osu.Game.Tournament/Models/TournamentMatch.cs b/osu.Game.Tournament/Models/TournamentMatch.cs
new file mode 100644
index 0000000000..06cce3d59e
--- /dev/null
+++ b/osu.Game.Tournament/Models/TournamentMatch.cs
@@ -0,0 +1,125 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using Newtonsoft.Json;
+using osu.Framework.Bindables;
+using osu.Game.Tournament.Screens.Ladder.Components;
+using SixLabors.Primitives;
+
+namespace osu.Game.Tournament.Models
+{
+ ///
+ /// A collection of two teams competing in a head-to-head match.
+ ///
+ [Serializable]
+ public class TournamentMatch
+ {
+ public int ID;
+
+ public List Acronyms
+ {
+ get
+ {
+ List